@livestore/common 0.3.0-dev.27 → 0.3.0-dev.29
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/__tests__/fixture.d.ts +83 -221
- package/dist/__tests__/fixture.d.ts.map +1 -1
- package/dist/__tests__/fixture.js +33 -11
- package/dist/__tests__/fixture.js.map +1 -1
- package/dist/adapter-types.d.ts +22 -15
- package/dist/adapter-types.d.ts.map +1 -1
- package/dist/adapter-types.js +15 -2
- package/dist/adapter-types.js.map +1 -1
- package/dist/bounded-collections.d.ts +1 -1
- package/dist/bounded-collections.d.ts.map +1 -1
- package/dist/debug-info.d.ts.map +1 -1
- package/dist/debug-info.js +1 -0
- package/dist/debug-info.js.map +1 -1
- package/dist/devtools/devtools-messages-client-session.d.ts +21 -21
- package/dist/devtools/devtools-messages-common.d.ts +6 -6
- package/dist/devtools/devtools-messages-leader.d.ts +45 -45
- package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-leader.js +11 -11
- package/dist/devtools/devtools-messages-leader.js.map +1 -1
- package/dist/index.d.ts +2 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -5
- package/dist/index.js.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.d.ts +25 -12
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.js +125 -89
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
- package/dist/leader-thread/{apply-mutation.d.ts → apply-event.d.ts} +7 -7
- package/dist/leader-thread/apply-event.d.ts.map +1 -0
- package/dist/leader-thread/apply-event.js +103 -0
- package/dist/leader-thread/apply-event.js.map +1 -0
- package/dist/leader-thread/eventlog.d.ts +27 -0
- package/dist/leader-thread/eventlog.d.ts.map +1 -0
- package/dist/leader-thread/eventlog.js +123 -0
- package/dist/leader-thread/eventlog.js.map +1 -0
- package/dist/leader-thread/leader-worker-devtools.js +18 -18
- package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.d.ts +16 -4
- package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.js +23 -16
- package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
- package/dist/leader-thread/mod.d.ts +1 -1
- package/dist/leader-thread/mod.d.ts.map +1 -1
- package/dist/leader-thread/mod.js +1 -1
- package/dist/leader-thread/mod.js.map +1 -1
- package/dist/leader-thread/recreate-db.d.ts.map +1 -1
- package/dist/leader-thread/recreate-db.js +6 -8
- package/dist/leader-thread/recreate-db.js.map +1 -1
- package/dist/leader-thread/types.d.ts +11 -11
- package/dist/leader-thread/types.d.ts.map +1 -1
- package/dist/materializer-helper.d.ts +23 -0
- package/dist/materializer-helper.d.ts.map +1 -0
- package/dist/materializer-helper.js +70 -0
- package/dist/materializer-helper.js.map +1 -0
- package/dist/query-builder/api.d.ts +58 -53
- package/dist/query-builder/api.d.ts.map +1 -1
- package/dist/query-builder/api.js +3 -5
- package/dist/query-builder/api.js.map +1 -1
- package/dist/query-builder/astToSql.d.ts.map +1 -1
- package/dist/query-builder/astToSql.js +59 -37
- package/dist/query-builder/astToSql.js.map +1 -1
- package/dist/query-builder/impl.d.ts +2 -3
- package/dist/query-builder/impl.d.ts.map +1 -1
- package/dist/query-builder/impl.js +48 -46
- package/dist/query-builder/impl.js.map +1 -1
- package/dist/query-builder/impl.test.d.ts +86 -1
- package/dist/query-builder/impl.test.d.ts.map +1 -1
- package/dist/query-builder/impl.test.js +244 -36
- package/dist/query-builder/impl.test.js.map +1 -1
- package/dist/rehydrate-from-eventlog.d.ts +14 -0
- package/dist/rehydrate-from-eventlog.d.ts.map +1 -0
- package/dist/{rehydrate-from-mutationlog.js → rehydrate-from-eventlog.js} +25 -26
- package/dist/rehydrate-from-eventlog.js.map +1 -0
- package/dist/schema/EventDef.d.ts +136 -0
- package/dist/schema/EventDef.d.ts.map +1 -0
- package/dist/schema/EventDef.js +58 -0
- package/dist/schema/EventDef.js.map +1 -0
- package/dist/schema/EventId.d.ts +2 -2
- package/dist/schema/EventId.d.ts.map +1 -1
- package/dist/schema/EventId.js +8 -2
- package/dist/schema/EventId.js.map +1 -1
- package/dist/schema/{MutationEvent.d.ts → LiveStoreEvent.d.ts} +56 -56
- package/dist/schema/LiveStoreEvent.d.ts.map +1 -0
- package/dist/schema/{MutationEvent.js → LiveStoreEvent.js} +25 -25
- package/dist/schema/LiveStoreEvent.js.map +1 -0
- package/dist/schema/client-document-def.d.ts +223 -0
- package/dist/schema/client-document-def.d.ts.map +1 -0
- package/dist/schema/client-document-def.js +170 -0
- package/dist/schema/client-document-def.js.map +1 -0
- package/dist/schema/client-document-def.test.d.ts +2 -0
- package/dist/schema/client-document-def.test.d.ts.map +1 -0
- package/dist/schema/client-document-def.test.js +201 -0
- package/dist/schema/client-document-def.test.js.map +1 -0
- package/dist/schema/db-schema/dsl/mod.d.ts.map +1 -1
- package/dist/schema/events.d.ts +2 -0
- package/dist/schema/events.d.ts.map +1 -0
- package/dist/schema/events.js +2 -0
- package/dist/schema/events.js.map +1 -0
- package/dist/schema/mod.d.ts +4 -3
- package/dist/schema/mod.d.ts.map +1 -1
- package/dist/schema/mod.js +4 -3
- package/dist/schema/mod.js.map +1 -1
- package/dist/schema/schema.d.ts +27 -23
- package/dist/schema/schema.d.ts.map +1 -1
- package/dist/schema/schema.js +45 -43
- package/dist/schema/schema.js.map +1 -1
- package/dist/schema/sqlite-state.d.ts +12 -0
- package/dist/schema/sqlite-state.d.ts.map +1 -0
- package/dist/schema/sqlite-state.js +36 -0
- package/dist/schema/sqlite-state.js.map +1 -0
- package/dist/schema/system-tables.d.ts +67 -98
- package/dist/schema/system-tables.d.ts.map +1 -1
- package/dist/schema/system-tables.js +62 -48
- package/dist/schema/system-tables.js.map +1 -1
- package/dist/schema/table-def.d.ts +26 -96
- package/dist/schema/table-def.d.ts.map +1 -1
- package/dist/schema/table-def.js +16 -64
- package/dist/schema/table-def.js.map +1 -1
- package/dist/schema/view.d.ts +3 -0
- package/dist/schema/view.d.ts.map +1 -0
- package/dist/schema/view.js +3 -0
- package/dist/schema/view.js.map +1 -0
- package/dist/schema-management/common.d.ts +4 -4
- package/dist/schema-management/common.d.ts.map +1 -1
- package/dist/schema-management/migrations.d.ts.map +1 -1
- package/dist/schema-management/migrations.js +6 -6
- package/dist/schema-management/migrations.js.map +1 -1
- package/dist/schema-management/validate-mutation-defs.d.ts +3 -3
- package/dist/schema-management/validate-mutation-defs.d.ts.map +1 -1
- package/dist/schema-management/validate-mutation-defs.js +17 -17
- package/dist/schema-management/validate-mutation-defs.js.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.d.ts +7 -7
- package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.js +31 -30
- package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
- package/dist/sync/next/facts.d.ts +19 -19
- package/dist/sync/next/facts.d.ts.map +1 -1
- package/dist/sync/next/facts.js +2 -2
- package/dist/sync/next/facts.js.map +1 -1
- package/dist/sync/next/history-dag-common.d.ts +3 -3
- 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-common.js.map +1 -1
- package/dist/sync/next/history-dag.js +1 -1
- package/dist/sync/next/history-dag.js.map +1 -1
- package/dist/sync/next/rebase-events.d.ts +7 -7
- package/dist/sync/next/rebase-events.d.ts.map +1 -1
- package/dist/sync/next/rebase-events.js +5 -5
- package/dist/sync/next/rebase-events.js.map +1 -1
- package/dist/sync/next/test/compact-events.calculator.test.js +38 -33
- package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
- package/dist/sync/next/test/compact-events.test.js +71 -71
- package/dist/sync/next/test/compact-events.test.js.map +1 -1
- package/dist/sync/next/test/{mutation-fixtures.d.ts → event-fixtures.d.ts} +29 -29
- package/dist/sync/next/test/event-fixtures.d.ts.map +1 -0
- package/dist/sync/next/test/{mutation-fixtures.js → event-fixtures.js} +60 -25
- package/dist/sync/next/test/event-fixtures.js.map +1 -0
- package/dist/sync/next/test/mod.d.ts +1 -1
- package/dist/sync/next/test/mod.d.ts.map +1 -1
- package/dist/sync/next/test/mod.js +1 -1
- package/dist/sync/next/test/mod.js.map +1 -1
- package/dist/sync/sync.d.ts +3 -3
- package/dist/sync/sync.d.ts.map +1 -1
- package/dist/sync/syncstate.d.ts +32 -32
- package/dist/sync/syncstate.d.ts.map +1 -1
- package/dist/sync/syncstate.js +31 -25
- package/dist/sync/syncstate.js.map +1 -1
- package/dist/sync/syncstate.test.js +165 -175
- package/dist/sync/syncstate.test.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.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/src/__tests__/fixture.ts +36 -15
- package/src/adapter-types.ts +23 -16
- package/src/debug-info.ts +1 -0
- package/src/devtools/devtools-messages-leader.ts +13 -13
- package/src/index.ts +2 -5
- package/src/leader-thread/LeaderSyncProcessor.ts +183 -122
- package/src/leader-thread/{apply-mutation.ts → apply-event.ts} +50 -74
- package/src/leader-thread/eventlog.ts +199 -0
- package/src/leader-thread/leader-worker-devtools.ts +18 -18
- package/src/leader-thread/make-leader-thread-layer.ts +51 -29
- package/src/leader-thread/mod.ts +1 -1
- package/src/leader-thread/recreate-db.ts +6 -9
- package/src/leader-thread/types.ts +12 -12
- package/src/materializer-helper.ts +110 -0
- package/src/query-builder/api.ts +79 -105
- package/src/query-builder/astToSql.ts +68 -39
- package/src/query-builder/impl.test.ts +264 -42
- package/src/query-builder/impl.ts +72 -56
- package/src/{rehydrate-from-mutationlog.ts → rehydrate-from-eventlog.ts} +33 -40
- package/src/schema/EventDef.ts +216 -0
- package/src/schema/EventId.ts +11 -3
- package/src/schema/{MutationEvent.ts → LiveStoreEvent.ts} +68 -69
- package/src/schema/client-document-def.test.ts +239 -0
- package/src/schema/client-document-def.ts +444 -0
- package/src/schema/db-schema/dsl/mod.ts +0 -1
- package/src/schema/events.ts +1 -0
- package/src/schema/mod.ts +4 -3
- package/src/schema/schema.ts +79 -69
- package/src/schema/sqlite-state.ts +62 -0
- package/src/schema/system-tables.ts +42 -53
- package/src/schema/table-def.ts +53 -209
- package/src/schema/view.ts +2 -0
- package/src/schema-management/common.ts +4 -4
- package/src/schema-management/migrations.ts +8 -9
- package/src/schema-management/validate-mutation-defs.ts +22 -24
- package/src/sync/ClientSessionSyncProcessor.ts +37 -36
- package/src/sync/next/facts.ts +31 -32
- package/src/sync/next/history-dag-common.ts +4 -4
- package/src/sync/next/history-dag.ts +1 -1
- package/src/sync/next/rebase-events.ts +13 -13
- package/src/sync/next/test/compact-events.calculator.test.ts +45 -45
- package/src/sync/next/test/compact-events.test.ts +73 -73
- package/src/sync/next/test/event-fixtures.ts +219 -0
- package/src/sync/next/test/mod.ts +1 -1
- package/src/sync/sync.ts +3 -3
- package/src/sync/syncstate.test.ts +168 -179
- package/src/sync/syncstate.ts +48 -38
- package/src/sync/validate-push-payload.ts +2 -2
- package/src/version.ts +1 -1
- package/tmp/pack.tgz +0 -0
- package/tsconfig.json +1 -0
- package/dist/derived-mutations.d.ts +0 -109
- package/dist/derived-mutations.d.ts.map +0 -1
- package/dist/derived-mutations.js +0 -54
- package/dist/derived-mutations.js.map +0 -1
- package/dist/derived-mutations.test.d.ts +0 -2
- package/dist/derived-mutations.test.d.ts.map +0 -1
- package/dist/derived-mutations.test.js +0 -93
- package/dist/derived-mutations.test.js.map +0 -1
- package/dist/init-singleton-tables.d.ts +0 -4
- package/dist/init-singleton-tables.d.ts.map +0 -1
- package/dist/init-singleton-tables.js +0 -16
- package/dist/init-singleton-tables.js.map +0 -1
- package/dist/leader-thread/apply-mutation.d.ts.map +0 -1
- package/dist/leader-thread/apply-mutation.js +0 -122
- package/dist/leader-thread/apply-mutation.js.map +0 -1
- package/dist/leader-thread/mutationlog.d.ts +0 -27
- package/dist/leader-thread/mutationlog.d.ts.map +0 -1
- package/dist/leader-thread/mutationlog.js +0 -124
- package/dist/leader-thread/mutationlog.js.map +0 -1
- package/dist/leader-thread/pull-queue-set.d.ts +0 -7
- package/dist/leader-thread/pull-queue-set.d.ts.map +0 -1
- package/dist/leader-thread/pull-queue-set.js +0 -38
- package/dist/leader-thread/pull-queue-set.js.map +0 -1
- package/dist/mutation.d.ts +0 -20
- package/dist/mutation.d.ts.map +0 -1
- package/dist/mutation.js +0 -68
- package/dist/mutation.js.map +0 -1
- package/dist/query-info.d.ts +0 -41
- package/dist/query-info.d.ts.map +0 -1
- package/dist/query-info.js +0 -7
- package/dist/query-info.js.map +0 -1
- package/dist/rehydrate-from-mutationlog.d.ts +0 -15
- package/dist/rehydrate-from-mutationlog.d.ts.map +0 -1
- package/dist/rehydrate-from-mutationlog.js.map +0 -1
- package/dist/schema/MutationEvent.d.ts.map +0 -1
- package/dist/schema/MutationEvent.js.map +0 -1
- package/dist/schema/mutations.d.ts +0 -115
- package/dist/schema/mutations.d.ts.map +0 -1
- package/dist/schema/mutations.js +0 -42
- package/dist/schema/mutations.js.map +0 -1
- package/dist/sync/next/test/mutation-fixtures.d.ts.map +0 -1
- package/dist/sync/next/test/mutation-fixtures.js.map +0 -1
- package/src/derived-mutations.test.ts +0 -101
- package/src/derived-mutations.ts +0 -170
- package/src/init-singleton-tables.ts +0 -24
- package/src/leader-thread/mutationlog.ts +0 -202
- package/src/mutation.ts +0 -108
- package/src/query-info.ts +0 -83
- package/src/schema/mutations.ts +0 -193
- package/src/sync/next/test/mutation-fixtures.ts +0 -228
package/src/query-builder/api.ts
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
import type { GetValForKey } from '@livestore/utils'
|
1
|
+
import type { GetValForKey, SingleOrReadonlyArray } from '@livestore/utils'
|
2
2
|
import { type Option, Predicate, type Schema } from '@livestore/utils/effect'
|
3
3
|
|
4
4
|
import type { SessionIdSymbol } from '../adapter-types.js'
|
5
|
-
import type {
|
5
|
+
import type { ClientDocumentTableDef } from '../schema/client-document-def.js'
|
6
6
|
import type { SqliteDsl } from '../schema/db-schema/mod.js'
|
7
|
-
import type {
|
7
|
+
import type { State } from '../schema/mod.js'
|
8
8
|
import type { SqlValue } from '../util.js'
|
9
9
|
|
10
10
|
export type QueryBuilderAst =
|
@@ -26,28 +26,28 @@ export namespace QueryBuilderAst {
|
|
26
26
|
readonly orderBy: ReadonlyArray<OrderBy>
|
27
27
|
readonly offset: Option.Option<number>
|
28
28
|
readonly limit: Option.Option<number>
|
29
|
-
readonly tableDef:
|
29
|
+
readonly tableDef: State.SQLite.TableDefBase
|
30
30
|
readonly where: ReadonlyArray<QueryBuilderAst.Where>
|
31
31
|
readonly resultSchemaSingle: Schema.Schema<any>
|
32
32
|
}
|
33
33
|
|
34
34
|
export interface CountQuery {
|
35
35
|
readonly _tag: 'CountQuery'
|
36
|
-
readonly tableDef:
|
36
|
+
readonly tableDef: State.SQLite.TableDefBase
|
37
37
|
readonly where: ReadonlyArray<QueryBuilderAst.Where>
|
38
38
|
readonly resultSchema: Schema.Schema<number, ReadonlyArray<{ count: number }>>
|
39
39
|
}
|
40
40
|
|
41
41
|
export interface RowQuery {
|
42
42
|
readonly _tag: 'RowQuery'
|
43
|
-
readonly tableDef:
|
44
|
-
readonly id: string | SessionIdSymbol
|
45
|
-
readonly
|
43
|
+
readonly tableDef: State.SQLite.ClientDocumentTableDef.Any
|
44
|
+
readonly id: string | SessionIdSymbol
|
45
|
+
readonly explicitDefaultValues: Record<string, unknown>
|
46
46
|
}
|
47
47
|
|
48
48
|
export interface InsertQuery {
|
49
49
|
readonly _tag: 'InsertQuery'
|
50
|
-
readonly tableDef:
|
50
|
+
readonly tableDef: State.SQLite.TableDefBase
|
51
51
|
readonly values: Record<string, unknown>
|
52
52
|
readonly onConflict: OnConflict | undefined
|
53
53
|
readonly returning: string[] | undefined
|
@@ -56,7 +56,7 @@ export namespace QueryBuilderAst {
|
|
56
56
|
|
57
57
|
export interface OnConflict {
|
58
58
|
/** Conflicting column name */
|
59
|
-
readonly
|
59
|
+
readonly targets: string[]
|
60
60
|
readonly action:
|
61
61
|
| { readonly _tag: 'ignore' }
|
62
62
|
| { readonly _tag: 'replace' }
|
@@ -68,7 +68,7 @@ export namespace QueryBuilderAst {
|
|
68
68
|
|
69
69
|
export interface UpdateQuery {
|
70
70
|
readonly _tag: 'UpdateQuery'
|
71
|
-
readonly tableDef:
|
71
|
+
readonly tableDef: State.SQLite.TableDefBase
|
72
72
|
readonly values: Record<string, unknown>
|
73
73
|
readonly where: ReadonlyArray<QueryBuilderAst.Where>
|
74
74
|
readonly returning: string[] | undefined
|
@@ -77,7 +77,7 @@ export namespace QueryBuilderAst {
|
|
77
77
|
|
78
78
|
export interface DeleteQuery {
|
79
79
|
readonly _tag: 'DeleteQuery'
|
80
|
-
readonly tableDef:
|
80
|
+
readonly tableDef: State.SQLite.TableDefBase
|
81
81
|
readonly where: ReadonlyArray<QueryBuilderAst.Where>
|
82
82
|
readonly returning: string[] | undefined
|
83
83
|
readonly resultSchema: Schema.Schema<any>
|
@@ -99,27 +99,31 @@ export namespace QueryBuilderAst {
|
|
99
99
|
|
100
100
|
export const QueryBuilderAstSymbol = Symbol.for('QueryBuilderAst')
|
101
101
|
export type QueryBuilderAstSymbol = typeof QueryBuilderAstSymbol
|
102
|
-
|
103
|
-
export
|
102
|
+
|
103
|
+
export const QueryBuilderResultSymbol = Symbol.for('QueryBuilderResult')
|
104
|
+
export type QueryBuilderResultSymbol = typeof QueryBuilderResultSymbol
|
105
|
+
|
106
|
+
export const QueryBuilderTypeId = Symbol.for('QueryBuilder')
|
107
|
+
export type QueryBuilderTypeId = typeof QueryBuilderTypeId
|
104
108
|
|
105
109
|
export const isQueryBuilder = (value: unknown): value is QueryBuilder<any, any, any> =>
|
106
|
-
Predicate.hasProperty(value,
|
110
|
+
Predicate.hasProperty(value, QueryBuilderTypeId)
|
107
111
|
|
108
112
|
export type QueryBuilder<
|
109
113
|
TResult,
|
110
|
-
TTableDef extends
|
114
|
+
TTableDef extends State.SQLite.TableDefBase,
|
111
115
|
/** Used to gradually remove features from the API based on the query context */
|
112
116
|
TWithout extends QueryBuilder.ApiFeature = never,
|
113
|
-
TQueryInfo extends QueryInfo = QueryInfo.None,
|
114
117
|
> = {
|
115
|
-
readonly [
|
118
|
+
readonly [QueryBuilderTypeId]: QueryBuilderTypeId
|
116
119
|
readonly [QueryBuilderAstSymbol]: QueryBuilderAst
|
120
|
+
readonly ['ResultType']: TResult
|
117
121
|
readonly asSql: () => { query: string; bindValues: SqlValue[] }
|
118
122
|
readonly toString: () => string
|
119
|
-
} & Omit<QueryBuilder.ApiFull<TResult, TTableDef, TWithout
|
123
|
+
} & Omit<QueryBuilder.ApiFull<TResult, TTableDef, TWithout>, TWithout>
|
120
124
|
|
121
125
|
export namespace QueryBuilder {
|
122
|
-
export type Any = QueryBuilder<any, any, any
|
126
|
+
export type Any = QueryBuilder<any, any, any>
|
123
127
|
export type WhereOps = WhereOps.Equality | WhereOps.Order | WhereOps.Like | WhereOps.In
|
124
128
|
|
125
129
|
export namespace WhereOps {
|
@@ -147,7 +151,7 @@ export namespace QueryBuilder {
|
|
147
151
|
| 'returning'
|
148
152
|
| 'onConflict'
|
149
153
|
|
150
|
-
export type WhereParams<TTableDef extends
|
154
|
+
export type WhereParams<TTableDef extends State.SQLite.TableDefBase> = Partial<{
|
151
155
|
[K in keyof TTableDef['sqliteDef']['columns']]:
|
152
156
|
| TTableDef['sqliteDef']['columns'][K]['schema']['Type']
|
153
157
|
| { op: QueryBuilder.WhereOps.SingleValue; value: TTableDef['sqliteDef']['columns'][K]['schema']['Type'] }
|
@@ -158,40 +162,31 @@ export namespace QueryBuilder {
|
|
158
162
|
| undefined
|
159
163
|
}>
|
160
164
|
|
161
|
-
export type OrderByParams<TTableDef extends
|
165
|
+
export type OrderByParams<TTableDef extends State.SQLite.TableDefBase> = ReadonlyArray<{
|
162
166
|
col: keyof TTableDef['sqliteDef']['columns'] & string
|
163
167
|
direction: 'asc' | 'desc'
|
164
168
|
}>
|
165
169
|
|
166
|
-
export type ApiFull<
|
167
|
-
TResult,
|
168
|
-
TTableDef extends DbSchema.TableDefBase,
|
169
|
-
TWithout extends ApiFeature,
|
170
|
-
TQueryInfo extends QueryInfo,
|
171
|
-
> = {
|
170
|
+
export type ApiFull<TResult, TTableDef extends State.SQLite.TableDefBase, TWithout extends ApiFeature> = {
|
172
171
|
/**
|
173
172
|
* `SELECT *` is the default
|
174
173
|
*
|
175
174
|
* Example:
|
176
175
|
* ```ts
|
177
176
|
* db.todos.select('id', 'text', 'completed')
|
178
|
-
* db.todos.select('id'
|
177
|
+
* db.todos.select('id')
|
179
178
|
* ```
|
180
179
|
*/
|
181
180
|
readonly select: {
|
182
|
-
|
183
|
-
|
184
|
-
|
181
|
+
/** Selects and plucks a single column */
|
182
|
+
<TColumn extends keyof TTableDef['sqliteDef']['columns'] & string>(
|
183
|
+
pluckColumn: TColumn,
|
185
184
|
): QueryBuilder<
|
186
|
-
|
187
|
-
? ReadonlyArray<TTableDef['sqliteDef']['columns'][TColumn]['schema']['Type']>
|
188
|
-
: ReadonlyArray<{
|
189
|
-
readonly [K in TColumn]: TTableDef['sqliteDef']['columns'][K]['schema']['Type']
|
190
|
-
}>,
|
185
|
+
ReadonlyArray<TTableDef['sqliteDef']['columns'][TColumn]['schema']['Type']>,
|
191
186
|
TTableDef,
|
192
|
-
TWithout | 'row' | 'select' | 'returning' | 'onConflict'
|
193
|
-
TQueryInfo
|
187
|
+
TWithout | 'row' | 'select' | 'returning' | 'onConflict'
|
194
188
|
>
|
189
|
+
/** Select multiple columns */
|
195
190
|
<TColumns extends keyof TTableDef['sqliteDef']['columns'] & string>(
|
196
191
|
...columns: TColumns[]
|
197
192
|
// TODO also support arbitrary SQL selects
|
@@ -201,8 +196,7 @@ export namespace QueryBuilder {
|
|
201
196
|
readonly [K in TColumns]: TTableDef['sqliteDef']['columns'][K]['schema']['Type']
|
202
197
|
}>,
|
203
198
|
TTableDef,
|
204
|
-
TWithout | 'row' | 'select' | 'count' | 'returning' | 'onConflict'
|
205
|
-
TQueryInfo
|
199
|
+
TWithout | 'row' | 'select' | 'count' | 'returning' | 'onConflict'
|
206
200
|
>
|
207
201
|
}
|
208
202
|
|
@@ -222,18 +216,16 @@ export namespace QueryBuilder {
|
|
222
216
|
* TODO: Also support `OR`
|
223
217
|
*/
|
224
218
|
readonly where: {
|
225
|
-
|
226
|
-
params: TParams,
|
227
|
-
): QueryBuilder<TResult, TTableDef, TWithout | 'row' | 'select', TQueryInfo>
|
219
|
+
(params: QueryBuilder.WhereParams<TTableDef>): QueryBuilder<TResult, TTableDef, TWithout | 'row' | 'select'>
|
228
220
|
<TColName extends keyof TTableDef['sqliteDef']['columns']>(
|
229
221
|
col: TColName,
|
230
222
|
value: TTableDef['sqliteDef']['columns'][TColName]['schema']['Type'],
|
231
|
-
): QueryBuilder<TResult, TTableDef, TWithout | 'row' | 'select'
|
223
|
+
): QueryBuilder<TResult, TTableDef, TWithout | 'row' | 'select'>
|
232
224
|
<TColName extends keyof TTableDef['sqliteDef']['columns']>(
|
233
225
|
col: TColName,
|
234
226
|
op: QueryBuilder.WhereOps,
|
235
227
|
value: TTableDef['sqliteDef']['columns'][TColName]['schema']['Type'],
|
236
|
-
): QueryBuilder<TResult, TTableDef, TWithout | 'row' | 'select'
|
228
|
+
): QueryBuilder<TResult, TTableDef, TWithout | 'row' | 'select'>
|
237
229
|
}
|
238
230
|
|
239
231
|
/**
|
@@ -246,8 +238,7 @@ export namespace QueryBuilder {
|
|
246
238
|
readonly count: () => QueryBuilder<
|
247
239
|
number,
|
248
240
|
TTableDef,
|
249
|
-
TWithout | 'row' | 'count' | 'select' | 'orderBy' | 'first' | 'offset' | 'limit' | 'returning' | 'onConflict'
|
250
|
-
TQueryInfo
|
241
|
+
TWithout | 'row' | 'count' | 'select' | 'orderBy' | 'first' | 'offset' | 'limit' | 'returning' | 'onConflict'
|
251
242
|
>
|
252
243
|
|
253
244
|
/**
|
@@ -260,10 +251,10 @@ export namespace QueryBuilder {
|
|
260
251
|
<TColName extends keyof TTableDef['sqliteDef']['columns'] & string>(
|
261
252
|
col: TColName,
|
262
253
|
direction: 'asc' | 'desc',
|
263
|
-
): QueryBuilder<TResult, TTableDef, TWithout | 'returning' | 'onConflict'
|
254
|
+
): QueryBuilder<TResult, TTableDef, TWithout | 'returning' | 'onConflict'>
|
264
255
|
<TParams extends QueryBuilder.OrderByParams<TTableDef>>(
|
265
256
|
params: TParams,
|
266
|
-
): QueryBuilder<TResult, TTableDef, TWithout | 'returning' | 'onConflict'
|
257
|
+
): QueryBuilder<TResult, TTableDef, TWithout | 'returning' | 'onConflict'>
|
267
258
|
}
|
268
259
|
|
269
260
|
/**
|
@@ -274,12 +265,7 @@ export namespace QueryBuilder {
|
|
274
265
|
*/
|
275
266
|
readonly offset: (
|
276
267
|
offset: number,
|
277
|
-
) => QueryBuilder<
|
278
|
-
TResult,
|
279
|
-
TTableDef,
|
280
|
-
TWithout | 'row' | 'offset' | 'orderBy' | 'returning' | 'onConflict',
|
281
|
-
TQueryInfo
|
282
|
-
>
|
268
|
+
) => QueryBuilder<TResult, TTableDef, TWithout | 'row' | 'offset' | 'orderBy' | 'returning' | 'onConflict'>
|
283
269
|
|
284
270
|
/**
|
285
271
|
* Example:
|
@@ -292,42 +278,26 @@ export namespace QueryBuilder {
|
|
292
278
|
) => QueryBuilder<
|
293
279
|
TResult,
|
294
280
|
TTableDef,
|
295
|
-
TWithout | 'row' | 'limit' | 'offset' | 'first' | 'orderBy' | 'returning' | 'onConflict'
|
296
|
-
TQueryInfo
|
281
|
+
TWithout | 'row' | 'limit' | 'offset' | 'first' | 'orderBy' | 'returning' | 'onConflict'
|
297
282
|
>
|
298
283
|
|
299
284
|
/**
|
300
285
|
* Example:
|
301
286
|
* ```ts
|
302
287
|
* db.todos.first()
|
288
|
+
* db.todos.where('id', '123').first()
|
303
289
|
* ```
|
290
|
+
*
|
291
|
+
* Query will fail if no rows are returned and no fallback is provided.
|
304
292
|
*/
|
305
|
-
readonly first: <TFallback
|
306
|
-
fallback?: () => TFallback
|
293
|
+
readonly first: <TFallback = never>(options?: {
|
294
|
+
fallback?: () => TFallback | GetSingle<TResult>
|
307
295
|
}) => QueryBuilder<
|
308
296
|
TFallback | GetSingle<TResult>,
|
309
297
|
TTableDef,
|
310
|
-
TWithout | 'row' | 'first' | 'orderBy' | 'select' | 'limit' | 'offset' | 'where' | 'returning' | 'onConflict'
|
311
|
-
TQueryInfo
|
298
|
+
TWithout | 'row' | 'first' | 'orderBy' | 'select' | 'limit' | 'offset' | 'where' | 'returning' | 'onConflict'
|
312
299
|
>
|
313
300
|
|
314
|
-
/**
|
315
|
-
* Gets a single row from the table and will create it if it doesn't exist yet.
|
316
|
-
*/
|
317
|
-
// TODO maybe call `getsert`?
|
318
|
-
readonly row: TTableDef['options']['isSingleton'] extends true
|
319
|
-
? () => QueryBuilder<RowQuery.Result<TTableDef>, TTableDef, QueryBuilder.ApiFeature, QueryInfo.Row>
|
320
|
-
: TTableDef['options']['deriveMutations']['enabled'] extends false
|
321
|
-
? (_: 'Error: Need to enable deriveMutations to use row()') => any
|
322
|
-
: TTableDef['options']['requiredInsertColumnNames'] extends never
|
323
|
-
? (
|
324
|
-
id: string | SessionIdSymbol | number,
|
325
|
-
) => QueryBuilder<RowQuery.Result<TTableDef>, TTableDef, QueryBuilder.ApiFeature, QueryInfo.Row>
|
326
|
-
: <TOptions extends RowQuery.RequiredColumnsOptions<TTableDef>>(
|
327
|
-
id: string | SessionIdSymbol | number,
|
328
|
-
opts: TOptions,
|
329
|
-
) => QueryBuilder<RowQuery.Result<TTableDef>, TTableDef, QueryBuilder.ApiFeature, QueryInfo.Row>
|
330
|
-
|
331
301
|
/**
|
332
302
|
* Insert a new row into the table
|
333
303
|
*
|
@@ -341,8 +311,7 @@ export namespace QueryBuilder {
|
|
341
311
|
) => QueryBuilder<
|
342
312
|
TResult,
|
343
313
|
TTableDef,
|
344
|
-
TWithout | 'row' | 'select' | 'count' | 'orderBy' | 'first' | 'offset' | 'limit' | 'where'
|
345
|
-
QueryInfo.Write
|
314
|
+
TWithout | 'row' | 'select' | 'count' | 'orderBy' | 'first' | 'offset' | 'limit' | 'where'
|
346
315
|
>
|
347
316
|
|
348
317
|
/**
|
@@ -364,24 +333,22 @@ export namespace QueryBuilder {
|
|
364
333
|
* NOTE This API doesn't yet support composite primary keys.
|
365
334
|
*/
|
366
335
|
readonly onConflict: {
|
367
|
-
(
|
368
|
-
target:
|
336
|
+
<TTarget extends SingleOrReadonlyArray<keyof TTableDef['sqliteDef']['columns']>>(
|
337
|
+
target: TTarget,
|
369
338
|
action: 'ignore' | 'replace',
|
370
339
|
): QueryBuilder<
|
371
340
|
TResult,
|
372
341
|
TTableDef,
|
373
|
-
TWithout | 'row' | 'select' | 'count' | 'orderBy' | 'first' | 'offset' | 'limit' | 'where'
|
374
|
-
TQueryInfo
|
342
|
+
TWithout | 'row' | 'select' | 'count' | 'orderBy' | 'first' | 'offset' | 'limit' | 'where'
|
375
343
|
>
|
376
|
-
<TTarget extends keyof TTableDef['sqliteDef']['columns']
|
344
|
+
<TTarget extends SingleOrReadonlyArray<keyof TTableDef['sqliteDef']['columns']>>(
|
377
345
|
target: TTarget,
|
378
346
|
action: 'update',
|
379
|
-
updateValues: Partial<TTableDef['
|
347
|
+
updateValues: Partial<TTableDef['rowSchema']['Type']>,
|
380
348
|
): QueryBuilder<
|
381
349
|
TResult,
|
382
350
|
TTableDef,
|
383
|
-
TWithout | 'row' | 'select' | 'count' | 'orderBy' | 'first' | 'offset' | 'limit' | 'where'
|
384
|
-
TQueryInfo
|
351
|
+
TWithout | 'row' | 'select' | 'count' | 'orderBy' | 'first' | 'offset' | 'limit' | 'where'
|
385
352
|
>
|
386
353
|
}
|
387
354
|
|
@@ -411,12 +378,11 @@ export namespace QueryBuilder {
|
|
411
378
|
* ```
|
412
379
|
*/
|
413
380
|
readonly update: (
|
414
|
-
values: Partial<TTableDef['
|
381
|
+
values: Partial<TTableDef['rowSchema']['Type']>,
|
415
382
|
) => QueryBuilder<
|
416
383
|
TResult,
|
417
384
|
TTableDef,
|
418
|
-
TWithout | 'row' | 'select' | 'count' | 'orderBy' | 'first' | 'offset' | 'limit' | 'onConflict'
|
419
|
-
QueryInfo.Write
|
385
|
+
TWithout | 'row' | 'select' | 'count' | 'orderBy' | 'first' | 'offset' | 'limit' | 'onConflict'
|
420
386
|
>
|
421
387
|
|
422
388
|
/**
|
@@ -432,35 +398,43 @@ export namespace QueryBuilder {
|
|
432
398
|
readonly delete: () => QueryBuilder<
|
433
399
|
TResult,
|
434
400
|
TTableDef,
|
435
|
-
TWithout | 'row' | 'select' | 'count' | 'orderBy' | 'first' | 'offset' | 'limit' | 'onConflict'
|
436
|
-
QueryInfo.Write
|
401
|
+
TWithout | 'row' | 'select' | 'count' | 'orderBy' | 'first' | 'offset' | 'limit' | 'onConflict'
|
437
402
|
>
|
438
403
|
}
|
439
404
|
}
|
440
405
|
|
441
406
|
export namespace RowQuery {
|
442
|
-
export type
|
407
|
+
export type GetOrCreateOptions<TTableDef extends ClientDocumentTableDef.TraitAny> = {
|
408
|
+
default: Partial<TTableDef['Value']>
|
409
|
+
}
|
410
|
+
|
411
|
+
// TODO get rid of this
|
412
|
+
export type RequiredColumnsOptions<TTableDef extends State.SQLite.TableDefBase> = {
|
443
413
|
/**
|
444
414
|
* Values to be inserted into the row if it doesn't exist yet
|
445
415
|
*/
|
446
|
-
|
416
|
+
explicitDefaultValues: Pick<
|
447
417
|
SqliteDsl.FromColumns.RowDecodedAll<TTableDef['sqliteDef']['columns']>,
|
448
418
|
SqliteDsl.FromColumns.RequiredInsertColumnNames<Omit<TTableDef['sqliteDef']['columns'], 'id'>>
|
449
419
|
>
|
450
420
|
}
|
451
421
|
|
452
|
-
export type Result<TTableDef extends
|
453
|
-
|
454
|
-
|
422
|
+
export type Result<TTableDef extends State.SQLite.TableDefBase> = SqliteDsl.FromColumns.RowDecoded<
|
423
|
+
TTableDef['sqliteDef']['columns']
|
424
|
+
>
|
425
|
+
|
426
|
+
export type DocumentResult<TTableDef extends ClientDocumentTableDef.Any> = GetValForKey<
|
427
|
+
SqliteDsl.FromColumns.RowDecoded<TTableDef['sqliteDef']['columns']>,
|
428
|
+
'value'
|
429
|
+
>
|
455
430
|
|
456
|
-
export type ResultEncoded<TTableDef extends
|
457
|
-
TTableDef['options']['
|
431
|
+
export type ResultEncoded<TTableDef extends State.SQLite.TableDefBase> =
|
432
|
+
TTableDef['options']['isClientDocumentTable'] extends true
|
458
433
|
? GetValForKey<SqliteDsl.FromColumns.RowEncoded<TTableDef['sqliteDef']['columns']>, 'value'>
|
459
434
|
: SqliteDsl.FromColumns.RowEncoded<TTableDef['sqliteDef']['columns']>
|
435
|
+
|
436
|
+
export type GetIdColumnType<TTableDef extends State.SQLite.TableDefBase> =
|
437
|
+
TTableDef['sqliteDef']['columns']['id']['schema']['Type']
|
460
438
|
}
|
461
439
|
|
462
440
|
type GetSingle<T> = T extends ReadonlyArray<infer U> ? U : never
|
463
|
-
|
464
|
-
// export type QueryBuilderParamRef = { _tag: 'QueryBuilderParamRef' }
|
465
|
-
// export type QueryBuilderSelectParams = { [key: string]: QueryBuilderSelectParam }
|
466
|
-
// export type QueryBuilderSelectParam = boolean | ((ref: QueryBuilderParamRef) => QueryBuilder<any, any>)
|
@@ -2,14 +2,14 @@ import { shouldNeverHappen } from '@livestore/utils'
|
|
2
2
|
import { Schema } from '@livestore/utils/effect'
|
3
3
|
|
4
4
|
import { SessionIdSymbol } from '../adapter-types.js'
|
5
|
-
import type {
|
5
|
+
import type { State } from '../schema/mod.js'
|
6
6
|
import type { SqlValue } from '../util.js'
|
7
7
|
import type { QueryBuilderAst } from './api.js'
|
8
8
|
|
9
9
|
// Helper functions for SQL generation
|
10
10
|
const formatWhereClause = (
|
11
11
|
whereConditions: ReadonlyArray<QueryBuilderAst.Where>,
|
12
|
-
tableDef:
|
12
|
+
tableDef: State.SQLite.TableDefBase,
|
13
13
|
bindValues: SqlValue[],
|
14
14
|
): string => {
|
15
15
|
if (whereConditions.length === 0) return ''
|
@@ -72,52 +72,67 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
|
|
72
72
|
if (ast._tag === 'InsertQuery') {
|
73
73
|
const columns = Object.keys(ast.values)
|
74
74
|
const placeholders = columns.map(() => '?').join(', ')
|
75
|
-
const
|
75
|
+
const encodedValues = Schema.encodeSync(ast.tableDef.insertSchema)(ast.values)
|
76
76
|
|
77
|
-
|
77
|
+
// Ensure bind values are added in the same order as columns
|
78
|
+
columns.forEach((col) => {
|
79
|
+
bindValues.push(encodedValues[col] as SqlValue)
|
80
|
+
})
|
78
81
|
|
79
|
-
let
|
82
|
+
let insertVerb = 'INSERT'
|
83
|
+
let conflictClause = '' // Store the ON CONFLICT clause separately
|
80
84
|
|
81
85
|
// Handle ON CONFLICT clause
|
82
86
|
if (ast.onConflict) {
|
83
|
-
|
84
|
-
if (ast.onConflict.action._tag === '
|
85
|
-
|
86
|
-
|
87
|
-
query += 'DO REPLACE'
|
87
|
+
// Handle REPLACE specifically as it changes the INSERT verb
|
88
|
+
if (ast.onConflict.action._tag === 'replace') {
|
89
|
+
insertVerb = 'INSERT OR REPLACE'
|
90
|
+
// For REPLACE, the conflict target is implied and no further clause is needed
|
88
91
|
} else {
|
89
|
-
//
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
92
|
+
// Build the ON CONFLICT clause for IGNORE or UPDATE
|
93
|
+
conflictClause = ` ON CONFLICT (${ast.onConflict.targets.join(', ')}) `
|
94
|
+
if (ast.onConflict.action._tag === 'ignore') {
|
95
|
+
conflictClause += 'DO NOTHING'
|
96
|
+
} else {
|
97
|
+
// Handle the update record case
|
98
|
+
const updateValues = ast.onConflict.action.update
|
99
|
+
const updateCols = Object.keys(updateValues)
|
100
|
+
if (updateCols.length === 0) {
|
101
|
+
throw new Error('No update columns provided for ON CONFLICT DO UPDATE')
|
102
|
+
}
|
95
103
|
|
96
|
-
|
97
|
-
|
104
|
+
const updates = updateCols
|
105
|
+
.map((col) => {
|
106
|
+
const value = updateValues[col]
|
107
|
+
// If the value is undefined, use excluded.col
|
108
|
+
return value === undefined ? `${col} = excluded.${col}` : `${col} = ?`
|
109
|
+
})
|
110
|
+
.join(', ')
|
111
|
+
|
112
|
+
// Add values for the parameters
|
113
|
+
updateCols.forEach((col) => {
|
98
114
|
const value = updateValues[col]
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
const value = updateValues[col]
|
107
|
-
if (value !== undefined) {
|
108
|
-
const colDef = ast.tableDef.sqliteDef.columns[col]
|
109
|
-
if (colDef === undefined) {
|
110
|
-
throw new Error(`Column ${col} not found`)
|
115
|
+
if (value !== undefined) {
|
116
|
+
const colDef = ast.tableDef.sqliteDef.columns[col]
|
117
|
+
if (colDef === undefined) {
|
118
|
+
throw new Error(`Column ${col} not found`)
|
119
|
+
}
|
120
|
+
const encodedValue = Schema.encodeSync(colDef.schema)(value)
|
121
|
+
bindValues.push(encodedValue as SqlValue)
|
111
122
|
}
|
112
|
-
|
113
|
-
bindValues.push(encodedValue as SqlValue)
|
114
|
-
}
|
115
|
-
})
|
123
|
+
})
|
116
124
|
|
117
|
-
|
125
|
+
conflictClause += `DO UPDATE SET ${updates}`
|
126
|
+
}
|
118
127
|
}
|
119
128
|
}
|
120
129
|
|
130
|
+
// Construct the main query part
|
131
|
+
let query = `${insertVerb} INTO '${ast.tableDef.sqliteDef.name}' (${columns.join(', ')}) VALUES (${placeholders})`
|
132
|
+
|
133
|
+
// Append the conflict clause if it was generated (i.e., not for REPLACE)
|
134
|
+
query += conflictClause
|
135
|
+
|
121
136
|
query += formatReturningClause(ast.returning)
|
122
137
|
return { query, bindValues }
|
123
138
|
}
|
@@ -125,8 +140,21 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
|
|
125
140
|
// UPDATE query
|
126
141
|
if (ast._tag === 'UpdateQuery') {
|
127
142
|
const setColumns = Object.keys(ast.values)
|
128
|
-
|
129
|
-
|
143
|
+
|
144
|
+
if (setColumns.length === 0) {
|
145
|
+
console.warn(
|
146
|
+
`UPDATE query requires at least one column to set (for table ${ast.tableDef.sqliteDef.name}). Running no-op query instead to skip this update query.`,
|
147
|
+
)
|
148
|
+
return { query: 'SELECT 1', bindValues: [] }
|
149
|
+
// return shouldNeverHappen('UPDATE query requires at least one column to set.')
|
150
|
+
}
|
151
|
+
|
152
|
+
const encodedValues = Schema.encodeSync(Schema.partial(ast.tableDef.rowSchema))(ast.values)
|
153
|
+
|
154
|
+
// Ensure bind values are added in the same order as columns
|
155
|
+
setColumns.forEach((col) => {
|
156
|
+
bindValues.push(encodedValues[col] as SqlValue)
|
157
|
+
})
|
130
158
|
|
131
159
|
let query = `UPDATE '${ast.tableDef.sqliteDef.name}' SET ${setColumns.map((col) => `${col} = ?`).join(', ')}`
|
132
160
|
|
@@ -189,10 +217,11 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
|
|
189
217
|
: ''
|
190
218
|
|
191
219
|
const limitStmt = ast.limit._tag === 'Some' ? `LIMIT ?` : ''
|
192
|
-
if (ast.limit._tag === 'Some') bindValues.push(ast.limit.value)
|
193
|
-
|
194
220
|
const offsetStmt = ast.offset._tag === 'Some' ? `OFFSET ?` : ''
|
221
|
+
|
222
|
+
// Push offset and limit values in the correct order matching the query string
|
195
223
|
if (ast.offset._tag === 'Some') bindValues.push(ast.offset.value)
|
224
|
+
if (ast.limit._tag === 'Some') bindValues.push(ast.limit.value)
|
196
225
|
|
197
226
|
const query = [selectStmt, fromStmt, whereStmt, orderByStmt, offsetStmt, limitStmt]
|
198
227
|
.map((clause) => clause.trim())
|