From b06a89350f27e5cda0f54b5c1c8b162caf8612b9 Mon Sep 17 00:00:00 2001 From: Kacper Donat Date: Sun, 26 Jan 2020 17:24:08 +0100 Subject: [PATCH] Add very primitive migration engine --- resources/ts/app.ts | 4 ++ resources/ts/components/favourites.ts | 11 ++---- resources/ts/store/favourites.ts | 1 - resources/ts/store/migrations.ts | 56 +++++++++++++++++++++++++++ resources/ts/utils.ts | 4 ++ 5 files changed, 68 insertions(+), 8 deletions(-) create mode 100644 resources/ts/store/migrations.ts diff --git a/resources/ts/app.ts b/resources/ts/app.ts index 1538913..2385e16 100644 --- a/resources/ts/app.ts +++ b/resources/ts/app.ts @@ -17,6 +17,8 @@ import PortalVue from 'portal-vue'; import VueDragscroll from 'vue-dragscroll'; import { Workbox } from "workbox-window"; +import { migrate } from "./store/migrations"; + Vue.use(Vuex); Vue.use(PortalVue); Vue.use(VueDragscroll); @@ -25,6 +27,8 @@ Vue.prototype.$isTouch = 'ontouchstart' in window || navigator.msMaxTouchPoints // async dependencies (async function () { + await migrate("vuex"); + const [ components, { default: store } ] = await Promise.all([ import('./components'), import('./store'), diff --git a/resources/ts/components/favourites.ts b/resources/ts/components/favourites.ts index 10c11fa..5a5f5bf 100644 --- a/resources/ts/components/favourites.ts +++ b/resources/ts/components/favourites.ts @@ -1,6 +1,6 @@ import Vue from 'vue' import { Component, Prop } from 'vue-property-decorator' -import { namespace, State } from "vuex-class"; +import { namespace, State, Mutation } from "vuex-class"; import { Favourite } from "../store/favourites"; import { SavedState } from "../store/root"; import { Stop } from "../model"; @@ -12,9 +12,10 @@ import { Favourites } from "../store"; export class FavouritesComponent extends Vue { @Favourites.State favourites: Favourite[]; @Favourites.Mutation remove: (fav: Favourite) => void; + @Mutation('replace') setStops: (stops: Stop[]) => void; choose(favourite: Favourite) { - this.$store.dispatch('load', favourite.state); + this.setStops(favourite.stops); } } @@ -22,11 +23,7 @@ function createFavouriteEntry(name: string, stops: Stop[]): Favourite { return { id: uuid.v4(), name, - stops, - state: { - version: 1, - stops: stops.map(stop => stop.id), - }, + stops } } diff --git a/resources/ts/store/favourites.ts b/resources/ts/store/favourites.ts index ebc27eb..0ba6343 100644 --- a/resources/ts/store/favourites.ts +++ b/resources/ts/store/favourites.ts @@ -7,7 +7,6 @@ export interface Favourite { id: string; name: string; stops: Stop[]; - state: SavedState; } export interface FavouritesState { diff --git a/resources/ts/store/migrations.ts b/resources/ts/store/migrations.ts new file mode 100644 index 0000000..444fa35 --- /dev/null +++ b/resources/ts/store/migrations.ts @@ -0,0 +1,56 @@ +import { distinct } from "../utils"; +import urls from "../urls"; +import * as uuid from "uuid"; + +type Migration = { + name: string, + key: string, + up: (state: any) => Promise; +} + +const migrations: Migration[] = [ + { + name: "202001261540_full_stop_in_state", + key: "vuex", + up: async state => { + const current = state.favourites.favourites; + + const ids = current + .map(favourite => favourite.state.stops) + .reduce((cur, acc) => [ ...cur, ...acc ]) + .filter(distinct) + ; + + const stops = await (await fetch(urls.prepare(urls.stops.all, { id: ids }))).json(); + const lookup = stops.reduce((lookup, stop) => ({ ...lookup, [stop.id]: stop }), {}); + + return { + ...state, + favourites: { + ...state.favourites, + favourites: state.favourites.favourites.map(favourite => ({ + id: favourite.id || uuid.v4(), + name: favourite.name, + stops: favourite.stops || favourite.state.stops.map(id => lookup[id]).filter(distinct), + })) + } + } + } + } +]; + +export async function migrate(key: string) { + const current = JSON.parse(window.localStorage.getItem('migrations')) || []; + const state = JSON.parse(window.localStorage.getItem(key)) || {}; + + const result = await migrations + .filter(migration => migration.key == key) + .filter(migration => !current.includes(migration.name)) + .reduce(async (state, migration) => { + current.push(migration.name); + return await migration.up(state) + }, state); + + window.localStorage.setItem('migrations', JSON.stringify(current)); + window.localStorage.setItem(key, JSON.stringify(result)); +} diff --git a/resources/ts/utils.ts b/resources/ts/utils.ts index 0fcbb68..293f245 100644 --- a/resources/ts/utils.ts +++ b/resources/ts/utils.ts @@ -63,3 +63,7 @@ export function get(object: any, path: string): any { return object[segments.shift()]; } + +export function distinct(value: T, index: number, array: T[]) { + return array.indexOf(value) === index; +}