Skip to content

Commit

Permalink
Add app settings storage
Browse files Browse the repository at this point in the history
  • Loading branch information
ShishKabab committed May 18, 2020
1 parent 1daa17b commit 17cf418
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 6 deletions.
49 changes: 49 additions & 0 deletions ts/session.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import pick from 'lodash/pick'
import omit from 'lodash/omit'
import * as api from "./public-api";
import TypedEmitter from 'typed-emitter'
import { AccessTokenManager } from "./access-tokens";
Expand Down Expand Up @@ -156,6 +158,53 @@ export class Session implements api.StorexHubApi_v0 {
this.destroyed = true
}
}

getAppSettings: api.StorexHubApi_v0['getAppSettings'] = async (options) => {
if (!this.identifiedApp) {
return { status: 'not-identified' }
}

const storage = await this.options.getStorage()
const existingSettings = await storage.systemModules.apps.getAppSettings(this.identifiedApp.id as number)
const settings = options.keys === 'all'
? existingSettings || {}
: pick(existingSettings || {}, options.keys)

return { status: 'success', settings }
}

setAppSettings: api.StorexHubApi_v0['setAppSettings'] = async (options) => {
if (!this.identifiedApp) {
return { status: 'not-identified' }
}

const storage = await this.options.getStorage()
const existingSettings = await storage.systemModules.apps.getAppSettings(this.identifiedApp.id as number)
const newSettings = { ...(existingSettings || {}), ...options.updates }
await storage.systemModules.apps.setAppSettings(this.identifiedApp.id as number, newSettings)

return { status: 'success' }
}

deleteAppSettings: api.StorexHubApi_v0['deleteAppSettings'] = async (options) => {
if (!this.identifiedApp) {
return { status: 'not-identified' }
}

const storage = await this.options.getStorage()
const existingSettings = await storage.systemModules.apps.getAppSettings(this.identifiedApp.id as number)
if (!existingSettings) {
if (options.keys === 'all') {
return { status: 'success' }
} else {
return { status: 'non-existing-keys', keys: options.keys }
}
}
const newSettings = options.keys === 'all' ? {} : omit(existingSettings, options.keys)
await storage.systemModules.apps.setAppSettings(this.identifiedApp.id as number, newSettings)

return { status: 'success' }
}
}

export async function checkAppSchema(schema: AppSchema, options: { identifiedApp: IdentifiedApp }): Promise<api.UpdateSchemaResult_v0> {
Expand Down
53 changes: 47 additions & 6 deletions ts/storage/modules/apps.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { StorageModule, StorageModuleConfig } from '@worldbrain/storex-pattern-modules'
import { AppSchema } from '@worldbrain/storex-hub-interfaces/lib/apps';
import { AppSettingValue } from '@worldbrain/storex-hub-interfaces/lib/api/server';
import STORAGE_VERSIONS from '../versions';
import { extendedJSONReviver } from '../../utils/json';

Expand All @@ -23,6 +24,15 @@ export class AppStorage extends StorageModule {
relationships: [
{ singleChildOf: 'app' }
]
},
appSettingsObject: {
version: STORAGE_VERSIONS[1],
fields: {
settings: { type: 'json' },
},
relationships: [
{ childOf: 'app' }
],
}
},
operations: {
Expand Down Expand Up @@ -57,6 +67,23 @@ export class AppStorage extends StorageModule {
collection: 'appSchema',
args: {}
},
createSettings: {
operation: 'createObject',
collection: 'appSettingsObject',
},
findSettings: {
operation: 'findObject',
collection: 'appSettingsObject',
args: { app: '$appId:pk' },
},
updateSettings: {
operation: 'updateObject',
collection: 'appSettingsObject',
args: [
{ app: '$appId:pk' },
{ settings: '$settings:json' }
],
}
}
}
}
Expand All @@ -69,13 +96,13 @@ export class AppStorage extends StorageModule {
return this.operation('findAppByIdentifier', { identifier })
}

async updateSchema(app: string | number, schema: AppSchema) {
const existingSchema = await this.operation('getSchema', { app })
async updateSchema(appId: string | number, schema: AppSchema) {
const existingSchema = await this.operation('getSchema', { app: appId })
const serialized = JSON.stringify(schema, null, 4)
if (existingSchema) {
await this.operation('updateSchema', { app, schema: serialized })
await this.operation('updateSchema', { app: appId, schema: serialized })
} else {
await this.operation('createSchema', { app, schema: serialized })
await this.operation('createSchema', { app: appId, schema: serialized })
}
}

Expand All @@ -87,10 +114,24 @@ export class AppStorage extends StorageModule {
}))
}

async getAppSchema(id: number) {
async getAppSchema(appId: number) {
const jsonReviver = extendedJSONReviver({ withDates: true })

const schemaObject = await this.operation('getSchema', { app: id });
const schemaObject = await this.operation('getSchema', { app: appId });
return { schema: JSON.parse(schemaObject.schema, jsonReviver) }
}

async getAppSettings(appId: number) {
const object = await this.operation('findSettings', { appId })
return object ? object.settings : null
}

async setAppSettings(appId: number, settings: { [key: string]: AppSettingValue }) {
const object = await this.operation('findSettings', { appId })
if (object) {
await this.operation('updateSettings', { appId, settings })
} else {
await this.operation('createSettings', { app: appId, settings })
}
}
}
1 change: 1 addition & 0 deletions ts/storage/versions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const STORAGE_VERSIONS: { [versionNumber: number]: Date } = {
0: new Date('2020-03-03'),
1: new Date('2020-04-01'),
}
export default STORAGE_VERSIONS
41 changes: 41 additions & 0 deletions ts/tests/api/settings.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import pick from 'lodash/pick'
import expect from 'expect';
import { createApiTestSuite } from "./index.tests";

export default createApiTestSuite('App settings', ({ it }) => {
it('should store and retrieve app settings', async ({ createSession }) => {
const { api: app } = await createSession()
await app.registerApp({ name: 'contacts', identify: true })

const settings = { foo: 'spam', bar: 5, ham: false }
await app.setAppSettings({ updates: { ...settings } })
expect(await app.getAppSettings({ keys: 'all' })).toEqual({
status: 'success',
settings,
})
expect(await app.getAppSettings({ keys: ['foo', 'bar'] })).toEqual({
status: 'success',
settings: { foo: settings.foo, bar: settings.bar },
})
})

it('should delete app settings', async ({ createSession }) => {
const { api: app } = await createSession()
await app.registerApp({ name: 'contacts', identify: true })

const settings = { foo: 'spam', bar: 5, ham: false }
await app.setAppSettings({ updates: { ...settings } })

await app.deleteAppSettings({ keys: ['foo'] })
expect(await app.getAppSettings({ keys: 'all' })).toEqual({
status: 'success',
settings: pick(settings, ['bar', 'ham']),
})

await app.deleteAppSettings({ keys: 'all' })
expect(await app.getAppSettings({ keys: 'all' })).toEqual({
status: 'success',
settings: {},
})
})
})

0 comments on commit 17cf418

Please sign in to comment.