From 0fee510e101ddc413e2d04003618889749466a93 Mon Sep 17 00:00:00 2001 From: Gregor MacLennan Date: Wed, 6 Sep 2023 12:23:44 +0100 Subject: [PATCH 1/5] Add deviceInfo data type to project instance --- ...jackal.sql => 0000_large_wendell_rand.sql} | 15 ++++ drizzle/project/meta/0000_snapshot.json | 83 ++++++++++++++++++- drizzle/project/meta/_journal.json | 4 +- src/datastore/index.js | 2 +- src/mapeo-project.js | 34 +++++++- src/schema/project.js | 5 ++ 6 files changed, 135 insertions(+), 8 deletions(-) rename drizzle/project/{0000_volatile_jackal.sql => 0000_large_wendell_rand.sql} (86%) diff --git a/drizzle/project/0000_volatile_jackal.sql b/drizzle/project/0000_large_wendell_rand.sql similarity index 86% rename from drizzle/project/0000_volatile_jackal.sql rename to drizzle/project/0000_large_wendell_rand.sql index 60f7f78c2..262e838ba 100644 --- a/drizzle/project/0000_volatile_jackal.sql +++ b/drizzle/project/0000_large_wendell_rand.sql @@ -17,6 +17,21 @@ CREATE TABLE `coreOwnership` ( `forks` text NOT NULL ); --> statement-breakpoint +CREATE TABLE `deviceInfo_backlink` ( + `versionId` text PRIMARY KEY NOT NULL +); +--> statement-breakpoint +CREATE TABLE `deviceInfo` ( + `docId` text PRIMARY KEY NOT NULL, + `versionId` text NOT NULL, + `schemaName` text NOT NULL, + `createdAt` text NOT NULL, + `updatedAt` text NOT NULL, + `links` text NOT NULL, + `name` text NOT NULL, + `forks` text NOT NULL +); +--> statement-breakpoint CREATE TABLE `field_backlink` ( `versionId` text PRIMARY KEY NOT NULL ); diff --git a/drizzle/project/meta/0000_snapshot.json b/drizzle/project/meta/0000_snapshot.json index 517b9841e..905195b40 100644 --- a/drizzle/project/meta/0000_snapshot.json +++ b/drizzle/project/meta/0000_snapshot.json @@ -1,7 +1,7 @@ { "version": "5", "dialect": "sqlite", - "id": "a4376411-f126-4579-adc2-da4f781d00bb", + "id": "c66bf0a9-28c1-446a-bc4b-51d4ec778947", "prevId": "00000000-0000-0000-0000-000000000000", "tables": { "coreOwnership_backlink": { @@ -113,6 +113,87 @@ "compositePrimaryKeys": {}, "uniqueConstraints": {} }, + "deviceInfo_backlink": { + "name": "deviceInfo_backlink", + "columns": { + "versionId": { + "name": "versionId", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "deviceInfo": { + "name": "deviceInfo", + "columns": { + "docId": { + "name": "docId", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "versionId": { + "name": "versionId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "schemaName": { + "name": "schemaName", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updatedAt": { + "name": "updatedAt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "links": { + "name": "links", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "forks": { + "name": "forks", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, "field_backlink": { "name": "field_backlink", "columns": { diff --git a/drizzle/project/meta/_journal.json b/drizzle/project/meta/_journal.json index 6565f25aa..fd3435bdb 100644 --- a/drizzle/project/meta/_journal.json +++ b/drizzle/project/meta/_journal.json @@ -5,8 +5,8 @@ { "idx": 0, "version": "5", - "when": 1693481966662, - "tag": "0000_volatile_jackal", + "when": 1693999502360, + "tag": "0000_large_wendell_rand", "breakpoints": true } ] diff --git a/src/datastore/index.js b/src/datastore/index.js index 9ade58d31..58d2c9dd5 100644 --- a/src/datastore/index.js +++ b/src/datastore/index.js @@ -25,7 +25,7 @@ import pDefer from 'p-defer' const NAMESPACE_SCHEMAS = /** @type {const} */ ({ data: ['observation'], - config: ['preset', 'field', 'project'], + config: ['preset', 'field', 'project', 'deviceInfo'], auth: ['coreOwnership', 'role'], }) diff --git a/src/mapeo-project.js b/src/mapeo-project.js index 6750419ff..0bbe14d59 100644 --- a/src/mapeo-project.js +++ b/src/mapeo-project.js @@ -16,6 +16,7 @@ import { IndexWriter } from './index-writer/index.js' import { projectTable } from './schema/client.js' import { coreOwnershipTable, + deviceInfoTable, fieldTable, observationTable, presetTable, @@ -108,10 +109,13 @@ export class MapeoProject { sqlite, getWinner, mapDoc: (doc, version) => { - if (doc.schemaName === 'coreOwnership') { - return mapAndValidateCoreOwnership(doc, version) - } else { - return doc + switch (doc.schemaName) { + case 'coreOwnership': + return mapAndValidateCoreOwnership(doc, version) + case 'deviceInfo': + return mapAndValidateDeviceInfo(doc, version) + default: + return doc } }, }) @@ -170,6 +174,11 @@ export class MapeoProject { table: roleTable, db, }), + deviceInfo: new DataType({ + dataStore: this.#dataStores.config, + table: deviceInfoTable, + db, + }), } this.#blobStore = new BlobStore({ @@ -369,3 +378,20 @@ function getCoreKeypairs({ projectKey, projectSecretKey, keyManager }) { return keypairs } + +/** + * Validate that a deviceInfo record is written by the device that is it about, + * e.g. version.coreKey should equal docId + * + * @param {import('@mapeo/schema').DeviceInfo} doc + * @param {import('@mapeo/schema').VersionIdObject} version + * @returns {import('@mapeo/schema').DeviceInfo} + */ +function mapAndValidateDeviceInfo(doc, { coreKey }) { + if (doc.docId !== coreKey.toString('hex')) { + throw new Error( + 'Invalid deviceInfo record, cannot write deviceInfo for another device' + ) + } + return doc +} diff --git a/src/schema/project.js b/src/schema/project.js index 3da818b10..872c02f92 100644 --- a/src/schema/project.js +++ b/src/schema/project.js @@ -16,9 +16,14 @@ export const coreOwnershipTable = sqliteTable( toColumns(schemas.coreOwnership) ) export const roleTable = sqliteTable('role', toColumns(schemas.role)) +export const deviceInfoTable = sqliteTable( + 'deviceInfo', + toColumns(schemas.deviceInfo) +) export const observationBacklinkTable = backlinkTable(observationTable) export const presetBacklinkTable = backlinkTable(presetTable) export const fieldBacklinkTable = backlinkTable(fieldTable) export const coreOwnershipBacklinkTable = backlinkTable(coreOwnershipTable) export const roleBacklinkTable = backlinkTable(roleTable) +export const deviceInfoBacklinkTable = backlinkTable(deviceInfoTable) From 0591adcd87296a142803d45f4de165341051e31b Mon Sep 17 00:00:00 2001 From: Gregor MacLennan Date: Wed, 6 Sep 2023 13:48:41 +0100 Subject: [PATCH 2/5] Add set & get deviceInfo --- ...jackpot.sql => 0000_stiff_tiger_shark.sql} | 7 ++++ drizzle/client/meta/0000_snapshot.json | 33 ++++++++++++++- drizzle/client/meta/_journal.json | 4 +- src/mapeo-manager.js | 42 ++++++++++++++++++- src/schema/client.js | 16 ++++++- src/schema/types.ts | 2 + test-e2e/device-info.js | 21 ++++++++++ 7 files changed, 120 insertions(+), 5 deletions(-) rename drizzle/client/{0000_steady_jackpot.sql => 0000_stiff_tiger_shark.sql} (74%) create mode 100644 test-e2e/device-info.js diff --git a/drizzle/client/0000_steady_jackpot.sql b/drizzle/client/0000_stiff_tiger_shark.sql similarity index 74% rename from drizzle/client/0000_steady_jackpot.sql rename to drizzle/client/0000_stiff_tiger_shark.sql index 3c8176dfc..de3354bcf 100644 --- a/drizzle/client/0000_steady_jackpot.sql +++ b/drizzle/client/0000_stiff_tiger_shark.sql @@ -1,3 +1,8 @@ +CREATE TABLE `deviceInfo` ( + `key` text NOT NULL, + `value` text +); +--> statement-breakpoint CREATE TABLE `project_backlink` ( `versionId` text PRIMARY KEY NOT NULL ); @@ -19,3 +24,5 @@ CREATE TABLE `project` ( `defaultPresets` text, `forks` text NOT NULL ); +--> statement-breakpoint +CREATE UNIQUE INDEX `deviceInfo_key_unique` ON `deviceInfo` (`key`); \ No newline at end of file diff --git a/drizzle/client/meta/0000_snapshot.json b/drizzle/client/meta/0000_snapshot.json index 6697cd68e..b6ca5d92b 100644 --- a/drizzle/client/meta/0000_snapshot.json +++ b/drizzle/client/meta/0000_snapshot.json @@ -1,9 +1,40 @@ { "version": "5", "dialect": "sqlite", - "id": "a4afa0b6-5fd1-4c8d-bc09-7e3f3fc1928f", + "id": "26df2e9a-f7ec-44e9-87fc-73d4f33e75c3", "prevId": "00000000-0000-0000-0000-000000000000", "tables": { + "deviceInfo": { + "name": "deviceInfo", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "deviceInfo_key_unique": { + "name": "deviceInfo_key_unique", + "columns": [ + "key" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, "project_backlink": { "name": "project_backlink", "columns": { diff --git a/drizzle/client/meta/_journal.json b/drizzle/client/meta/_journal.json index ae0101447..bacea2953 100644 --- a/drizzle/client/meta/_journal.json +++ b/drizzle/client/meta/_journal.json @@ -5,8 +5,8 @@ { "idx": 0, "version": "5", - "when": 1693337118674, - "tag": "0000_steady_jackpot", + "when": 1694004242465, + "tag": "0000_stiff_tiger_shark", "breakpoints": true } ] diff --git a/src/mapeo-manager.js b/src/mapeo-manager.js index e3a118bf1..102091dc8 100644 --- a/src/mapeo-manager.js +++ b/src/mapeo-manager.js @@ -8,7 +8,11 @@ import { migrate } from 'drizzle-orm/better-sqlite3/migrator' import Hypercore from 'hypercore' import { IndexWriter } from './index-writer/index.js' import { MapeoProject } from './mapeo-project.js' -import { projectKeysTable, projectTable } from './schema/client.js' +import { + deviceInfoTable, + projectKeysTable, + projectTable, +} from './schema/client.js' import { ProjectKeys } from './generated/keys.js' import { deNullify } from './utils.js' import { RandomAccessFilePool } from './core-manager/random-access-file-pool.js' @@ -294,4 +298,40 @@ export class MapeoManager { return projectId } + + /** + * @typedef {Omit} DeviceInfoParam + */ + + /** + * @template {import('type-fest').Exact} T + * @param {T} deviceInfo + */ + async setDeviceInfo(deviceInfo) { + const entries = + /** @type {import('type-fest').Entries} */ ( + Object.entries(deviceInfo) + ) + for (const [key, value] of entries) { + this.#db + .insert(deviceInfoTable) + .values({ key, value }) + .onConflictDoUpdate({ + target: deviceInfoTable.key, + set: { key, value }, + }) + .run() + } + // TODO: Also call project.$member.update(deviceInfo) for each active project + } + + async getDeviceInfo() { + const deviceInfo = /** @type {DeviceInfoParam} */ ({}) + const entries = this.#db.select().from(deviceInfoTable).all() + for (const { key, value } of entries) { + // @ts-ignore + deviceInfo[key] = value + } + return deviceInfo + } } diff --git a/src/schema/client.js b/src/schema/client.js index 13c0938ef..446b0858a 100644 --- a/src/schema/client.js +++ b/src/schema/client.js @@ -2,7 +2,7 @@ // database and it contains information that is shared across all projects on a // device import { blob, sqliteTable, text } from 'drizzle-orm/sqlite-core' -import { dereferencedDocSchemas as schemas } from '@mapeo/schema' +import { dereferencedDocSchemas as schemas, valueSchemas } from '@mapeo/schema' import { jsonSchemaToDrizzleColumns as toColumns } from './schema-to-drizzle.js' import { backlinkTable, customJson } from './utils.js' @@ -27,3 +27,17 @@ export const projectKeysTable = sqliteTable('projectKeys', { ) .notNull(), }) + +const deviceInfoKeys = /** + * @type {import('./types.js').NonEmptyArray< + * Exclude + * >} + */ (Object.keys(valueSchemas.deviceInfo.properties)) + +// This table is for arbitrary deviceInfo data - rather than updating the schema +// if we add more properties, we just use a row for each property (like mbtiles +// does for metadata). All values should be stored as JSON +export const deviceInfoTable = sqliteTable('deviceInfo', { + key: text('key', { enum: deviceInfoKeys }).notNull().unique(), + value: customJson('value'), +}) diff --git a/src/schema/types.ts b/src/schema/types.ts index 4d3c1da30..2e78745d7 100644 --- a/src/schema/types.ts +++ b/src/schema/types.ts @@ -149,3 +149,5 @@ export type SchemaToDrizzleColumns< : never : never } & { forks: JsonBuilder<'forks', string[], true, false> } + +export type NonEmptyArray = [T, ...T[]] diff --git a/test-e2e/device-info.js b/test-e2e/device-info.js new file mode 100644 index 000000000..a122e178a --- /dev/null +++ b/test-e2e/device-info.js @@ -0,0 +1,21 @@ +import { test } from 'brittle' +import { KeyManager } from '@mapeo/crypto' +import { MapeoManager } from '../src/mapeo-manager.js' +import RAM from 'random-access-memory' + +test('write and read deviceInfo', async (t) => { + const rootKey = KeyManager.generateRootKey() + const manager = new MapeoManager({ + rootKey, + dbFolder: ':memory:', + coreStorage: () => new RAM(), + }) + const info1 = { name: 'my device' } + await manager.setDeviceInfo(info1) + const readInfo1 = await manager.getDeviceInfo() + t.alike(readInfo1, info1) + const info2 = { name: 'new name' } + await manager.setDeviceInfo(info2) + const readInfo2 = await manager.getDeviceInfo() + t.alike(readInfo2, info2) +}) From 3f54a1237d7dcb123c038ff14e2e58f316ae363b Mon Sep 17 00:00:00 2001 From: Gregor MacLennan Date: Thu, 7 Sep 2023 10:44:49 +0100 Subject: [PATCH 3/5] fix type errors --- src/datatype/index.js | 1 - src/mapeo-manager.js | 8 ++++---- src/schema/client.js | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/datatype/index.js b/src/datatype/index.js index 32de204ee..a074fd763 100644 --- a/src/datatype/index.js +++ b/src/datatype/index.js @@ -121,7 +121,6 @@ export class DataType { // TS can't track the relationship between TDoc and TValue, so doc above is // typed as MapeoDoc (without versionId) rather than as TDoc. - // @ts-expect-error await this.#dataStore.write(doc) return this.getByDocId(doc.docId) } diff --git a/src/mapeo-manager.js b/src/mapeo-manager.js index 102091dc8..2f0650229 100644 --- a/src/mapeo-manager.js +++ b/src/mapeo-manager.js @@ -9,7 +9,7 @@ import Hypercore from 'hypercore' import { IndexWriter } from './index-writer/index.js' import { MapeoProject } from './mapeo-project.js' import { - deviceInfoTable, + localDeviceInfoTable, projectKeysTable, projectTable, } from './schema/client.js' @@ -314,10 +314,10 @@ export class MapeoManager { ) for (const [key, value] of entries) { this.#db - .insert(deviceInfoTable) + .insert(localDeviceInfoTable) .values({ key, value }) .onConflictDoUpdate({ - target: deviceInfoTable.key, + target: localDeviceInfoTable.key, set: { key, value }, }) .run() @@ -327,7 +327,7 @@ export class MapeoManager { async getDeviceInfo() { const deviceInfo = /** @type {DeviceInfoParam} */ ({}) - const entries = this.#db.select().from(deviceInfoTable).all() + const entries = this.#db.select().from(localDeviceInfoTable).all() for (const { key, value } of entries) { // @ts-ignore deviceInfo[key] = value diff --git a/src/schema/client.js b/src/schema/client.js index 446b0858a..46fd44369 100644 --- a/src/schema/client.js +++ b/src/schema/client.js @@ -37,7 +37,7 @@ const deviceInfoKeys = /** // This table is for arbitrary deviceInfo data - rather than updating the schema // if we add more properties, we just use a row for each property (like mbtiles // does for metadata). All values should be stored as JSON -export const deviceInfoTable = sqliteTable('deviceInfo', { +export const localDeviceInfoTable = sqliteTable('deviceInfo', { key: text('key', { enum: deviceInfoKeys }).notNull().unique(), value: customJson('value'), }) From fd8f891aaf642de96f64a68f2f448b8cf6b34701 Mon Sep 17 00:00:00 2001 From: Gregor MacLennan Date: Thu, 7 Sep 2023 11:00:57 +0100 Subject: [PATCH 4/5] store deviceInfo in JSON column, single row --- ..._shark.sql => 0000_safe_mother_askani.sql} | 6 +-- drizzle/client/meta/0000_snapshot.json | 18 +++---- drizzle/client/meta/_journal.json | 4 +- src/mapeo-manager.js | 50 +++++++++---------- src/schema/client.js | 23 +++++---- 5 files changed, 49 insertions(+), 52 deletions(-) rename drizzle/client/{0000_stiff_tiger_shark.sql => 0000_safe_mother_askani.sql} (82%) diff --git a/drizzle/client/0000_stiff_tiger_shark.sql b/drizzle/client/0000_safe_mother_askani.sql similarity index 82% rename from drizzle/client/0000_stiff_tiger_shark.sql rename to drizzle/client/0000_safe_mother_askani.sql index de3354bcf..545a2b685 100644 --- a/drizzle/client/0000_stiff_tiger_shark.sql +++ b/drizzle/client/0000_safe_mother_askani.sql @@ -1,6 +1,6 @@ CREATE TABLE `deviceInfo` ( - `key` text NOT NULL, - `value` text + `deviceId` text NOT NULL, + `deviceInfo` text NOT NULL ); --> statement-breakpoint CREATE TABLE `project_backlink` ( @@ -25,4 +25,4 @@ CREATE TABLE `project` ( `forks` text NOT NULL ); --> statement-breakpoint -CREATE UNIQUE INDEX `deviceInfo_key_unique` ON `deviceInfo` (`key`); \ No newline at end of file +CREATE UNIQUE INDEX `deviceInfo_deviceId_unique` ON `deviceInfo` (`deviceId`); \ No newline at end of file diff --git a/drizzle/client/meta/0000_snapshot.json b/drizzle/client/meta/0000_snapshot.json index b6ca5d92b..ad14a4c49 100644 --- a/drizzle/client/meta/0000_snapshot.json +++ b/drizzle/client/meta/0000_snapshot.json @@ -1,32 +1,32 @@ { "version": "5", "dialect": "sqlite", - "id": "26df2e9a-f7ec-44e9-87fc-73d4f33e75c3", + "id": "8bfa6650-adeb-48a8-96f5-a5aec7deb811", "prevId": "00000000-0000-0000-0000-000000000000", "tables": { "deviceInfo": { "name": "deviceInfo", "columns": { - "key": { - "name": "key", + "deviceId": { + "name": "deviceId", "type": "text", "primaryKey": false, "notNull": true, "autoincrement": false }, - "value": { - "name": "value", + "deviceInfo": { + "name": "deviceInfo", "type": "text", "primaryKey": false, - "notNull": false, + "notNull": true, "autoincrement": false } }, "indexes": { - "deviceInfo_key_unique": { - "name": "deviceInfo_key_unique", + "deviceInfo_deviceId_unique": { + "name": "deviceInfo_deviceId_unique", "columns": [ - "key" + "deviceId" ], "isUnique": true } diff --git a/drizzle/client/meta/_journal.json b/drizzle/client/meta/_journal.json index bacea2953..5589cb4b8 100644 --- a/drizzle/client/meta/_journal.json +++ b/drizzle/client/meta/_journal.json @@ -5,8 +5,8 @@ { "idx": 0, "version": "5", - "when": 1694004242465, - "tag": "0000_stiff_tiger_shark", + "when": 1694080834004, + "tag": "0000_safe_mother_askani", "breakpoints": true } ] diff --git a/src/mapeo-manager.js b/src/mapeo-manager.js index 2f0650229..70fdeb6b2 100644 --- a/src/mapeo-manager.js +++ b/src/mapeo-manager.js @@ -36,6 +36,7 @@ export class MapeoManager { /** @type {import('./types.js').CoreStorage} */ #coreStorage #dbFolder + #deviceId /** * @param {Object} opts @@ -54,6 +55,9 @@ export class MapeoManager { migrate(this.#db, { migrationsFolder: './drizzle/client' }) this.#keyManager = new KeyManager(rootKey) + this.#deviceId = this.#keyManager + .getIdentityKeypair() + .publicKey.toString('hex') this.#projectSettingsIndexWriter = new IndexWriter({ tables: [projectTable], sqlite, @@ -300,38 +304,30 @@ export class MapeoManager { } /** - * @typedef {Omit} DeviceInfoParam - */ - - /** - * @template {import('type-fest').Exact} T + * @template {import('type-fest').Exact} T * @param {T} deviceInfo */ async setDeviceInfo(deviceInfo) { - const entries = - /** @type {import('type-fest').Entries} */ ( - Object.entries(deviceInfo) - ) - for (const [key, value] of entries) { - this.#db - .insert(localDeviceInfoTable) - .values({ key, value }) - .onConflictDoUpdate({ - target: localDeviceInfoTable.key, - set: { key, value }, - }) - .run() - } - // TODO: Also call project.$member.update(deviceInfo) for each active project + const values = { deviceId: this.#deviceId, deviceInfo } + this.#db + .insert(localDeviceInfoTable) + .values(values) + .onConflictDoUpdate({ + target: localDeviceInfoTable.deviceId, + set: values, + }) + .run() } + /** + * @returns {Promise>} + */ async getDeviceInfo() { - const deviceInfo = /** @type {DeviceInfoParam} */ ({}) - const entries = this.#db.select().from(localDeviceInfoTable).all() - for (const { key, value } of entries) { - // @ts-ignore - deviceInfo[key] = value - } - return deviceInfo + const row = this.#db + .select() + .from(localDeviceInfoTable) + .where(eq(localDeviceInfoTable.deviceId, this.#deviceId)) + .get() + return row ? row.deviceInfo : {} } } diff --git a/src/schema/client.js b/src/schema/client.js index 46fd44369..81a11b724 100644 --- a/src/schema/client.js +++ b/src/schema/client.js @@ -2,7 +2,7 @@ // database and it contains information that is shared across all projects on a // device import { blob, sqliteTable, text } from 'drizzle-orm/sqlite-core' -import { dereferencedDocSchemas as schemas, valueSchemas } from '@mapeo/schema' +import { dereferencedDocSchemas as schemas } from '@mapeo/schema' import { jsonSchemaToDrizzleColumns as toColumns } from './schema-to-drizzle.js' import { backlinkTable, customJson } from './utils.js' @@ -28,16 +28,17 @@ export const projectKeysTable = sqliteTable('projectKeys', { .notNull(), }) -const deviceInfoKeys = /** - * @type {import('./types.js').NonEmptyArray< - * Exclude - * >} - */ (Object.keys(valueSchemas.deviceInfo.properties)) +/** + * @typedef {Omit} DeviceInfoParam + */ -// This table is for arbitrary deviceInfo data - rather than updating the schema -// if we add more properties, we just use a row for each property (like mbtiles -// does for metadata). All values should be stored as JSON +const deviceInfoColumn = + /** @type {ReturnType>} */ ( + customJson + ) + +// This table only ever has one row in it. export const localDeviceInfoTable = sqliteTable('deviceInfo', { - key: text('key', { enum: deviceInfoKeys }).notNull().unique(), - value: customJson('value'), + deviceId: text('deviceId').notNull().unique(), + deviceInfo: deviceInfoColumn('deviceInfo').notNull(), }) From 236b3289d4018b756ee79a2f1ce61d85bee32927 Mon Sep 17 00:00:00 2001 From: Gregor MacLennan Date: Thu, 7 Sep 2023 11:29:43 +0100 Subject: [PATCH 5/5] fix broken test Non-mapeo doc tables mustn't have the same name as mapeo doc tables --- ..._classy_krista_starr.sql => 0000_charming_klaw.sql} | 4 ++-- drizzle/client/meta/0000_snapshot.json | 10 +++++----- drizzle/client/meta/_journal.json | 4 ++-- src/schema/client.js | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) rename drizzle/client/{0000_classy_krista_starr.sql => 0000_charming_klaw.sql} (84%) diff --git a/drizzle/client/0000_classy_krista_starr.sql b/drizzle/client/0000_charming_klaw.sql similarity index 84% rename from drizzle/client/0000_classy_krista_starr.sql rename to drizzle/client/0000_charming_klaw.sql index a9ede435a..d82a91065 100644 --- a/drizzle/client/0000_classy_krista_starr.sql +++ b/drizzle/client/0000_charming_klaw.sql @@ -1,4 +1,4 @@ -CREATE TABLE `deviceInfo` ( +CREATE TABLE `localDeviceInfo` ( `deviceId` text NOT NULL, `deviceInfo` text NOT NULL ); @@ -26,4 +26,4 @@ CREATE TABLE `project` ( `forks` text NOT NULL ); --> statement-breakpoint -CREATE UNIQUE INDEX `deviceInfo_deviceId_unique` ON `deviceInfo` (`deviceId`); \ No newline at end of file +CREATE UNIQUE INDEX `localDeviceInfo_deviceId_unique` ON `localDeviceInfo` (`deviceId`); \ No newline at end of file diff --git a/drizzle/client/meta/0000_snapshot.json b/drizzle/client/meta/0000_snapshot.json index 999c8be81..ff1c7f11e 100644 --- a/drizzle/client/meta/0000_snapshot.json +++ b/drizzle/client/meta/0000_snapshot.json @@ -1,11 +1,11 @@ { "version": "5", "dialect": "sqlite", - "id": "8d256051-a3d8-47f0-ab8b-ead133232319", + "id": "518b4a6e-b310-4f08-a39e-5a046c1e1da9", "prevId": "00000000-0000-0000-0000-000000000000", "tables": { - "deviceInfo": { - "name": "deviceInfo", + "localDeviceInfo": { + "name": "localDeviceInfo", "columns": { "deviceId": { "name": "deviceId", @@ -23,8 +23,8 @@ } }, "indexes": { - "deviceInfo_deviceId_unique": { - "name": "deviceInfo_deviceId_unique", + "localDeviceInfo_deviceId_unique": { + "name": "localDeviceInfo_deviceId_unique", "columns": [ "deviceId" ], diff --git a/drizzle/client/meta/_journal.json b/drizzle/client/meta/_journal.json index ba8c1ae8c..88337728f 100644 --- a/drizzle/client/meta/_journal.json +++ b/drizzle/client/meta/_journal.json @@ -5,8 +5,8 @@ { "idx": 0, "version": "5", - "when": 1694081075579, - "tag": "0000_classy_krista_starr", + "when": 1694082554479, + "tag": "0000_charming_klaw", "breakpoints": true } ] diff --git a/src/schema/client.js b/src/schema/client.js index fdded43de..2a8e3bd75 100644 --- a/src/schema/client.js +++ b/src/schema/client.js @@ -39,7 +39,7 @@ const deviceInfoColumn = ) // This table only ever has one row in it. -export const localDeviceInfoTable = sqliteTable('deviceInfo', { +export const localDeviceInfoTable = sqliteTable('localDeviceInfo', { deviceId: text('deviceId').notNull().unique(), deviceInfo: deviceInfoColumn('deviceInfo').notNull(), })