@livestore/common 0.4.0-dev.22 → 0.4.0-dev.24
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 +9 -9
- package/dist/ClientSessionLeaderThreadProxy.d.ts.map +1 -1
- package/dist/WorkerTransportError.d.ts +11 -0
- package/dist/WorkerTransportError.d.ts.map +1 -0
- package/dist/WorkerTransportError.js +11 -0
- package/dist/WorkerTransportError.js.map +1 -0
- package/dist/adapter-types.d.ts +3 -3
- package/dist/adapter-types.d.ts.map +1 -1
- package/dist/adapter-types.js.map +1 -1
- package/dist/bounded-collections.d.ts.map +1 -1
- package/dist/bounded-collections.js +6 -4
- package/dist/bounded-collections.js.map +1 -1
- package/dist/debug-info.js +4 -4
- package/dist/debug-info.js.map +1 -1
- package/dist/devtools/devtools-messages-common.js +1 -1
- package/dist/devtools/devtools-messages-common.js.map +1 -1
- package/dist/devtools/mod.js +1 -1
- package/dist/devtools/mod.js.map +1 -1
- package/dist/errors.d.ts +15 -15
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +11 -11
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.d.ts +20 -6
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.js +287 -257
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
- package/dist/leader-thread/RejectedPushError.d.ts +107 -0
- package/dist/leader-thread/RejectedPushError.d.ts.map +1 -0
- package/dist/leader-thread/RejectedPushError.js +78 -0
- package/dist/leader-thread/RejectedPushError.js.map +1 -0
- package/dist/leader-thread/connection.js +1 -1
- package/dist/leader-thread/connection.js.map +1 -1
- package/dist/leader-thread/eventlog.d.ts.map +1 -1
- package/dist/leader-thread/eventlog.js +12 -11
- package/dist/leader-thread/eventlog.js.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.d.ts +1 -2
- package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.js +25 -14
- package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.d.ts +8 -3
- package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.js +7 -10
- package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.test.js +1 -1
- package/dist/leader-thread/make-leader-thread-layer.test.js.map +1 -1
- package/dist/leader-thread/materialize-event.js +4 -4
- package/dist/leader-thread/materialize-event.js.map +1 -1
- package/dist/leader-thread/recreate-db.js +1 -1
- package/dist/leader-thread/recreate-db.js.map +1 -1
- package/dist/leader-thread/shutdown-channel.d.ts +2 -2
- package/dist/leader-thread/shutdown-channel.d.ts.map +1 -1
- package/dist/leader-thread/shutdown-channel.js +2 -2
- package/dist/leader-thread/shutdown-channel.js.map +1 -1
- package/dist/leader-thread/stream-events.d.ts.map +1 -1
- package/dist/leader-thread/stream-events.js +4 -3
- package/dist/leader-thread/stream-events.js.map +1 -1
- package/dist/leader-thread/types.d.ts +7 -6
- package/dist/leader-thread/types.d.ts.map +1 -1
- package/dist/leader-thread/types.js.map +1 -1
- package/dist/logging.js +4 -4
- package/dist/logging.js.map +1 -1
- package/dist/make-client-session.js +2 -2
- package/dist/make-client-session.js.map +1 -1
- package/dist/materializer-helper.js +6 -6
- package/dist/materializer-helper.js.map +1 -1
- package/dist/otel.d.ts +1 -1
- package/dist/otel.d.ts.map +1 -1
- package/dist/otel.js +2 -2
- package/dist/otel.js.map +1 -1
- package/dist/rematerialize-from-eventlog.d.ts +1 -1
- package/dist/rematerialize-from-eventlog.d.ts.map +1 -1
- package/dist/rematerialize-from-eventlog.js +11 -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.js +4 -4
- package/dist/schema/EventDef/define.js.map +1 -1
- package/dist/schema/EventDef/deprecated.js +3 -3
- package/dist/schema/EventDef/deprecated.js.map +1 -1
- package/dist/schema/EventDef/deprecated.test.js +1 -1
- package/dist/schema/EventDef/deprecated.test.js.map +1 -1
- package/dist/schema/EventSequenceNumber/client.d.ts.map +1 -1
- package/dist/schema/EventSequenceNumber/client.js +11 -11
- package/dist/schema/EventSequenceNumber/client.js.map +1 -1
- package/dist/schema/EventSequenceNumber.test.js +1 -1
- package/dist/schema/EventSequenceNumber.test.js.map +1 -1
- package/dist/schema/LiveStoreEvent/client.d.ts +8 -0
- package/dist/schema/LiveStoreEvent/client.d.ts.map +1 -1
- package/dist/schema/LiveStoreEvent/client.js +15 -3
- package/dist/schema/LiveStoreEvent/client.js.map +1 -1
- package/dist/schema/LiveStoreEvent/client.test.d.ts +2 -0
- package/dist/schema/LiveStoreEvent/client.test.d.ts.map +1 -0
- package/dist/schema/LiveStoreEvent/client.test.js +111 -0
- package/dist/schema/LiveStoreEvent/client.test.js.map +1 -0
- package/dist/schema/schema.d.ts.map +1 -1
- package/dist/schema/schema.js +7 -4
- package/dist/schema/schema.js.map +1 -1
- package/dist/schema/state/sqlite/client-document-def.d.ts.map +1 -1
- package/dist/schema/state/sqlite/client-document-def.js +18 -6
- package/dist/schema/state/sqlite/client-document-def.js.map +1 -1
- package/dist/schema/state/sqlite/client-document-def.test.js +1 -1
- 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.js +1 -1
- package/dist/schema/state/sqlite/column-annotations.js.map +1 -1
- package/dist/schema/state/sqlite/column-annotations.test.js +1 -1
- package/dist/schema/state/sqlite/column-annotations.test.js.map +1 -1
- package/dist/schema/state/sqlite/column-def.d.ts.map +1 -1
- package/dist/schema/state/sqlite/column-def.js +36 -34
- package/dist/schema/state/sqlite/column-def.js.map +1 -1
- package/dist/schema/state/sqlite/column-def.test.js +7 -6
- 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 +8 -8
- package/dist/schema/state/sqlite/column-spec.js.map +1 -1
- package/dist/schema/state/sqlite/column-spec.test.js +1 -1
- package/dist/schema/state/sqlite/column-spec.test.js.map +1 -1
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.js +2 -2
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.js.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts +2 -2
- 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 +11 -2
- 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/field-defs.test.js.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts +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/dsl/mod.js.map +1 -1
- package/dist/schema/state/sqlite/mod.d.ts.map +1 -1
- package/dist/schema/state/sqlite/mod.js +3 -5
- package/dist/schema/state/sqlite/mod.js.map +1 -1
- package/dist/schema/state/sqlite/query-builder/api.d.ts +10 -2
- package/dist/schema/state/sqlite/query-builder/api.d.ts.map +1 -1
- package/dist/schema/state/sqlite/query-builder/astToSql.js +11 -11
- package/dist/schema/state/sqlite/query-builder/astToSql.js.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.d.ts +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.d.ts.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.js +28 -14
- package/dist/schema/state/sqlite/query-builder/impl.js.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.test.js +3 -2
- package/dist/schema/state/sqlite/query-builder/impl.test.js.map +1 -1
- package/dist/schema/state/sqlite/schema-helpers.js +2 -2
- package/dist/schema/state/sqlite/schema-helpers.js.map +1 -1
- package/dist/schema/state/sqlite/table-def.d.ts +5 -3
- package/dist/schema/state/sqlite/table-def.d.ts.map +1 -1
- package/dist/schema/state/sqlite/table-def.js +1 -1
- package/dist/schema/state/sqlite/table-def.js.map +1 -1
- package/dist/schema/state/sqlite/table-def.test.js +57 -4
- package/dist/schema/state/sqlite/table-def.test.js.map +1 -1
- package/dist/schema/unknown-events.d.ts +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 +1 -1
- package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js.map +1 -1
- package/dist/schema-management/common.js +2 -2
- package/dist/schema-management/common.js.map +1 -1
- package/dist/schema-management/migrations.js +1 -1
- package/dist/schema-management/migrations.js.map +1 -1
- package/dist/sql-queries/sql-queries.js +8 -6
- 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.map +1 -1
- package/dist/sqlite-db-helper.js +3 -3
- package/dist/sqlite-db-helper.js.map +1 -1
- package/dist/sqlite-types.d.ts +2 -2
- package/dist/sqlite-types.d.ts.map +1 -1
- package/dist/sqlite-types.js.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.d.ts +8 -9
- package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.js +95 -113
- package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
- package/dist/sync/errors.d.ts +0 -38
- package/dist/sync/errors.d.ts.map +1 -1
- package/dist/sync/errors.js +3 -20
- package/dist/sync/errors.js.map +1 -1
- package/dist/sync/mock-sync-backend.d.ts +5 -3
- package/dist/sync/mock-sync-backend.d.ts.map +1 -1
- package/dist/sync/mock-sync-backend.js +70 -68
- package/dist/sync/mock-sync-backend.js.map +1 -1
- package/dist/sync/next/compact-events.js +6 -6
- package/dist/sync/next/compact-events.js.map +1 -1
- package/dist/sync/next/facts.d.ts.map +1 -1
- package/dist/sync/next/facts.js +6 -6
- package/dist/sync/next/facts.js.map +1 -1
- package/dist/sync/next/history-dag-common.d.ts.map +1 -1
- package/dist/sync/next/history-dag-common.js +6 -6
- package/dist/sync/next/history-dag-common.js.map +1 -1
- package/dist/sync/next/history-dag.js +3 -3
- package/dist/sync/next/history-dag.js.map +1 -1
- package/dist/sync/next/rebase-events.js +1 -1
- package/dist/sync/next/rebase-events.js.map +1 -1
- package/dist/sync/next/test/compact-events.calculator.test.js +2 -2
- package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
- package/dist/sync/next/test/compact-events.test.d.ts.map +1 -1
- package/dist/sync/next/test/compact-events.test.js +2 -2
- package/dist/sync/next/test/compact-events.test.js.map +1 -1
- package/dist/sync/next/test/event-fixtures.d.ts.map +1 -1
- package/dist/sync/next/test/event-fixtures.js +2 -2
- package/dist/sync/next/test/event-fixtures.js.map +1 -1
- package/dist/sync/sync-backend-kv.d.ts.map +1 -1
- package/dist/sync/sync-backend-kv.js.map +1 -1
- package/dist/sync/sync-backend.d.ts +3 -3
- package/dist/sync/sync-backend.d.ts.map +1 -1
- package/dist/sync/sync-backend.js +1 -1
- package/dist/sync/sync-backend.js.map +1 -1
- package/dist/sync/sync.d.ts +20 -0
- package/dist/sync/sync.d.ts.map +1 -1
- package/dist/sync/syncstate.d.ts +4 -17
- package/dist/sync/syncstate.d.ts.map +1 -1
- package/dist/sync/syncstate.js +51 -74
- package/dist/sync/syncstate.js.map +1 -1
- package/dist/sync/syncstate.test.js +148 -96
- package/dist/sync/syncstate.test.js.map +1 -1
- package/dist/sync/transport-chunking.js +3 -3
- package/dist/sync/transport-chunking.js.map +1 -1
- package/dist/sync/validate-push-payload.d.ts +2 -2
- package/dist/sync/validate-push-payload.d.ts.map +1 -1
- package/dist/sync/validate-push-payload.js +4 -6
- package/dist/sync/validate-push-payload.js.map +1 -1
- package/dist/util.js +2 -2
- package/dist/util.js.map +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +2 -5
- package/dist/version.js.map +1 -1
- package/package.json +66 -12
- package/src/ClientSessionLeaderThreadProxy.ts +9 -9
- package/src/WorkerTransportError.ts +12 -0
- package/src/adapter-types.ts +9 -3
- package/src/bounded-collections.ts +6 -5
- package/src/debug-info.ts +4 -4
- package/src/devtools/devtools-messages-common.ts +1 -1
- package/src/devtools/mod.ts +1 -1
- package/src/errors.ts +18 -17
- package/src/index.ts +2 -0
- package/src/leader-thread/LeaderSyncProcessor.ts +421 -392
- package/src/leader-thread/RejectedPushError.ts +106 -0
- package/src/leader-thread/connection.ts +1 -1
- package/src/leader-thread/eventlog.ts +16 -14
- package/src/leader-thread/leader-worker-devtools.ts +96 -66
- package/src/leader-thread/make-leader-thread-layer.test.ts +1 -1
- package/src/leader-thread/make-leader-thread-layer.ts +33 -31
- package/src/leader-thread/materialize-event.ts +4 -4
- package/src/leader-thread/recreate-db.ts +1 -1
- package/src/leader-thread/shutdown-channel.ts +2 -6
- package/src/leader-thread/stream-events.ts +10 -5
- package/src/leader-thread/types.ts +7 -6
- package/src/logging.ts +4 -4
- package/src/make-client-session.ts +2 -2
- package/src/materializer-helper.ts +9 -9
- package/src/otel.ts +3 -2
- package/src/rematerialize-from-eventlog.ts +60 -60
- package/src/schema/EventDef/define.ts +6 -6
- package/src/schema/EventDef/deprecated.test.ts +2 -1
- package/src/schema/EventDef/deprecated.ts +3 -3
- package/src/schema/EventSequenceNumber/client.ts +11 -11
- package/src/schema/EventSequenceNumber.test.ts +2 -1
- package/src/schema/LiveStoreEvent/client.test.ts +129 -0
- package/src/schema/LiveStoreEvent/client.ts +17 -3
- package/src/schema/schema.ts +9 -4
- package/src/schema/state/sqlite/client-document-def.test.ts +2 -1
- package/src/schema/state/sqlite/client-document-def.ts +20 -6
- package/src/schema/state/sqlite/column-annotations.test.ts +2 -1
- package/src/schema/state/sqlite/column-annotations.ts +2 -1
- package/src/schema/state/sqlite/column-def.test.ts +8 -6
- package/src/schema/state/sqlite/column-def.ts +41 -36
- package/src/schema/state/sqlite/column-spec.test.ts +3 -1
- package/src/schema/state/sqlite/column-spec.ts +9 -8
- package/src/schema/state/sqlite/db-schema/ast/sqlite.ts +2 -2
- package/src/schema/state/sqlite/db-schema/dsl/field-defs.test.ts +2 -1
- package/src/schema/state/sqlite/db-schema/dsl/field-defs.ts +13 -4
- package/src/schema/state/sqlite/db-schema/dsl/mod.ts +3 -3
- package/src/schema/state/sqlite/mod.ts +4 -5
- package/src/schema/state/sqlite/query-builder/api.ts +12 -5
- package/src/schema/state/sqlite/query-builder/astToSql.ts +11 -11
- package/src/schema/state/sqlite/query-builder/impl.test.ts +4 -2
- package/src/schema/state/sqlite/query-builder/impl.ts +26 -12
- package/src/schema/state/sqlite/schema-helpers.ts +2 -2
- package/src/schema/state/sqlite/table-def.test.ts +67 -4
- package/src/schema/state/sqlite/table-def.ts +8 -15
- package/src/schema/unknown-events.ts +2 -2
- package/src/schema-management/__tests__/migrations-autoincrement-quoting.test.ts +3 -1
- package/src/schema-management/common.ts +2 -2
- package/src/schema-management/migrations.ts +1 -1
- package/src/sql-queries/sql-queries.ts +10 -6
- package/src/sql-queries/sql-query-builder.ts +1 -0
- package/src/sqlite-db-helper.ts +3 -3
- package/src/sqlite-types.ts +3 -2
- package/src/sync/ClientSessionSyncProcessor.ts +148 -152
- package/src/sync/errors.ts +10 -22
- package/src/sync/mock-sync-backend.ts +139 -97
- package/src/sync/next/compact-events.ts +5 -5
- package/src/sync/next/facts.ts +7 -6
- package/src/sync/next/history-dag-common.ts +9 -6
- package/src/sync/next/history-dag.ts +3 -3
- package/src/sync/next/rebase-events.ts +1 -1
- package/src/sync/next/test/compact-events.calculator.test.ts +3 -2
- package/src/sync/next/test/compact-events.test.ts +4 -3
- package/src/sync/next/test/event-fixtures.ts +2 -2
- package/src/sync/sync-backend-kv.ts +1 -0
- package/src/sync/sync-backend.ts +5 -4
- package/src/sync/sync.ts +21 -0
- package/src/sync/syncstate.test.ts +553 -433
- package/src/sync/syncstate.ts +80 -86
- package/src/sync/transport-chunking.ts +3 -3
- package/src/sync/validate-push-payload.ts +4 -6
- package/src/util.ts +2 -2
- package/src/version.ts +2 -6
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Schema } from '@livestore/utils/effect'
|
|
2
|
+
|
|
2
3
|
import { type SqliteAst, SqliteDsl } from './db-schema/mod.ts'
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -12,13 +13,13 @@ import { type SqliteAst, SqliteDsl } from './db-schema/mod.ts'
|
|
|
12
13
|
export const makeColumnSpec = (tableAst: SqliteAst.Table) => {
|
|
13
14
|
const pkColumns = tableAst.columns.filter((_) => _.primaryKey)
|
|
14
15
|
const hasSinglePk = pkColumns.length === 1
|
|
15
|
-
const pkColumn = hasSinglePk ? pkColumns[0] : undefined
|
|
16
|
+
const pkColumn = hasSinglePk === true ? pkColumns[0] : undefined
|
|
16
17
|
|
|
17
18
|
// Build column definitions, handling the special SQLite rule that AUTOINCREMENT
|
|
18
19
|
// is only valid on a single column declared as INTEGER PRIMARY KEY (column-level).
|
|
19
20
|
const columnDefStrs = tableAst.columns.map((column) =>
|
|
20
21
|
toSqliteColumnSpec(column, {
|
|
21
|
-
inlinePrimaryKey: hasSinglePk && column === pkColumn &&
|
|
22
|
+
inlinePrimaryKey: hasSinglePk && column === pkColumn && column.primaryKey,
|
|
22
23
|
}),
|
|
23
24
|
)
|
|
24
25
|
|
|
@@ -36,24 +37,24 @@ const toSqliteColumnSpec = (column: SqliteAst.Column, opts: { inlinePrimaryKey:
|
|
|
36
37
|
const columnTypeStr = column.type._tag
|
|
37
38
|
// When PRIMARY KEY is declared inline, NOT NULL is implied and should not be emitted,
|
|
38
39
|
// and AUTOINCREMENT must immediately follow PRIMARY KEY within the same constraint.
|
|
39
|
-
const nullableStr = opts.inlinePrimaryKey ? '' : column.nullable === false ? 'not null' : ''
|
|
40
|
+
const nullableStr = opts.inlinePrimaryKey === true ? '' : column.nullable === false ? 'not null' : ''
|
|
40
41
|
|
|
41
42
|
// Only include AUTOINCREMENT when it's valid: single-column INTEGER PRIMARY KEY
|
|
42
|
-
const includeAutoIncrement = opts.inlinePrimaryKey && column.type._tag === 'integer' && column.autoIncrement === true
|
|
43
|
+
const includeAutoIncrement = opts.inlinePrimaryKey === true && column.type._tag === 'integer' && column.autoIncrement === true
|
|
43
44
|
|
|
44
|
-
const pkStr = opts.inlinePrimaryKey ? 'primary key' : ''
|
|
45
|
-
const autoIncrementStr = includeAutoIncrement ? 'autoincrement' : ''
|
|
45
|
+
const pkStr = opts.inlinePrimaryKey === true ? 'primary key' : ''
|
|
46
|
+
const autoIncrementStr = includeAutoIncrement === true ? 'autoincrement' : ''
|
|
46
47
|
|
|
47
48
|
const defaultValueStr = (() => {
|
|
48
49
|
if (column.default._tag === 'None') return ''
|
|
49
50
|
|
|
50
51
|
const defaultValue = column.default.value
|
|
51
|
-
if (SqliteDsl.isDefaultThunk(defaultValue)) return ''
|
|
52
|
+
if (SqliteDsl.isDefaultThunk(defaultValue) === true) return ''
|
|
52
53
|
|
|
53
54
|
const resolvedDefault = SqliteDsl.resolveColumnDefault(defaultValue)
|
|
54
55
|
|
|
55
56
|
if (resolvedDefault === null) return 'default null'
|
|
56
|
-
if (SqliteDsl.isSqlDefaultValue(resolvedDefault)) return `default ${resolvedDefault.sql}`
|
|
57
|
+
if (SqliteDsl.isSqlDefaultValue(resolvedDefault) === true) return `default ${resolvedDefault.sql}`
|
|
57
58
|
|
|
58
59
|
const encodeValue = Schema.encodeSync(column.schema)
|
|
59
60
|
const encodedDefaultValue = encodeValue(resolvedDefault)
|
|
@@ -124,7 +124,7 @@ const trimInfoForHasing = (obj: Table | Column | Index | ForeignKey | DbSchema):
|
|
|
124
124
|
|
|
125
125
|
// NEW: Include schema hash for JSON columns
|
|
126
126
|
// This ensures that changes to the JSON schema are detected
|
|
127
|
-
if (isJsonColumn(obj) && obj.schema) {
|
|
127
|
+
if (isJsonColumn(obj) === true && obj.schema !== undefined) {
|
|
128
128
|
// Use Effect's Schema.hash for consistent hashing
|
|
129
129
|
baseInfo.jsonSchemaHash = Schema.hash(obj.schema)
|
|
130
130
|
}
|
|
@@ -155,7 +155,7 @@ const trimInfoForHasing = (obj: Table | Column | Index | ForeignKey | DbSchema):
|
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
default: {
|
|
158
|
-
throw new Error(`Unreachable: ${obj}`)
|
|
158
|
+
throw new Error(`Unreachable: ${String(obj)}`)
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
161
|
}
|
|
@@ -6,6 +6,7 @@ export type SqlDefaultValue = {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
export const isSqlDefaultValue = (value: unknown): value is SqlDefaultValue => {
|
|
9
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- type guard property access after structural check
|
|
9
10
|
return typeof value === 'object' && value !== null && 'sql' in value && typeof (value as any).sql === 'string'
|
|
10
11
|
}
|
|
11
12
|
|
|
@@ -16,14 +17,14 @@ export const isDefaultThunk = (value: unknown): value is ColumnDefaultThunk<unkn
|
|
|
16
17
|
export type ColumnDefaultValue<T> = T | null | ColumnDefaultThunk<T | null> | SqlDefaultValue
|
|
17
18
|
|
|
18
19
|
export const resolveColumnDefault = <T>(value: ColumnDefaultValue<T>): T | null | SqlDefaultValue =>
|
|
19
|
-
isDefaultThunk(value) ?
|
|
20
|
+
isDefaultThunk(value) === true ? value() : value
|
|
20
21
|
|
|
21
|
-
export type ColumnDefinition<TEncoded, TDecoded> = {
|
|
22
|
+
export type ColumnDefinition<TEncoded, TDecoded, TNullable extends boolean = boolean> = {
|
|
22
23
|
readonly columnType: FieldColumnType
|
|
23
24
|
readonly schema: Schema.Schema<TDecoded, TEncoded>
|
|
24
25
|
readonly default: Option.Option<ColumnDefaultValue<TDecoded>>
|
|
25
26
|
/** @default false */
|
|
26
|
-
readonly nullable:
|
|
27
|
+
readonly nullable: TNullable
|
|
27
28
|
/** @default false */
|
|
28
29
|
readonly primaryKey: boolean
|
|
29
30
|
/** @default false */
|
|
@@ -40,6 +41,7 @@ export const isColumnDefinition = (value: unknown): value is ColumnDefinition.An
|
|
|
40
41
|
typeof value === 'object' &&
|
|
41
42
|
value !== null &&
|
|
42
43
|
'columnType' in value &&
|
|
44
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- type guard narrowing; columnType checked to be in valid set
|
|
43
45
|
validColumnTypes.includes(value.columnType as any)
|
|
44
46
|
)
|
|
45
47
|
}
|
|
@@ -105,6 +107,7 @@ const makeColDef =
|
|
|
105
107
|
const schema = nullable === true ? Schema.NullOr(schemaWithoutNull) : schemaWithoutNull
|
|
106
108
|
const default_ = def?.default === undefined || def.default === NoDefault ? Option.none() : Option.some(def.default)
|
|
107
109
|
|
|
110
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- column factory return type uses complex conditional generics; consumer type safety enforced by ColDefFn signature
|
|
108
111
|
return {
|
|
109
112
|
columnType,
|
|
110
113
|
schema,
|
|
@@ -200,10 +203,12 @@ type MakeSpecializedColDefFn = {
|
|
|
200
203
|
|
|
201
204
|
const makeSpecializedColDef: MakeSpecializedColDefFn = (columnType, opts) => (def?: ColumnDefinitionInput) => {
|
|
202
205
|
const nullable = def?.nullable ?? false
|
|
206
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- schema type variance; custom schema compatibility checked at call site
|
|
203
207
|
const schemaWithoutNull = opts._tag === 'baseSchemaFn' ? opts.baseSchemaFn(def?.schema as any) : opts.baseSchema
|
|
204
208
|
const schema = nullable === true ? Schema.NullOr(schemaWithoutNull) : schemaWithoutNull
|
|
205
209
|
const default_ = def?.default === undefined || def.default === NoDefault ? Option.none() : Option.some(def.default)
|
|
206
210
|
|
|
211
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- specialized column factory return type uses complex conditional generics; consumer type safety enforced by SpecializedColDefFn signature
|
|
207
212
|
return {
|
|
208
213
|
columnType,
|
|
209
214
|
schema,
|
|
@@ -236,7 +241,7 @@ export const boolean: SpecializedColDefFn<'integer', false, boolean> = makeSpeci
|
|
|
236
241
|
_tag: 'baseSchema',
|
|
237
242
|
baseSchema: Schema.transform(Schema.Number, Schema.Boolean, {
|
|
238
243
|
decode: (_) => _ === 1,
|
|
239
|
-
encode: (_) => (_ ? 1 : 0),
|
|
244
|
+
encode: (_) => (_ === true ? 1 : 0),
|
|
240
245
|
}),
|
|
241
246
|
})
|
|
242
247
|
|
|
@@ -259,15 +264,19 @@ export const defaultSchemaForColumnType = <TColumnType extends FieldColumnType>(
|
|
|
259
264
|
|
|
260
265
|
switch (columnType) {
|
|
261
266
|
case 'text': {
|
|
267
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- switch-based type narrowing for column type to schema mapping; each case is correct for its branch
|
|
262
268
|
return Schema.String as any as Schema.Schema<T>
|
|
263
269
|
}
|
|
264
270
|
case 'integer': {
|
|
271
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- switch-based type narrowing for column type to schema mapping; each case is correct for its branch
|
|
265
272
|
return Schema.Number as any as Schema.Schema<T>
|
|
266
273
|
}
|
|
267
274
|
case 'real': {
|
|
275
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- switch-based type narrowing for column type to schema mapping; each case is correct for its branch
|
|
268
276
|
return Schema.Number as any as Schema.Schema<T>
|
|
269
277
|
}
|
|
270
278
|
case 'blob': {
|
|
279
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- switch-based type narrowing for column type to schema mapping; each case is correct for its branch
|
|
271
280
|
return Schema.Uint8ArrayFromSelf as any as Schema.Schema<T>
|
|
272
281
|
}
|
|
273
282
|
default: {
|
|
@@ -31,7 +31,7 @@ export type DbSchemaFromInputSchema<TSchemaInput extends DbSchemaInput> =
|
|
|
31
31
|
export const makeDbSchema = <TDbSchemaInput extends DbSchemaInput>(
|
|
32
32
|
schema: TDbSchemaInput,
|
|
33
33
|
): DbSchemaFromInputSchema<TDbSchemaInput> => {
|
|
34
|
-
return Array.isArray(schema) ? Object.fromEntries(schema.map((_) => [_.name, _])) : (schema as any)
|
|
34
|
+
return Array.isArray(schema) === true ? Object.fromEntries(schema.map((_) => [_.name, _])) : (schema as any)
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
export const table = <TTableName extends string, TColumns extends Columns, TIndexes extends Index[]>(
|
|
@@ -76,6 +76,7 @@ export const insertStructSchemaForTable = <TTableDefinition extends TableDefinit
|
|
|
76
76
|
Object.fromEntries(
|
|
77
77
|
tableDef.ast.columns.map((column) => [
|
|
78
78
|
column.name,
|
|
79
|
+
|
|
79
80
|
column.nullable === true || column.default._tag === 'Some' ? Schema.optional(column.schema) : column.schema,
|
|
80
81
|
]),
|
|
81
82
|
),
|
|
@@ -195,8 +196,7 @@ export namespace FromColumns {
|
|
|
195
196
|
}
|
|
196
197
|
|
|
197
198
|
export type NullableColumnNames<TColumns extends Columns> = keyof {
|
|
198
|
-
|
|
199
|
-
[K in keyof TColumns as TColumns[K] extends ColumnDefinition<any, true> ? K : never]: {}
|
|
199
|
+
[K in keyof TColumns as TColumns[K]['nullable'] extends true ? K : never]: {}
|
|
200
200
|
}
|
|
201
201
|
|
|
202
202
|
export type RequiredInsertColumns<TColumns extends Columns> = {
|
|
@@ -22,16 +22,15 @@ export * from './column-spec.ts'
|
|
|
22
22
|
export * from './table-def.ts'
|
|
23
23
|
|
|
24
24
|
export const makeState = <TStateInput extends InputState>(inputSchema: TStateInput): InternalState => {
|
|
25
|
-
const inputTables: ReadonlyArray<TableDef> =
|
|
26
|
-
? inputSchema.tables
|
|
27
|
-
: Object.values(inputSchema.tables)
|
|
25
|
+
const inputTables: ReadonlyArray<TableDef> =
|
|
26
|
+
Array.isArray(inputSchema.tables) === true ? inputSchema.tables : Object.values(inputSchema.tables)
|
|
28
27
|
|
|
29
28
|
const tables = new Map<string, TableDef.Any>()
|
|
30
29
|
|
|
31
30
|
for (const tableDef of inputTables) {
|
|
32
31
|
const sqliteDef = tableDef.sqliteDef
|
|
33
32
|
// TODO validate tables (e.g. index names are unique)
|
|
34
|
-
if (tables.has(sqliteDef.ast.name)) {
|
|
33
|
+
if (tables.has(sqliteDef.ast.name) === true) {
|
|
35
34
|
shouldNeverHappen(`Duplicate table name: ${sqliteDef.ast.name}. Please use unique names for tables.`)
|
|
36
35
|
}
|
|
37
36
|
tables.set(sqliteDef.ast.name, tableDef)
|
|
@@ -48,7 +47,7 @@ export const makeState = <TStateInput extends InputState>(inputSchema: TStateInp
|
|
|
48
47
|
}
|
|
49
48
|
|
|
50
49
|
for (const tableDef of inputTables) {
|
|
51
|
-
if (tableIsClientDocumentTable(tableDef)) {
|
|
50
|
+
if (tableIsClientDocumentTable(tableDef) === true) {
|
|
52
51
|
materializers.set(
|
|
53
52
|
tableDef[ClientDocumentTableDefSymbol].derived.setEventDef.name,
|
|
54
53
|
tableDef[ClientDocumentTableDefSymbol].derived.setMaterializer,
|
|
@@ -230,9 +230,8 @@ export namespace QueryBuilder {
|
|
|
230
230
|
/** Select multiple columns */
|
|
231
231
|
<TColumns extends keyof TTableDef['sqliteDef']['columns'] & string>(
|
|
232
232
|
...columns: TColumns[]
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
): QueryBuilder<
|
|
233
|
+
)// params: QueryBuilderSelectParams, // TODO also support arbitrary SQL selects
|
|
234
|
+
: QueryBuilder<
|
|
236
235
|
ReadonlyArray<{
|
|
237
236
|
readonly [K in TColumns]: TTableDef['sqliteDef']['columns'][K]['schema']['Type']
|
|
238
237
|
}>,
|
|
@@ -358,12 +357,20 @@ export namespace QueryBuilder {
|
|
|
358
357
|
>
|
|
359
358
|
|
|
360
359
|
/**
|
|
361
|
-
* Insert a new row into the table
|
|
360
|
+
* Insert a new row into the table.
|
|
361
|
+
*
|
|
362
|
+
* @remarks
|
|
363
|
+
*
|
|
364
|
+
* Follows SQL semantics: nullable columns and columns with defaults are omittable.
|
|
365
|
+
* `NullOr(S)` and `optional(NullOr(S))` both produce nullable columns, so both are omittable.
|
|
366
|
+
*
|
|
367
|
+
* @example
|
|
362
368
|
*
|
|
363
|
-
* Example:
|
|
364
369
|
* ```ts
|
|
365
370
|
* db.todos.insert({ id: '123', text: 'Buy milk', status: 'active' })
|
|
366
371
|
* ```
|
|
372
|
+
*
|
|
373
|
+
* @param values - The row values to insert.
|
|
367
374
|
*/
|
|
368
375
|
readonly insert: (
|
|
369
376
|
values: TTableDef['insertSchema']['Type'],
|
|
@@ -11,11 +11,11 @@ import type { QueryBuilderAst } from './api.ts'
|
|
|
11
11
|
* Returns the element schema, or undefined if not a JSON array transformation.
|
|
12
12
|
*/
|
|
13
13
|
const extractArrayElementFromTransformation = (ast: SchemaAST.AST): Schema.Schema.Any | undefined => {
|
|
14
|
-
if (
|
|
14
|
+
if (SchemaAST.isTransformation(ast) === false) return undefined
|
|
15
15
|
|
|
16
16
|
const toAst = ast.to
|
|
17
17
|
// Check if the "to" side is a TupleType (Effect's internal representation of Array)
|
|
18
|
-
if (
|
|
18
|
+
if (SchemaAST.isTupleType(toAst) === false) return undefined
|
|
19
19
|
|
|
20
20
|
// For Schema.Array, rest contains { type: AST } elements - get the first one's type
|
|
21
21
|
const restElement = toAst.rest[0]
|
|
@@ -34,13 +34,13 @@ const getJsonArrayElementSchema = (colSchema: Schema.Schema.Any): Schema.Schema.
|
|
|
34
34
|
|
|
35
35
|
// Case 1: Direct transformation (non-nullable JSON array)
|
|
36
36
|
// Schema.parseJson(Schema.Array(ElementSchema)) creates a Transformation AST
|
|
37
|
-
if (SchemaAST.isTransformation(ast)) {
|
|
37
|
+
if (SchemaAST.isTransformation(ast) === true) {
|
|
38
38
|
return extractArrayElementFromTransformation(ast)
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
// Case 2: Nullable JSON array - Schema.NullOr wraps the parseJson in a Union
|
|
42
42
|
// Structure: Union([Transformation (JSON array), Literal (null)])
|
|
43
|
-
if (SchemaAST.isUnion(ast)) {
|
|
43
|
+
if (SchemaAST.isUnion(ast) === true) {
|
|
44
44
|
for (const member of ast.types) {
|
|
45
45
|
const result = extractArrayElementFromTransformation(member)
|
|
46
46
|
if (result !== undefined) return result
|
|
@@ -63,7 +63,7 @@ const encodeJsonArrayElementValue = (elementSchema: Schema.Schema.Any, value: un
|
|
|
63
63
|
return JSON.stringify(encoded)
|
|
64
64
|
}
|
|
65
65
|
if (typeof encoded === 'boolean') {
|
|
66
|
-
return encoded ? 1 : 0
|
|
66
|
+
return encoded === true ? 1 : 0
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
return encoded
|
|
@@ -118,9 +118,9 @@ const formatWhereClause = (
|
|
|
118
118
|
// Handle array values for IN/NOT IN operators
|
|
119
119
|
const isArray = op === 'IN' || op === 'NOT IN'
|
|
120
120
|
|
|
121
|
-
if (isArray) {
|
|
121
|
+
if (isArray === true) {
|
|
122
122
|
// Verify value is an array
|
|
123
|
-
if (
|
|
123
|
+
if (Array.isArray(value) === false) {
|
|
124
124
|
return shouldNeverHappen(`Expected array value for ${op} operator but got`, value)
|
|
125
125
|
}
|
|
126
126
|
|
|
@@ -145,7 +145,7 @@ const formatWhereClause = (
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
const formatReturningClause = (returning?: string[]): string => {
|
|
148
|
-
if (
|
|
148
|
+
if (returning == null || returning.length === 0) return ''
|
|
149
149
|
return ` RETURNING ${returning.map(quoteIdentifier).join(', ')}`
|
|
150
150
|
}
|
|
151
151
|
|
|
@@ -169,7 +169,7 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
|
|
|
169
169
|
let conflictClause = '' // Store the ON CONFLICT clause separately
|
|
170
170
|
|
|
171
171
|
// Handle ON CONFLICT clause
|
|
172
|
-
if (ast.onConflict) {
|
|
172
|
+
if (ast.onConflict !== undefined) {
|
|
173
173
|
// Handle REPLACE specifically as it changes the INSERT verb
|
|
174
174
|
if (ast.onConflict.action._tag === 'replace') {
|
|
175
175
|
insertVerb = 'INSERT OR REPLACE'
|
|
@@ -249,7 +249,7 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
|
|
|
249
249
|
.join(', ')}`
|
|
250
250
|
|
|
251
251
|
const whereClause = formatWhereClause(ast.where, ast.tableDef, bindValues)
|
|
252
|
-
if (whereClause) query += ` ${whereClause}`
|
|
252
|
+
if (whereClause !== undefined) query += ` ${whereClause}`
|
|
253
253
|
|
|
254
254
|
query += formatReturningClause(ast.returning)
|
|
255
255
|
return { query, bindValues, usedTables }
|
|
@@ -260,7 +260,7 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
|
|
|
260
260
|
let query = `DELETE FROM '${ast.tableDef.sqliteDef.name}'`
|
|
261
261
|
|
|
262
262
|
const whereClause = formatWhereClause(ast.where, ast.tableDef, bindValues)
|
|
263
|
-
if (whereClause) query += ` ${whereClause}`
|
|
263
|
+
if (whereClause !== undefined) query += ` ${whereClause}`
|
|
264
264
|
|
|
265
265
|
query += formatReturningClause(ast.returning)
|
|
266
266
|
return { query, bindValues, usedTables }
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { Schema } from '@livestore/utils/effect'
|
|
2
1
|
import { describe, expect, it } from 'vitest'
|
|
3
2
|
|
|
3
|
+
import { Schema } from '@livestore/utils/effect'
|
|
4
|
+
import { objectToString } from '@livestore/utils'
|
|
5
|
+
|
|
4
6
|
import { State } from '../../../mod.ts'
|
|
5
7
|
import type { QueryBuilder } from './api.ts'
|
|
6
8
|
import { getResultSchema } from './impl.ts'
|
|
@@ -101,7 +103,7 @@ const db = { todos, todosWithIntId, comments, issue, selections, UiState, UiStat
|
|
|
101
103
|
const dump = (qb: QueryBuilder<any, any, any>) => ({
|
|
102
104
|
bindValues: qb.asSql().bindValues,
|
|
103
105
|
query: qb.asSql().query,
|
|
104
|
-
schema: getResultSchema(qb)
|
|
106
|
+
schema: objectToString(getResultSchema(qb)),
|
|
105
107
|
})
|
|
106
108
|
|
|
107
109
|
describe('query builder', () => {
|
|
@@ -9,7 +9,7 @@ import { astToSql } from './astToSql.ts'
|
|
|
9
9
|
export const makeQueryBuilder = <TResult, TTableDef extends TableDefBase>(
|
|
10
10
|
tableDef: TTableDef,
|
|
11
11
|
ast: QueryBuilderAst = emptyAst(tableDef),
|
|
12
|
-
): QueryBuilder<TResult, TTableDef
|
|
12
|
+
): QueryBuilder<TResult, TTableDef> => {
|
|
13
13
|
const api = {
|
|
14
14
|
select() {
|
|
15
15
|
assertSelectQueryBuilderAst(ast)
|
|
@@ -18,6 +18,7 @@ export const makeQueryBuilder = <TResult, TTableDef extends TableDefBase>(
|
|
|
18
18
|
|
|
19
19
|
// Pluck if there's only one column selected
|
|
20
20
|
if (params.length === 1) {
|
|
21
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- arguments-based overload dispatch requires manual narrowing
|
|
21
22
|
const [col] = params as any as [string]
|
|
22
23
|
return makeQueryBuilder(tableDef, {
|
|
23
24
|
...ast,
|
|
@@ -26,8 +27,10 @@ export const makeQueryBuilder = <TResult, TTableDef extends TableDefBase>(
|
|
|
26
27
|
})
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- arguments-based overload dispatch requires manual narrowing
|
|
29
31
|
const columns = params as unknown as ReadonlyArray<string>
|
|
30
32
|
|
|
33
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- query builder return type depends on AST state; consumer type safety enforced by api.ts
|
|
31
34
|
return makeQueryBuilder(tableDef, {
|
|
32
35
|
...ast,
|
|
33
36
|
resultSchemaSingle:
|
|
@@ -44,7 +47,8 @@ export const makeQueryBuilder = <TResult, TTableDef extends TableDefBase>(
|
|
|
44
47
|
const newOps = Object.entries(params)
|
|
45
48
|
.filter(([, value]) => value !== undefined)
|
|
46
49
|
.map<QueryBuilderAst.Where>(([col, value]) =>
|
|
47
|
-
Predicate.hasProperty(value, 'op') && Predicate.hasProperty(value, 'value')
|
|
50
|
+
Predicate.hasProperty(value, 'op') === true && Predicate.hasProperty(value, 'value') === true
|
|
51
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- where clause construction; shape validated at runtime
|
|
48
52
|
? ({ col, op: value.op, value: value.value } as any)
|
|
49
53
|
: { col, op: '=', value },
|
|
50
54
|
)
|
|
@@ -54,6 +58,7 @@ export const makeQueryBuilder = <TResult, TTableDef extends TableDefBase>(
|
|
|
54
58
|
case 'SelectQuery':
|
|
55
59
|
case 'UpdateQuery':
|
|
56
60
|
case 'DeleteQuery': {
|
|
61
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- query builder return type depends on AST state; consumer type safety enforced by api.ts
|
|
57
62
|
return makeQueryBuilder(tableDef, {
|
|
58
63
|
...ast,
|
|
59
64
|
where: [...ast.where, ...newOps],
|
|
@@ -74,6 +79,7 @@ export const makeQueryBuilder = <TResult, TTableDef extends TableDefBase>(
|
|
|
74
79
|
case 'SelectQuery':
|
|
75
80
|
case 'UpdateQuery':
|
|
76
81
|
case 'DeleteQuery': {
|
|
82
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- query builder return type depends on AST state; consumer type safety enforced by api.ts
|
|
77
83
|
return makeQueryBuilder(tableDef, {
|
|
78
84
|
...ast,
|
|
79
85
|
where: [...ast.where, { col, op, value }],
|
|
@@ -91,6 +97,7 @@ export const makeQueryBuilder = <TResult, TTableDef extends TableDefBase>(
|
|
|
91
97
|
if (arguments.length === 0 || arguments.length > 2) return invalidQueryBuilder()
|
|
92
98
|
|
|
93
99
|
if (arguments.length === 1) {
|
|
100
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- arguments-based overload dispatch requires manual narrowing
|
|
94
101
|
const params = arguments[0] as QueryBuilder.OrderByParams<TTableDef>
|
|
95
102
|
return makeQueryBuilder(tableDef, {
|
|
96
103
|
...ast,
|
|
@@ -98,8 +105,10 @@ export const makeQueryBuilder = <TResult, TTableDef extends TableDefBase>(
|
|
|
98
105
|
})
|
|
99
106
|
}
|
|
100
107
|
|
|
108
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- arguments-based overload dispatch requires manual narrowing
|
|
101
109
|
const [col, direction] = arguments as any as [keyof TTableDef['sqliteDef']['columns'] & string, 'asc' | 'desc']
|
|
102
110
|
|
|
111
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- query builder return type depends on AST state; consumer type safety enforced by api.ts
|
|
103
112
|
return makeQueryBuilder(tableDef, {
|
|
104
113
|
...ast,
|
|
105
114
|
orderBy: [...ast.orderBy, { col, direction }],
|
|
@@ -116,7 +125,7 @@ export const makeQueryBuilder = <TResult, TTableDef extends TableDefBase>(
|
|
|
116
125
|
return makeQueryBuilder(tableDef, { ...ast, offset: Option.some(offset) })
|
|
117
126
|
},
|
|
118
127
|
count: () => {
|
|
119
|
-
if (isRowQuery(ast) || ast._tag === 'InsertQuery' || ast._tag === 'UpdateQuery' || ast._tag === 'DeleteQuery')
|
|
128
|
+
if (isRowQuery(ast) === true || ast._tag === 'InsertQuery' || ast._tag === 'UpdateQuery' || ast._tag === 'DeleteQuery')
|
|
120
129
|
return invalidQueryBuilder()
|
|
121
130
|
|
|
122
131
|
return makeQueryBuilder(tableDef, {
|
|
@@ -171,6 +180,7 @@ export const makeQueryBuilder = <TResult, TTableDef extends TableDefBase>(
|
|
|
171
180
|
insert: (values) => {
|
|
172
181
|
const filteredValues = Object.fromEntries(Object.entries(values).filter(([, value]) => value !== undefined))
|
|
173
182
|
|
|
183
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- query builder return type depends on AST state; consumer type safety enforced by api.ts
|
|
174
184
|
return makeQueryBuilder(tableDef, {
|
|
175
185
|
_tag: 'InsertQuery',
|
|
176
186
|
tableDef,
|
|
@@ -185,7 +195,7 @@ export const makeQueryBuilder = <TResult, TTableDef extends TableDefBase>(
|
|
|
185
195
|
action: 'ignore' | 'replace' | 'update',
|
|
186
196
|
updateValues?: Record<string, unknown>,
|
|
187
197
|
) => {
|
|
188
|
-
const targets = Array.isArray(targetOrTargets) ? targetOrTargets : [targetOrTargets]
|
|
198
|
+
const targets = Array.isArray(targetOrTargets) === true ? targetOrTargets : [targetOrTargets]
|
|
189
199
|
|
|
190
200
|
assertInsertQueryBuilderAst(ast)
|
|
191
201
|
|
|
@@ -199,6 +209,7 @@ export const makeQueryBuilder = <TResult, TTableDef extends TableDefBase>(
|
|
|
199
209
|
Match.exhaustive,
|
|
200
210
|
)
|
|
201
211
|
|
|
212
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- query builder return type depends on AST state; consumer type safety enforced by api.ts
|
|
202
213
|
return makeQueryBuilder(tableDef, {
|
|
203
214
|
...ast,
|
|
204
215
|
onConflict,
|
|
@@ -208,6 +219,7 @@ export const makeQueryBuilder = <TResult, TTableDef extends TableDefBase>(
|
|
|
208
219
|
returning: (...columns) => {
|
|
209
220
|
assertWriteQueryBuilderAst(ast)
|
|
210
221
|
|
|
222
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- query builder return type depends on AST state; consumer type safety enforced by api.ts
|
|
211
223
|
return makeQueryBuilder(tableDef, {
|
|
212
224
|
...ast,
|
|
213
225
|
returning: columns,
|
|
@@ -221,6 +233,7 @@ export const makeQueryBuilder = <TResult, TTableDef extends TableDefBase>(
|
|
|
221
233
|
// Preserve where clauses if coming from a SelectQuery
|
|
222
234
|
const whereClause = ast._tag === 'SelectQuery' ? ast.where : []
|
|
223
235
|
|
|
236
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- query builder return type depends on AST state; consumer type safety enforced by api.ts
|
|
224
237
|
return makeQueryBuilder(tableDef, {
|
|
225
238
|
_tag: 'UpdateQuery',
|
|
226
239
|
tableDef,
|
|
@@ -235,6 +248,7 @@ export const makeQueryBuilder = <TResult, TTableDef extends TableDefBase>(
|
|
|
235
248
|
// Preserve where clauses if coming from a SelectQuery
|
|
236
249
|
const whereClause = ast._tag === 'SelectQuery' ? ast.where : []
|
|
237
250
|
|
|
251
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- query builder return type depends on AST state; consumer type safety enforced by api.ts
|
|
238
252
|
return makeQueryBuilder(tableDef, {
|
|
239
253
|
_tag: 'DeleteQuery',
|
|
240
254
|
tableDef,
|
|
@@ -248,6 +262,7 @@ export const makeQueryBuilder = <TResult, TTableDef extends TableDefBase>(
|
|
|
248
262
|
return {
|
|
249
263
|
[QueryBuilderTypeId]: QueryBuilderTypeId,
|
|
250
264
|
[QueryBuilderAstSymbol]: ast,
|
|
265
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- phantom type field for generic inference only
|
|
251
266
|
ResultType: 'only-for-type-inference' as TResult,
|
|
252
267
|
asSql: () => astToSql(ast),
|
|
253
268
|
toString: () => {
|
|
@@ -277,19 +292,19 @@ const emptyAst = (tableDef: TableDefBase): QueryBuilderAst.SelectQuery => ({
|
|
|
277
292
|
|
|
278
293
|
// Helper functions
|
|
279
294
|
|
|
280
|
-
|
|
295
|
+
const assertSelectQueryBuilderAst: (ast: QueryBuilderAst) => asserts ast is QueryBuilderAst.SelectQuery = (ast) => {
|
|
281
296
|
if (ast._tag !== 'SelectQuery') {
|
|
282
297
|
return shouldNeverHappen(`Expected SelectQuery but got ${ast._tag}`)
|
|
283
298
|
}
|
|
284
299
|
}
|
|
285
300
|
|
|
286
|
-
|
|
301
|
+
const assertInsertQueryBuilderAst: (ast: QueryBuilderAst) => asserts ast is QueryBuilderAst.InsertQuery = (ast) => {
|
|
287
302
|
if (ast._tag !== 'InsertQuery') {
|
|
288
303
|
return shouldNeverHappen(`Expected InsertQuery but got ${ast._tag}`)
|
|
289
304
|
}
|
|
290
305
|
}
|
|
291
306
|
|
|
292
|
-
|
|
307
|
+
const assertWriteQueryBuilderAst: (ast: QueryBuilderAst) => asserts ast is QueryBuilderAst.WriteQuery = (ast) => {
|
|
293
308
|
if (ast._tag !== 'InsertQuery' && ast._tag !== 'UpdateQuery' && ast._tag !== 'DeleteQuery') {
|
|
294
309
|
return shouldNeverHappen(`Expected WriteQuery but got ${ast._tag}`)
|
|
295
310
|
}
|
|
@@ -298,7 +313,7 @@ function assertWriteQueryBuilderAst(ast: QueryBuilderAst): asserts ast is QueryB
|
|
|
298
313
|
const isRowQuery = (ast: QueryBuilderAst): ast is QueryBuilderAst.RowQuery => ast._tag === 'RowQuery'
|
|
299
314
|
|
|
300
315
|
export const invalidQueryBuilder = (msg?: string) => {
|
|
301
|
-
return shouldNeverHappen(`Invalid query builder${msg ? `: ${msg}` : ''}`)
|
|
316
|
+
return shouldNeverHappen(`Invalid query builder${msg !== undefined ? `: ${msg}` : ''}`)
|
|
302
317
|
}
|
|
303
318
|
|
|
304
319
|
export const getResultSchema = (qb: QueryBuilder<any, any, any>): Schema.Schema<any> => {
|
|
@@ -328,7 +343,7 @@ export const getResultSchema = (qb: QueryBuilder<any, any, any>): Schema.Schema<
|
|
|
328
343
|
case 'UpdateQuery':
|
|
329
344
|
case 'DeleteQuery': {
|
|
330
345
|
// For write operations with RETURNING clause, we need to return the appropriate schema
|
|
331
|
-
if (queryAst.returning && queryAst.returning.length > 0) {
|
|
346
|
+
if (queryAst.returning !== undefined && queryAst.returning.length > 0) {
|
|
332
347
|
// Create a schema for the returned columns
|
|
333
348
|
return queryAst.tableDef.rowSchema.pipe(Schema.pick(...queryAst.returning), Schema.Array)
|
|
334
349
|
}
|
|
@@ -344,8 +359,7 @@ export const getResultSchema = (qb: QueryBuilder<any, any, any>): Schema.Schema<
|
|
|
344
359
|
Schema.headOrElse(),
|
|
345
360
|
)
|
|
346
361
|
}
|
|
347
|
-
default:
|
|
348
|
-
casesHandled(queryAst)
|
|
349
|
-
}
|
|
362
|
+
default:
|
|
363
|
+
return casesHandled(queryAst)
|
|
350
364
|
}
|
|
351
365
|
}
|
|
@@ -13,7 +13,7 @@ export const getDefaultValuesEncoded = <TTableDef extends TableDefBase>(
|
|
|
13
13
|
ReadonlyRecord.filter((col, key) => {
|
|
14
14
|
if (fallbackValues?.[key] !== undefined) return true
|
|
15
15
|
if (key === 'id') return false
|
|
16
|
-
return col!.default._tag === 'None' || SqliteDsl.isSqlDefaultValue(col!.default.value)
|
|
16
|
+
return col!.default._tag === 'None' || !SqliteDsl.isSqlDefaultValue(col!.default.value)
|
|
17
17
|
}),
|
|
18
18
|
ReadonlyRecord.map((column, columnName) => {
|
|
19
19
|
if (fallbackValues?.[columnName] !== undefined) return fallbackValues[columnName]
|
|
@@ -39,7 +39,7 @@ export const getDefaultValuesDecoded = <TTableDef extends TableDefBase>(
|
|
|
39
39
|
ReadonlyRecord.filter((col, key) => {
|
|
40
40
|
if (fallbackValues?.[key] !== undefined) return true
|
|
41
41
|
if (key === 'id') return false
|
|
42
|
-
return col!.default._tag === 'None' || SqliteDsl.isSqlDefaultValue(col!.default.value)
|
|
42
|
+
return col!.default._tag === 'None' || !SqliteDsl.isSqlDefaultValue(col!.default.value)
|
|
43
43
|
}),
|
|
44
44
|
ReadonlyRecord.map((column, columnName) => {
|
|
45
45
|
if (fallbackValues?.[columnName] !== undefined) return fallbackValues[columnName]
|