@livestore/common 0.5.0-dev.0 → 0.5.0-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/ClientSessionLeaderThreadProxy.d.ts.map +1 -1
- package/dist/MaterializationJournal.d.ts +2 -2
- package/dist/MaterializationJournal.d.ts.map +1 -1
- package/dist/MaterializationJournal.js +7 -7
- package/dist/StateHead.d.ts +1 -1
- package/dist/StateHead.d.ts.map +1 -1
- package/dist/StateHead.js +4 -4
- package/dist/WorkerTransportError.d.ts.map +1 -1
- package/dist/__tests__/fixture.d.ts +7 -7
- package/dist/__tests__/fixture.js +2 -2
- package/dist/adapter-types.d.ts +4 -0
- package/dist/adapter-types.d.ts.map +1 -1
- package/dist/adapter-types.js +4 -4
- package/dist/bounded-collections.d.ts.map +1 -1
- package/dist/bounded-collections.js.map +1 -1
- package/dist/debug-info.d.ts.map +1 -1
- package/dist/debug-info.js +9 -8
- package/dist/debug-info.js.map +1 -1
- package/dist/defs.d.ts +4 -4
- package/dist/defs.js +2 -2
- package/dist/devtools/devtools-compatibility.test.js +1 -1
- package/dist/devtools/devtools-messages-client-session.d.ts +4 -4
- package/dist/devtools/devtools-messages-client-session.js +4 -4
- package/dist/devtools/devtools-messages-common.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-common.js +1 -1
- package/dist/devtools/devtools-messages-leader.d.ts +9 -9
- package/dist/devtools/devtools-messages-leader.js +4 -4
- package/dist/devtools/devtools-messages.js +3 -3
- package/dist/devtools/devtools-sessioninfo.d.ts.map +1 -1
- package/dist/devtools/mod.d.ts.map +1 -1
- package/dist/devtools/mod.js +3 -3
- package/dist/errors.d.ts +4 -4
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.js +22 -22
- package/dist/leader-thread/LeaderSyncProcessor.d.ts +27 -6
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.js +65 -55
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
- package/dist/leader-thread/RejectedPushError.d.ts +9 -9
- package/dist/leader-thread/RejectedPushError.d.ts.map +1 -1
- package/dist/leader-thread/RejectedPushError.js +1 -1
- package/dist/leader-thread/connection.d.ts.map +1 -1
- package/dist/leader-thread/connection.js +2 -2
- package/dist/leader-thread/eventlog.d.ts +11 -1
- package/dist/leader-thread/eventlog.d.ts.map +1 -1
- package/dist/leader-thread/eventlog.js +13 -13
- package/dist/leader-thread/eventlog.js.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.d.ts +1 -1
- package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.js +4 -4
- package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.d.ts +6 -0
- package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.js +43 -29
- package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.test.js +2 -2
- package/dist/leader-thread/materialize-event.d.ts.map +1 -1
- package/dist/leader-thread/materialize-event.js +9 -9
- package/dist/leader-thread/mod.js +9 -9
- package/dist/leader-thread/recreate-db.d.ts +5 -1
- package/dist/leader-thread/recreate-db.d.ts.map +1 -1
- package/dist/leader-thread/recreate-db.js +21 -25
- package/dist/leader-thread/recreate-db.js.map +1 -1
- package/dist/leader-thread/shutdown-channel.js +1 -1
- package/dist/leader-thread/stream-events.d.ts.map +1 -1
- package/dist/leader-thread/stream-events.js +3 -5
- package/dist/leader-thread/stream-events.js.map +1 -1
- package/dist/leader-thread/types.d.ts +6 -4
- package/dist/leader-thread/types.d.ts.map +1 -1
- package/dist/leader-thread/types.js +5 -1
- package/dist/leader-thread/types.js.map +1 -1
- package/dist/make-client-session.d.ts +1 -1
- package/dist/make-client-session.d.ts.map +1 -1
- package/dist/make-client-session.js +2 -2
- package/dist/materializer-helper.d.ts.map +1 -1
- package/dist/materializer-helper.js +4 -4
- package/dist/materializer-helper.js.map +1 -1
- package/dist/otel.d.ts.map +1 -1
- package/dist/rematerialize-from-eventlog.d.ts +3 -1
- package/dist/rematerialize-from-eventlog.d.ts.map +1 -1
- package/dist/rematerialize-from-eventlog.js +16 -9
- package/dist/rematerialize-from-eventlog.js.map +1 -1
- package/dist/schema/EventDef/define.d.ts +2 -2
- package/dist/schema/EventDef/define.d.ts.map +1 -1
- package/dist/schema/EventDef/define.test.js +1 -1
- package/dist/schema/EventDef/deprecated.d.ts +1 -1
- package/dist/schema/EventDef/deprecated.d.ts.map +1 -1
- package/dist/schema/EventDef/deprecated.test.js +2 -2
- package/dist/schema/EventDef/facts.d.ts.map +1 -1
- package/dist/schema/EventDef/materializer.d.ts +2 -2
- package/dist/schema/EventDef/materializer.d.ts.map +1 -1
- package/dist/schema/EventDef/mod.js +5 -5
- package/dist/schema/EventSequenceNumber/client.d.ts +3 -8
- package/dist/schema/EventSequenceNumber/client.d.ts.map +1 -1
- package/dist/schema/EventSequenceNumber/client.js +12 -15
- package/dist/schema/EventSequenceNumber/client.js.map +1 -1
- package/dist/schema/EventSequenceNumber/mod.js +2 -2
- package/dist/schema/EventSequenceNumber.test.js +1 -1
- package/dist/schema/LiveStoreEvent/client.d.ts +8 -8
- package/dist/schema/LiveStoreEvent/client.d.ts.map +1 -1
- package/dist/schema/LiveStoreEvent/client.js +1 -1
- package/dist/schema/LiveStoreEvent/client.js.map +1 -1
- package/dist/schema/LiveStoreEvent/client.test.js +2 -2
- package/dist/schema/LiveStoreEvent/global.d.ts.map +1 -1
- package/dist/schema/LiveStoreEvent/global.js +1 -1
- package/dist/schema/LiveStoreEvent/input.d.ts +1 -1
- package/dist/schema/LiveStoreEvent/input.d.ts.map +1 -1
- package/dist/schema/LiveStoreEvent/mod.js +4 -4
- package/dist/schema/events.js +1 -1
- package/dist/schema/mod.js +11 -11
- package/dist/schema/schema.d.ts +1 -1
- package/dist/schema/schema.d.ts.map +1 -1
- package/dist/schema/schema.js +3 -3
- package/dist/schema/state/mod.js +2 -2
- package/dist/schema/state/sqlite/client-document-def.d.ts +1 -1
- package/dist/schema/state/sqlite/client-document-def.d.ts.map +1 -1
- package/dist/schema/state/sqlite/client-document-def.js +8 -8
- package/dist/schema/state/sqlite/client-document-def.js.map +1 -1
- package/dist/schema/state/sqlite/client-document-def.test.js +24 -10
- package/dist/schema/state/sqlite/client-document-def.test.js.map +1 -1
- package/dist/schema/state/sqlite/column-annotations.d.ts.map +1 -1
- package/dist/schema/state/sqlite/column-annotations.test.js +1 -1
- package/dist/schema/state/sqlite/column-def.d.ts.map +1 -1
- package/dist/schema/state/sqlite/column-def.js +17 -3
- package/dist/schema/state/sqlite/column-def.js.map +1 -1
- package/dist/schema/state/sqlite/column-def.test.js +60 -5
- package/dist/schema/state/sqlite/column-def.test.js.map +1 -1
- package/dist/schema/state/sqlite/column-spec.d.ts.map +1 -1
- package/dist/schema/state/sqlite/column-spec.js +1 -1
- package/dist/schema/state/sqlite/column-spec.test.js +2 -2
- package/dist/schema/state/sqlite/column-spec.test.js.map +1 -1
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint-digest.d.ts +3 -0
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint-digest.d.ts.map +1 -0
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint-digest.js +5 -0
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint-digest.js.map +1 -0
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint.d.ts +5 -0
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint.d.ts.map +1 -0
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint.js +183 -0
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint.js.map +1 -0
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint.test.d.ts +2 -0
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint.test.d.ts.map +1 -0
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint.test.js +142 -0
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint.test.js.map +1 -0
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts +1 -6
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts.map +1 -1
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.js +1 -82
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.js.map +1 -1
- package/dist/schema/state/sqlite/db-schema/ast/validate.d.ts.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js +2 -1
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.js +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/mod.js +1 -1
- package/dist/schema/state/sqlite/db-schema/has-json-string-encoding.d.ts +3 -0
- package/dist/schema/state/sqlite/db-schema/has-json-string-encoding.d.ts.map +1 -0
- package/dist/schema/state/sqlite/db-schema/has-json-string-encoding.js +6 -0
- package/dist/schema/state/sqlite/db-schema/has-json-string-encoding.js.map +1 -0
- package/dist/schema/state/sqlite/db-schema/mod.js +2 -2
- package/dist/schema/state/sqlite/mod.d.ts.map +1 -1
- package/dist/schema/state/sqlite/mod.js +10 -9
- package/dist/schema/state/sqlite/mod.js.map +1 -1
- package/dist/schema/state/sqlite/persistence.d.ts.map +1 -1
- package/dist/schema/state/sqlite/query-builder/api.d.ts.map +1 -1
- package/dist/schema/state/sqlite/query-builder/astToSql.d.ts.map +1 -1
- package/dist/schema/state/sqlite/query-builder/astToSql.js +2 -7
- package/dist/schema/state/sqlite/query-builder/astToSql.js.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.d.ts +1 -3
- package/dist/schema/state/sqlite/query-builder/impl.d.ts.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.js +2 -2
- package/dist/schema/state/sqlite/query-builder/impl.js.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.test.js +2 -2
- package/dist/schema/state/sqlite/query-builder/mod.js +2 -2
- package/dist/schema/state/sqlite/schema-helpers.d.ts.map +1 -1
- package/dist/schema/state/sqlite/schema-helpers.js +1 -1
- package/dist/schema/state/sqlite/schema-helpers.test.js +2 -2
- package/dist/schema/state/sqlite/system-tables/eventlog-tables.js +3 -3
- package/dist/schema/state/sqlite/system-tables/mod.js +2 -2
- package/dist/schema/state/sqlite/system-tables/state-tables.d.ts +60 -17
- package/dist/schema/state/sqlite/system-tables/state-tables.d.ts.map +1 -1
- package/dist/schema/state/sqlite/system-tables/state-tables.js +14 -5
- package/dist/schema/state/sqlite/system-tables/state-tables.js.map +1 -1
- package/dist/schema/state/sqlite/table-def.d.ts +1 -1
- package/dist/schema/state/sqlite/table-def.d.ts.map +1 -1
- package/dist/schema/state/sqlite/table-def.js +24 -8
- package/dist/schema/state/sqlite/table-def.js.map +1 -1
- package/dist/schema/state/sqlite/table-def.test.js +54 -1
- package/dist/schema/state/sqlite/table-def.test.js.map +1 -1
- package/dist/schema/unknown-events.d.ts.map +1 -1
- package/dist/schema/unknown-events.js +1 -1
- package/dist/schema/unknown-events.js.map +1 -1
- package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js +26 -4
- package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js.map +1 -1
- package/dist/schema-management/common.d.ts.map +1 -1
- package/dist/schema-management/common.js +2 -2
- package/dist/schema-management/migrations.d.ts +4 -4
- package/dist/schema-management/migrations.d.ts.map +1 -1
- package/dist/schema-management/migrations.js +9 -9
- package/dist/schema-management/migrations.js.map +1 -1
- package/dist/schema-management/validate-schema.d.ts.map +1 -1
- package/dist/schema-management/validate-schema.js +1 -1
- package/dist/session-id-symbol.d.ts.map +1 -1
- package/dist/sql-queries/index.js +3 -3
- package/dist/sql-queries/sql-queries.d.ts.map +1 -1
- package/dist/sql-queries/sql-queries.js +3 -3
- package/dist/sql-queries/sql-queries.js.map +1 -1
- package/dist/sql-queries/sql-query-builder.d.ts.map +1 -1
- package/dist/sql-queries/sql-query-builder.js +1 -1
- package/dist/sql-queries/types.d.ts.map +1 -1
- package/dist/sqlite-db-helper.d.ts +2 -2
- package/dist/sqlite-db-helper.d.ts.map +1 -1
- package/dist/sqlite-db-helper.js +2 -2
- package/dist/sync/ClientSessionSyncProcessor.d.ts +3 -3
- package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.js +7 -7
- package/dist/sync/errors.js +1 -1
- package/dist/sync/index.js +6 -6
- package/dist/sync/mock-sync-backend.d.ts.map +1 -1
- package/dist/sync/mock-sync-backend.js +4 -4
- package/dist/sync/mock-sync-backend.test.js +2 -2
- package/dist/sync/next/compact-events.d.ts.map +1 -1
- package/dist/sync/next/compact-events.js +3 -3
- package/dist/sync/next/facts.d.ts.map +1 -1
- package/dist/sync/next/facts.js +1 -1
- package/dist/sync/next/history-dag-common.d.ts +1 -1
- package/dist/sync/next/history-dag-common.d.ts.map +1 -1
- package/dist/sync/next/history-dag-common.js +1 -1
- package/dist/sync/next/history-dag.d.ts.map +1 -1
- package/dist/sync/next/history-dag.js +3 -3
- package/dist/sync/next/mod.js +5 -5
- package/dist/sync/next/rebase-events.d.ts.map +1 -1
- package/dist/sync/next/rebase-events.js +2 -2
- package/dist/sync/next/test/compact-events.calculator.test.js +4 -4
- package/dist/sync/next/test/compact-events.test.js +4 -4
- package/dist/sync/next/test/event-fixtures.d.ts +1 -1
- package/dist/sync/next/test/event-fixtures.d.ts.map +1 -1
- package/dist/sync/next/test/event-fixtures.js +5 -5
- package/dist/sync/next/test/history-dag-common.test.js +2 -2
- package/dist/sync/next/test/mod.js +1 -1
- package/dist/sync/sync-backend-kv.js +1 -1
- package/dist/sync/sync-backend.d.ts.map +1 -1
- package/dist/sync/sync-backend.js +1 -1
- package/dist/sync/sync.js +2 -2
- package/dist/sync/syncstate.d.ts +3 -3
- package/dist/sync/syncstate.d.ts.map +1 -1
- package/dist/sync/syncstate.js +2 -2
- package/dist/sync/syncstate.js.map +1 -1
- package/dist/sync/syncstate.test.js +3 -3
- package/dist/sync/transport-chunking.d.ts.map +1 -1
- package/dist/sync/validate-push-payload.d.ts.map +1 -1
- package/dist/sync/validate-push-payload.js +2 -2
- package/dist/testing/event-factory.d.ts.map +1 -1
- package/dist/testing/event-factory.js +2 -2
- package/dist/testing/event-factory.js.map +1 -1
- package/dist/testing/mod.js +1 -1
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +1 -0
- package/dist/util.js.map +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +40 -39
- package/src/adapter-types.ts +4 -0
- package/src/debug-info.ts +11 -8
- package/src/defs.ts +2 -2
- package/src/leader-thread/LeaderSyncProcessor.ts +121 -97
- package/src/leader-thread/eventlog.ts +13 -5
- package/src/leader-thread/leader-worker-devtools.ts +1 -1
- package/src/leader-thread/make-leader-thread-layer.ts +49 -23
- package/src/leader-thread/recreate-db.ts +26 -25
- package/src/leader-thread/stream-events.ts +1 -3
- package/src/leader-thread/types.ts +5 -0
- package/src/materializer-helper.ts +1 -1
- package/src/rematerialize-from-eventlog.ts +28 -13
- package/src/schema/EventSequenceNumber/client.ts +12 -15
- package/src/schema/schema.ts +1 -1
- package/src/schema/state/sqlite/client-document-def.test.ts +23 -7
- package/src/schema/state/sqlite/client-document-def.ts +2 -2
- package/src/schema/state/sqlite/column-def.test.ts +84 -3
- package/src/schema/state/sqlite/column-def.ts +16 -1
- package/src/schema/state/sqlite/db-schema/ast/fingerprint-digest.ts +6 -0
- package/src/schema/state/sqlite/db-schema/ast/fingerprint.test.ts +209 -0
- package/src/schema/state/sqlite/db-schema/ast/fingerprint.ts +225 -0
- package/src/schema/state/sqlite/db-schema/ast/sqlite.ts +1 -90
- package/src/schema/state/sqlite/db-schema/dsl/field-defs.ts +1 -0
- package/src/schema/state/sqlite/db-schema/has-json-string-encoding.ts +9 -0
- package/src/schema/state/sqlite/mod.ts +2 -1
- package/src/schema/state/sqlite/query-builder/astToSql.ts +1 -8
- package/src/schema/state/sqlite/system-tables/state-tables.ts +13 -2
- package/src/schema/state/sqlite/table-def.test.ts +66 -0
- package/src/schema/state/sqlite/table-def.ts +21 -5
- package/src/schema-management/__tests__/migrations-autoincrement-quoting.test.ts +33 -2
- package/src/schema-management/migrations.ts +7 -6
- package/src/sql-queries/sql-queries.ts +1 -1
- package/src/util.ts +1 -0
- package/dist/schema/state/sqlite/db-schema/hash.d.ts +0 -2
- package/dist/schema/state/sqlite/db-schema/hash.d.ts.map +0 -1
- package/dist/schema/state/sqlite/db-schema/hash.js +0 -15
- package/dist/schema/state/sqlite/db-schema/hash.js.map +0 -1
- package/src/schema/state/sqlite/db-schema/hash.ts +0 -13
|
@@ -182,6 +182,54 @@ describe('table function overloads', () => {
|
|
|
182
182
|
expect(userTable.sqliteDef.columns.email.nullable).toBe(true)
|
|
183
183
|
})
|
|
184
184
|
|
|
185
|
+
it('keeps a date codec so the column round-trips through its encoded form', () => {
|
|
186
|
+
const StampSchema = Schema.Struct({
|
|
187
|
+
id: Schema.String.pipe(State.SQLite.withPrimaryKey),
|
|
188
|
+
createdAt: Schema.DateFromString,
|
|
189
|
+
seenAt: Schema.DateFromMillis,
|
|
190
|
+
bornAt: Schema.Date,
|
|
191
|
+
deletedAt: Schema.NullOr(Schema.DateFromString),
|
|
192
|
+
archivedAt: Schema.optional(Schema.DateFromString),
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
const { columns } = State.SQLite.table({ name: 'stamps', schema: StampSchema }).sqliteDef
|
|
196
|
+
const date = new Date('2026-01-02T03:04:05.678Z')
|
|
197
|
+
const roundTrip = (column: { schema: Schema.Codec<any, any> }, value: unknown) =>
|
|
198
|
+
Schema.decodeUnknownSync(column.schema)(Schema.encodeUnknownSync(column.schema)(value))
|
|
199
|
+
|
|
200
|
+
expect(columns.createdAt.columnType).toBe('text')
|
|
201
|
+
expect(Schema.encodeUnknownSync(columns.createdAt.schema)(date)).toBe(date.toISOString())
|
|
202
|
+
expect(roundTrip(columns.createdAt, date)).toEqual(date)
|
|
203
|
+
|
|
204
|
+
expect(columns.seenAt.columnType).toBe('integer')
|
|
205
|
+
expect(Schema.encodeUnknownSync(columns.seenAt.schema)(date)).toBe(date.getTime())
|
|
206
|
+
expect(roundTrip(columns.seenAt, date)).toEqual(date)
|
|
207
|
+
|
|
208
|
+
expect(columns.bornAt.columnType).toBe('text')
|
|
209
|
+
expect(Schema.encodeUnknownSync(columns.bornAt.schema)(date)).toBe(date.toISOString())
|
|
210
|
+
expect(roundTrip(columns.bornAt, date)).toEqual(date)
|
|
211
|
+
|
|
212
|
+
expect(columns.deletedAt.nullable).toBe(true)
|
|
213
|
+
expect(roundTrip(columns.deletedAt, date)).toEqual(date)
|
|
214
|
+
expect(roundTrip(columns.deletedAt, null)).toBeNull()
|
|
215
|
+
|
|
216
|
+
expect(columns.archivedAt.nullable).toBe(true)
|
|
217
|
+
expect(roundTrip(columns.archivedAt, date)).toEqual(date)
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
it('stores a codec field in its encoded form, like getColumnDefForSchema does', () => {
|
|
221
|
+
const CounterSchema = Schema.Struct({
|
|
222
|
+
id: Schema.String,
|
|
223
|
+
count: Schema.FiniteFromString,
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
const { columns } = State.SQLite.table({ name: 'counters', schema: CounterSchema }).sqliteDef
|
|
227
|
+
|
|
228
|
+
expect(columns.count.columnType).toBe('text')
|
|
229
|
+
expect(Schema.encodeUnknownSync(columns.count.schema)(42)).toBe('42')
|
|
230
|
+
expect(Schema.decodeSync(columns.count.schema)('42')).toBe(42)
|
|
231
|
+
})
|
|
232
|
+
|
|
185
233
|
it('should handle Schema.Int as integer column', () => {
|
|
186
234
|
const CounterSchema = Schema.Struct({
|
|
187
235
|
id: Schema.String,
|
|
@@ -223,6 +271,24 @@ describe('table function overloads', () => {
|
|
|
223
271
|
expect(userTable.sqliteDef.columns.age.columnType).toBe('integer')
|
|
224
272
|
})
|
|
225
273
|
|
|
274
|
+
it('preserves Date field codecs in Schema.Class tables', () => {
|
|
275
|
+
class Stamp extends Schema.Class<Stamp>('Stamp')({
|
|
276
|
+
id: Schema.String,
|
|
277
|
+
createdAt: Schema.DateFromString,
|
|
278
|
+
seenAt: Schema.DateFromMillis,
|
|
279
|
+
}) {}
|
|
280
|
+
|
|
281
|
+
const { columns } = State.SQLite.table({ name: 'stamps', schema: Stamp }).sqliteDef
|
|
282
|
+
const date = new Date('2026-01-02T03:04:05.678Z')
|
|
283
|
+
|
|
284
|
+
expect(columns.createdAt.columnType).toBe('text')
|
|
285
|
+
expect(Schema.decodeSync(columns.createdAt.schema)(date.toISOString())).toEqual(date)
|
|
286
|
+
expect(Schema.encodeUnknownSync(columns.createdAt.schema)(date)).toBe(date.toISOString())
|
|
287
|
+
expect(columns.seenAt.columnType).toBe('integer')
|
|
288
|
+
expect(Schema.decodeSync(columns.seenAt.schema)(date.getTime())).toEqual(date)
|
|
289
|
+
expect(Schema.encodeUnknownSync(columns.seenAt.schema)(date)).toBe(date.getTime())
|
|
290
|
+
})
|
|
291
|
+
|
|
226
292
|
it('should support schemas that transform flat columns into nested types', () => {
|
|
227
293
|
const Flat = Schema.Struct({
|
|
228
294
|
id: Schema.String.pipe(State.SQLite.withPrimaryKey),
|
|
@@ -265,26 +265,42 @@ export function table<
|
|
|
265
265
|
return tableDef as any
|
|
266
266
|
}
|
|
267
267
|
|
|
268
|
+
/**
|
|
269
|
+
* The encoded side of the schema decides which columns exist (a transformation may flatten a nested
|
|
270
|
+
* type into columns). Where the schema itself declares a property of the same name, that property's
|
|
271
|
+
* own AST becomes the column schema: it still carries the field's encoding, so a codec such as
|
|
272
|
+
* `Schema.DateFromString` or `Schema.DateFromMillis` stores its encoded form and decodes back to
|
|
273
|
+
* its type. Substituting the type-side AST instead would strip that encoding and leave a `Date`
|
|
274
|
+
* with nothing SQLite can store natively, which is how date columns ended up JSON-encoded and
|
|
275
|
+
* unreadable.
|
|
276
|
+
*/
|
|
268
277
|
const getSqlitePropertySignatures = (schema: Schema.Top): ReadonlyArray<SchemaAST.PropertySignature> => {
|
|
269
278
|
const encodedPropertySignatures = getPropertySignatures(SchemaAST.toEncoded(schema.ast))
|
|
270
|
-
const
|
|
279
|
+
const ownPropertySignatures = getPropertySignatures(schema.ast)
|
|
271
280
|
|
|
272
281
|
return encodedPropertySignatures.map((encodedPropertySignature) => {
|
|
273
|
-
const
|
|
282
|
+
const ownPropertySignature = ownPropertySignatures.find(
|
|
274
283
|
(propertySignature) => propertySignature.name === encodedPropertySignature.name,
|
|
275
284
|
)
|
|
276
285
|
|
|
277
|
-
if (
|
|
286
|
+
if (ownPropertySignature === undefined || hasLiveStoreSqliteAnnotation(encodedPropertySignature.type) === true) {
|
|
278
287
|
return encodedPropertySignature
|
|
279
288
|
}
|
|
280
289
|
|
|
281
|
-
return
|
|
290
|
+
return ownPropertySignature
|
|
282
291
|
})
|
|
283
292
|
}
|
|
284
293
|
|
|
285
294
|
const getPropertySignatures = (ast: SchemaAST.AST): ReadonlyArray<SchemaAST.PropertySignature> => {
|
|
286
295
|
if (SchemaAST.isObjects(ast) === true) return ast.propertySignatures
|
|
287
296
|
|
|
297
|
+
// Class declarations encode through their fields object. Inspect that first
|
|
298
|
+
// link before toEncoded strips the individual field codecs.
|
|
299
|
+
if (SchemaAST.isDeclaration(ast) === true) {
|
|
300
|
+
const fieldsAst = ast.encoding?.[0]?.to
|
|
301
|
+
if (fieldsAst !== undefined) return getPropertySignatures(fieldsAst)
|
|
302
|
+
}
|
|
303
|
+
|
|
288
304
|
if (SchemaAST.isUnion(ast) === true) {
|
|
289
305
|
const members = ast.types.map(getPropertySignatures)
|
|
290
306
|
const [head, ...tail] = members
|
|
@@ -314,7 +330,7 @@ const getPropertySignatures = (ast: SchemaAST.AST): ReadonlyArray<SchemaAST.Prop
|
|
|
314
330
|
const keyContext = hasOptionalMember === true ? new SchemaAST.Context(true, false) : undefined
|
|
315
331
|
const union = new SchemaAST.Union(
|
|
316
332
|
propertySignatures.map((memberPropertySignature) => memberPropertySignature.type),
|
|
317
|
-
ast.
|
|
333
|
+
ast.options,
|
|
318
334
|
undefined,
|
|
319
335
|
undefined,
|
|
320
336
|
undefined,
|
|
@@ -2,13 +2,16 @@ import { describe, expect, it } from 'vitest'
|
|
|
2
2
|
|
|
3
3
|
import { Effect, Option, Schema } from '@livestore/utils/effect'
|
|
4
4
|
|
|
5
|
+
import { fingerprint } from '../../schema/state/sqlite/db-schema/ast/fingerprint.ts'
|
|
5
6
|
import { SqliteAst } from '../../schema/state/sqlite/db-schema/mod.ts'
|
|
7
|
+
import { schemaMetaTable } from '../../schema/state/sqlite/system-tables/state-tables.ts'
|
|
6
8
|
import type { PreparedStatement, SqliteDb } from '../../sqlite-types.ts'
|
|
7
9
|
import type { PreparedBindValues } from '../../util.ts'
|
|
8
10
|
import { migrateTable } from '../migrations.ts'
|
|
9
11
|
|
|
10
12
|
const makeStubDb = () => {
|
|
11
13
|
const executed: string[] = []
|
|
14
|
+
const bindings: Array<PreparedBindValues | undefined> = []
|
|
12
15
|
|
|
13
16
|
const db: SqliteDb = {
|
|
14
17
|
_tag: 'SqliteDb',
|
|
@@ -16,8 +19,9 @@ const makeStubDb = () => {
|
|
|
16
19
|
debug: { head: 0 as any },
|
|
17
20
|
prepare: (queryStr: string): PreparedStatement => ({
|
|
18
21
|
sql: queryStr,
|
|
19
|
-
execute: (
|
|
22
|
+
execute: (bind: PreparedBindValues | undefined) => {
|
|
20
23
|
executed.push(queryStr)
|
|
24
|
+
bindings.push(bind)
|
|
21
25
|
},
|
|
22
26
|
select: <T>(_bind: PreparedBindValues | undefined) => [] as unknown as ReadonlyArray<T>,
|
|
23
27
|
finalize: () => {},
|
|
@@ -32,7 +36,7 @@ const makeStubDb = () => {
|
|
|
32
36
|
makeChangeset: () => ({ invert: () => ({ invert: () => ({}) as any, apply: () => {} }) as any, apply: () => {} }),
|
|
33
37
|
}
|
|
34
38
|
|
|
35
|
-
return { db, executed }
|
|
39
|
+
return { db, executed, bindings }
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
describe('migrateTable - quoting and autoincrement', () => {
|
|
@@ -85,4 +89,31 @@ describe('migrateTable - quoting and autoincrement', () => {
|
|
|
85
89
|
expect(createStmt!).not.toContain("PRIMARY KEY ('id')")
|
|
86
90
|
expect(createStmt!).not.toMatch(/'todos'|'id'|'text'/)
|
|
87
91
|
})
|
|
92
|
+
|
|
93
|
+
it('persists full textual table fingerprints', () => {
|
|
94
|
+
const { db, bindings } = makeStubDb()
|
|
95
|
+
const table = SqliteAst.table(
|
|
96
|
+
'todos',
|
|
97
|
+
[
|
|
98
|
+
SqliteAst.column({
|
|
99
|
+
name: 'id',
|
|
100
|
+
type: { _tag: 'text' },
|
|
101
|
+
nullable: false,
|
|
102
|
+
primaryKey: true,
|
|
103
|
+
autoIncrement: false,
|
|
104
|
+
default: Option.none(),
|
|
105
|
+
schema: Schema.String,
|
|
106
|
+
}),
|
|
107
|
+
],
|
|
108
|
+
[],
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
migrateTable({ db, tableAst: table, behaviour: 'create-if-not-exists' }).pipe(Effect.runSync)
|
|
112
|
+
|
|
113
|
+
const schemaMetaBinding = bindings.find(
|
|
114
|
+
(binding) => binding !== undefined && Array.isArray(binding) === false && '$schemaHash' in binding,
|
|
115
|
+
)
|
|
116
|
+
expect(schemaMetaBinding).toMatchObject({ $schemaHash: fingerprint(table) })
|
|
117
|
+
expect(schemaMetaTable.sqliteDef.ast.columns.find((column) => column.name === 'schemaHash')?.type._tag).toBe('text')
|
|
118
|
+
})
|
|
88
119
|
})
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - EVENTLOG TABLES (NEVER modify): Changes cause data loss - need manual versioning!
|
|
9
9
|
*
|
|
10
10
|
* How it works:
|
|
11
|
-
* 1. Each table's schema is
|
|
11
|
+
* 1. Each table's schema is fingerprinted
|
|
12
12
|
* 2. Hashes are stored in SCHEMA_META_TABLE after successful migrations
|
|
13
13
|
* 3. On app start, current schema hashes are compared with stored hashes
|
|
14
14
|
* 4. Mismatches trigger migrations:
|
|
@@ -37,7 +37,8 @@ import type { MigrationsReport, MigrationsReportEntry } from '../defs.ts'
|
|
|
37
37
|
import type { UnknownError } from '../errors.ts'
|
|
38
38
|
import type { LiveStoreSchema } from '../schema/mod.ts'
|
|
39
39
|
import { makeColumnSpec } from '../schema/state/sqlite/column-spec.ts'
|
|
40
|
-
import {
|
|
40
|
+
import { fingerprint } from '../schema/state/sqlite/db-schema/ast/fingerprint.ts'
|
|
41
|
+
import type { SqliteAst } from '../schema/state/sqlite/db-schema/mod.ts'
|
|
41
42
|
import type { SchemaEventDefsMetaRow, SchemaMetaRow } from '../schema/state/sqlite/system-tables/state-tables.ts'
|
|
42
43
|
import {
|
|
43
44
|
isStateSystemTable,
|
|
@@ -114,14 +115,14 @@ export const migrateDb = ({
|
|
|
114
115
|
...Array.from(schema.state.sqlite.tables.values()).filter((_) => !isStateSystemTable(_.sqliteDef.name)),
|
|
115
116
|
]
|
|
116
117
|
|
|
117
|
-
const tablesToMigrate = new Set<{ tableAst: SqliteAst.Table; schemaHash:
|
|
118
|
+
const tablesToMigrate = new Set<{ tableAst: SqliteAst.Table; schemaHash: string }>()
|
|
118
119
|
|
|
119
120
|
const migrationsReportEntries: MigrationsReportEntry[] = []
|
|
120
121
|
for (const tableDef of tableDefs) {
|
|
121
122
|
const tableAst = tableDef.sqliteDef.ast
|
|
122
123
|
const tableName = tableAst.name
|
|
123
124
|
const dbSchemaHash = dbSchemaHashByTable[tableName]
|
|
124
|
-
const schemaHash =
|
|
125
|
+
const schemaHash = fingerprint(tableAst)
|
|
125
126
|
|
|
126
127
|
if (schemaHash !== dbSchemaHash) {
|
|
127
128
|
tablesToMigrate.add({ tableAst, schemaHash })
|
|
@@ -151,13 +152,13 @@ export const migrateDb = ({
|
|
|
151
152
|
export const migrateTable = ({
|
|
152
153
|
db,
|
|
153
154
|
tableAst,
|
|
154
|
-
schemaHash =
|
|
155
|
+
schemaHash = fingerprint(tableAst),
|
|
155
156
|
behaviour,
|
|
156
157
|
skipMetaTable = false,
|
|
157
158
|
}: {
|
|
158
159
|
db: SqliteDb
|
|
159
160
|
tableAst: SqliteAst.Table
|
|
160
|
-
schemaHash?:
|
|
161
|
+
schemaHash?: string
|
|
161
162
|
behaviour: 'drop-and-recreate' | 'create-if-not-exists'
|
|
162
163
|
skipMetaTable?: boolean
|
|
163
164
|
}) =>
|
|
@@ -298,7 +298,7 @@ Error: ${parseErrorStr}
|
|
|
298
298
|
Value:`,
|
|
299
299
|
value,
|
|
300
300
|
)
|
|
301
|
-
// oxlint-disable-next-line
|
|
301
|
+
// oxlint-disable-next-line no-debugger -- intentional breakpoint for SQL decode errors
|
|
302
302
|
debugger
|
|
303
303
|
throw res.failure
|
|
304
304
|
} else {
|
package/src/util.ts
CHANGED
|
@@ -19,6 +19,7 @@ export const SqliteReal = Schema.Number
|
|
|
19
19
|
|
|
20
20
|
export const SqlValueSchema = Schema.Union([
|
|
21
21
|
Schema.String,
|
|
22
|
+
// @effect-diagnostics-next-line schemaNumber:off -- SQLite REAL permits Infinity/NaN; SqliteReal is the documented domain carve-out
|
|
22
23
|
SqliteReal,
|
|
23
24
|
Schema.Uint8Array as any as Schema.Codec<Uint8Array<ArrayBuffer>>,
|
|
24
25
|
Schema.Null,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../../../../src/schema/state/sqlite/db-schema/hash.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,QAAQ,GAAI,KAAK,MAAM,WAWnC,CAAA"}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// Based on https://stackoverflow.com/a/7616484
|
|
2
|
-
export const hashCode = (str) => {
|
|
3
|
-
let hash = 0;
|
|
4
|
-
let i;
|
|
5
|
-
let chr;
|
|
6
|
-
if (str.length === 0)
|
|
7
|
-
return hash;
|
|
8
|
-
for (i = 0; i < str.length; i++) {
|
|
9
|
-
chr = str.charCodeAt(i);
|
|
10
|
-
hash = (hash << 5) - hash + chr;
|
|
11
|
-
hash = Math.trunc(hash); // Convert to 32bit integer
|
|
12
|
-
}
|
|
13
|
-
return hash;
|
|
14
|
-
};
|
|
15
|
-
//# sourceMappingURL=hash.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../../../../../src/schema/state/sqlite/db-schema/hash.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAE,EAAE;IACtC,IAAI,IAAI,GAAG,CAAC,CAAA;IACZ,IAAI,CAAS,CAAA;IACb,IAAI,GAAW,CAAA;IACf,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACjC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;QACvB,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,GAAG,GAAG,CAAA;QAC/B,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA,CAAC,2BAA2B;IACrD,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC,CAAA"}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// Based on https://stackoverflow.com/a/7616484
|
|
2
|
-
export const hashCode = (str: string) => {
|
|
3
|
-
let hash = 0
|
|
4
|
-
let i: number
|
|
5
|
-
let chr: number
|
|
6
|
-
if (str.length === 0) return hash
|
|
7
|
-
for (i = 0; i < str.length; i++) {
|
|
8
|
-
chr = str.charCodeAt(i)
|
|
9
|
-
hash = (hash << 5) - hash + chr
|
|
10
|
-
hash = Math.trunc(hash) // Convert to 32bit integer
|
|
11
|
-
}
|
|
12
|
-
return hash
|
|
13
|
-
}
|