@livestore/livestore 0.0.47 → 0.0.48-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.
Files changed (123) hide show
  1. package/README.md +3 -1
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/MainDatabaseWrapper.d.ts +2 -2
  4. package/dist/MainDatabaseWrapper.d.ts.map +1 -1
  5. package/dist/MainDatabaseWrapper.js.map +1 -1
  6. package/dist/__tests__/react/fixture.d.ts +262 -158
  7. package/dist/__tests__/react/fixture.d.ts.map +1 -1
  8. package/dist/__tests__/react/fixture.js +14 -12
  9. package/dist/__tests__/react/fixture.js.map +1 -1
  10. package/dist/__tests__/react/utils/otel.d.ts +1 -1
  11. package/dist/__tests__/react/utils/otel.d.ts.map +1 -1
  12. package/dist/effect/LiveStore.d.ts +5 -5
  13. package/dist/effect/LiveStore.d.ts.map +1 -1
  14. package/dist/effect/LiveStore.js +5 -4
  15. package/dist/effect/LiveStore.js.map +1 -1
  16. package/dist/index.d.ts +3 -4
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +0 -1
  19. package/dist/index.js.map +1 -1
  20. package/dist/react/LiveStoreProvider.d.ts +4 -4
  21. package/dist/react/LiveStoreProvider.d.ts.map +1 -1
  22. package/dist/react/LiveStoreProvider.js +8 -8
  23. package/dist/react/LiveStoreProvider.js.map +1 -1
  24. package/dist/react/LiveStoreProvider.test.js +3 -4
  25. package/dist/react/LiveStoreProvider.test.js.map +1 -1
  26. package/dist/react/index.d.ts +1 -0
  27. package/dist/react/index.d.ts.map +1 -1
  28. package/dist/react/index.js +1 -0
  29. package/dist/react/index.js.map +1 -1
  30. package/dist/react/useAtom.d.ts +5 -2
  31. package/dist/react/useAtom.d.ts.map +1 -1
  32. package/dist/react/useAtom.js +20 -4
  33. package/dist/react/useAtom.js.map +1 -1
  34. package/dist/react/useLocalId.d.ts +10 -0
  35. package/dist/react/useLocalId.d.ts.map +1 -0
  36. package/dist/react/useLocalId.js +20 -0
  37. package/dist/react/useLocalId.js.map +1 -0
  38. package/dist/react/useQuery.test.js +7 -7
  39. package/dist/react/useQuery.test.js.map +1 -1
  40. package/dist/react/useRow.d.ts +3 -1
  41. package/dist/react/useRow.d.ts.map +1 -1
  42. package/dist/react/useRow.js +25 -8
  43. package/dist/react/useRow.js.map +1 -1
  44. package/dist/react/useRow.test.js +58 -29
  45. package/dist/react/useRow.test.js.map +1 -1
  46. package/dist/react/useTemporaryQuery.d.ts +1 -1
  47. package/dist/react/useTemporaryQuery.d.ts.map +1 -1
  48. package/dist/react/useTemporaryQuery.js.map +1 -1
  49. package/dist/react/useTemporaryQuery.test.js +3 -3
  50. package/dist/react/useTemporaryQuery.test.js.map +1 -1
  51. package/dist/react/utils/useStateRefWithReactiveInput.d.ts.map +1 -1
  52. package/dist/reactive.test.js +1 -1
  53. package/dist/reactive.test.js.map +1 -1
  54. package/dist/reactiveQueries/base-class.d.ts +1 -1
  55. package/dist/reactiveQueries/base-class.d.ts.map +1 -1
  56. package/dist/reactiveQueries/base-class.js.map +1 -1
  57. package/dist/reactiveQueries/graphql.d.ts +4 -4
  58. package/dist/reactiveQueries/graphql.d.ts.map +1 -1
  59. package/dist/reactiveQueries/graphql.js +2 -1
  60. package/dist/reactiveQueries/graphql.js.map +1 -1
  61. package/dist/reactiveQueries/js.d.ts +1 -1
  62. package/dist/reactiveQueries/js.d.ts.map +1 -1
  63. package/dist/reactiveQueries/js.js.map +1 -1
  64. package/dist/reactiveQueries/sql.d.ts +1 -1
  65. package/dist/reactiveQueries/sql.d.ts.map +1 -1
  66. package/dist/reactiveQueries/sql.js +2 -2
  67. package/dist/reactiveQueries/sql.js.map +1 -1
  68. package/dist/row-query.d.ts +3 -3
  69. package/dist/row-query.d.ts.map +1 -1
  70. package/dist/row-query.js +47 -34
  71. package/dist/row-query.js.map +1 -1
  72. package/dist/store.d.ts +20 -19
  73. package/dist/store.d.ts.map +1 -1
  74. package/dist/store.js +67 -41
  75. package/dist/store.js.map +1 -1
  76. package/dist/utils/bounded-collections.d.ts +1 -1
  77. package/dist/utils/bounded-collections.d.ts.map +1 -1
  78. package/dist/utils/util.d.ts +0 -1
  79. package/dist/utils/util.d.ts.map +1 -1
  80. package/dist/utils/util.js.map +1 -1
  81. package/package.json +16 -16
  82. package/src/MainDatabaseWrapper.ts +3 -3
  83. package/src/__tests__/react/fixture.tsx +32 -18
  84. package/src/effect/LiveStore.ts +9 -8
  85. package/src/index.ts +7 -5
  86. package/src/react/LiveStoreProvider.test.tsx +5 -5
  87. package/src/react/LiveStoreProvider.tsx +11 -11
  88. package/src/react/index.ts +1 -0
  89. package/src/react/useAtom.ts +31 -5
  90. package/src/react/useLocalId.ts +30 -0
  91. package/src/react/useQuery.test.tsx +8 -8
  92. package/src/react/useRow.test.tsx +60 -35
  93. package/src/react/useRow.ts +43 -12
  94. package/src/react/useTemporaryQuery.test.tsx +4 -4
  95. package/src/react/useTemporaryQuery.ts +1 -1
  96. package/src/reactive.test.ts +1 -1
  97. package/src/reactiveQueries/base-class.ts +1 -1
  98. package/src/reactiveQueries/graphql.ts +3 -2
  99. package/src/reactiveQueries/js.ts +1 -1
  100. package/src/reactiveQueries/sql.ts +3 -3
  101. package/src/row-query.ts +67 -55
  102. package/src/store.ts +89 -59
  103. package/src/utils/util.ts +0 -2
  104. package/dist/cud.d.ts +0 -28
  105. package/dist/cud.d.ts.map +0 -1
  106. package/dist/cud.js +0 -47
  107. package/dist/cud.js.map +0 -1
  108. package/dist/cud.test.d.ts +0 -2
  109. package/dist/cud.test.d.ts.map +0 -1
  110. package/dist/cud.test.js +0 -47
  111. package/dist/cud.test.js.map +0 -1
  112. package/dist/migrations.d.ts +0 -16
  113. package/dist/migrations.d.ts.map +0 -1
  114. package/dist/migrations.js +0 -98
  115. package/dist/migrations.js.map +0 -1
  116. package/dist/query-info.d.ts +0 -48
  117. package/dist/query-info.d.ts.map +0 -1
  118. package/dist/query-info.js +0 -39
  119. package/dist/query-info.js.map +0 -1
  120. package/src/cud.test.ts +0 -52
  121. package/src/cud.ts +0 -88
  122. package/src/migrations.ts +0 -151
  123. package/src/query-info.ts +0 -104
@@ -1,48 +0,0 @@
1
- import { type DbSchema, type RawSqlMutationEvent } from '@livestore/common/schema';
2
- import { Schema } from '@livestore/utils/effect';
3
- /**
4
- * Semantic information about a query with supported cases being:
5
- * - a whole row
6
- * - a single column value
7
- * - a sub value in a JSON column
8
- */
9
- export type QueryInfo<TTableDef extends DbSchema.TableDef = DbSchema.TableDef> = QueryInfoNone | QueryInfoRow<TTableDef> | QueryInfoColJsonValue<TTableDef, GetJsonColumn<TTableDef>> | QueryInfoCol<TTableDef, keyof TTableDef['sqliteDef']['columns']>;
10
- export type QueryInfoNone = {
11
- _tag: 'None';
12
- };
13
- export type QueryInfoRow<TTableDef extends DbSchema.TableDef> = {
14
- _tag: 'Row';
15
- table: TTableDef;
16
- id: string;
17
- };
18
- export type QueryInfoCol<TTableDef extends DbSchema.TableDef, TColName extends keyof TTableDef['sqliteDef']['columns']> = {
19
- _tag: 'Col';
20
- table: TTableDef;
21
- id: string;
22
- column: TColName;
23
- };
24
- export type QueryInfoColJsonValue<TTableDef extends DbSchema.TableDef, TColName extends GetJsonColumn<TTableDef>> = {
25
- _tag: 'ColJsonValue';
26
- table: TTableDef;
27
- id: string;
28
- column: TColName;
29
- /**
30
- * example: `$.tabs[3].items[2]` (`$` referring to the column value)
31
- */
32
- jsonPath: string;
33
- };
34
- type GetJsonColumn<TTableDef extends DbSchema.TableDef> = keyof {
35
- [ColName in keyof TTableDef['sqliteDef']['columns'] as TTableDef['sqliteDef']['columns'][ColName]['columnType'] extends 'text' ? ColName : never]: {};
36
- };
37
- export type UpdateValueForPath<TPath extends QueryInfo> = TPath extends {
38
- _tag: 'Row';
39
- } ? Partial<DbSchema.FromTable.RowDecodedAll<TPath['table']>> : TPath extends {
40
- _tag: 'Col';
41
- } ? Schema.Schema.Type<TPath['table']['sqliteDef']['columns'][TPath['column']]['schema']> : TPath extends {
42
- _tag: 'ColJsonValue';
43
- } ? {
44
- TODO: true;
45
- } : never;
46
- export declare const mutationForQueryInfo: <const TPath extends QueryInfo<DbSchema.TableDef<DbSchema.DefaultSqliteTableDefConstrained, boolean, DbSchema.TableOptions, Schema.Schema<any, any, never>>>>(updatePath: TPath, value: UpdateValueForPath<TPath>) => RawSqlMutationEvent;
47
- export {};
48
- //# sourceMappingURL=query-info.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"query-info.d.ts","sourceRoot":"","sources":["../src/query-info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAkB,KAAK,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAElG,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAEhD;;;;;GAKG;AACH,MAAM,MAAM,SAAS,CAAC,SAAS,SAAS,QAAQ,CAAC,QAAQ,GAAG,QAAQ,CAAC,QAAQ,IACzE,aAAa,GACb,YAAY,CAAC,SAAS,CAAC,GACvB,qBAAqB,CAAC,SAAS,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC,GAC1D,YAAY,CAAC,SAAS,EAAE,MAAM,SAAS,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,CAAA;AAEpE,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,YAAY,CAAC,SAAS,SAAS,QAAQ,CAAC,QAAQ,IAAI;IAC9D,IAAI,EAAE,KAAK,CAAA;IACX,KAAK,EAAE,SAAS,CAAA;IAChB,EAAE,EAAE,MAAM,CAAA;CACX,CAAA;AAED,MAAM,MAAM,YAAY,CACtB,SAAS,SAAS,QAAQ,CAAC,QAAQ,EACnC,QAAQ,SAAS,MAAM,SAAS,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,IACtD;IACF,IAAI,EAAE,KAAK,CAAA;IACX,KAAK,EAAE,SAAS,CAAA;IAChB,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,QAAQ,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,qBAAqB,CAAC,SAAS,SAAS,QAAQ,CAAC,QAAQ,EAAE,QAAQ,SAAS,aAAa,CAAC,SAAS,CAAC,IAAI;IAClH,IAAI,EAAE,cAAc,CAAA;IACpB,KAAK,EAAE,SAAS,CAAA;IAChB,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,QAAQ,CAAA;IAChB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,KAAK,aAAa,CAAC,SAAS,SAAS,QAAQ,CAAC,QAAQ,IAAI,MAAM;KAC7D,OAAO,IAAI,MAAM,SAAS,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,SAAS,MAAM,GAC1H,OAAO,GACP,KAAK,GAAG,EAAE;CACf,CAAA;AAED,MAAM,MAAM,kBAAkB,CAAC,KAAK,SAAS,SAAS,IAAI,KAAK,SAAS;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,GACnF,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GACzD,KAAK,SAAS;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,GAC3B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GACrF,KAAK,SAAS;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,GACd,KAAK,CAAA;AAEb,eAAO,MAAM,oBAAoB,4KACnB,KAAK,SACV,mBAAmB,KAAK,CAAC,KAC/B,mBAuCF,CAAA"}
@@ -1,39 +0,0 @@
1
- import { rawSqlMutation } from '@livestore/common/schema';
2
- import { notYetImplemented, shouldNeverHappen } from '@livestore/utils';
3
- import { Schema } from '@livestore/utils/effect';
4
- export const mutationForQueryInfo = (updatePath, value) => {
5
- if (updatePath._tag === 'ColJsonValue' || updatePath._tag === 'None') {
6
- return notYetImplemented('TODO');
7
- }
8
- const sqliteTableDef = updatePath.table.sqliteDef;
9
- const id = updatePath.id;
10
- const { columnNames, bindValues } = (() => {
11
- if (updatePath._tag === 'Row') {
12
- const columnNames = Object.keys(value);
13
- const partialStructSchema = updatePath.table.schema.pipe(Schema.pick(...columnNames));
14
- // const columnNames = Object.keys(value)
15
- const encodedBindValues = Schema.encodeEither(partialStructSchema)(value);
16
- if (encodedBindValues._tag === 'Left') {
17
- return shouldNeverHappen(encodedBindValues.left.toString());
18
- }
19
- else {
20
- return { columnNames, bindValues: encodedBindValues.right };
21
- }
22
- }
23
- else if (updatePath._tag === 'Col') {
24
- const columnName = updatePath.column;
25
- const columnSchema = sqliteTableDef.columns[columnName]?.schema ?? shouldNeverHappen(`Column ${columnName} not found`);
26
- const bindValues = { [columnName]: Schema.encodeSync(columnSchema)(value) };
27
- return { columnNames: [columnName], bindValues };
28
- }
29
- else {
30
- return shouldNeverHappen();
31
- }
32
- })();
33
- const updateClause = columnNames.map((columnName) => `${columnName} = $${columnName}`).join(', ');
34
- const whereClause = `where id = '${id}'`;
35
- const sql = `UPDATE ${sqliteTableDef.name} SET ${updateClause} ${whereClause}`;
36
- const writeTables = new Set([updatePath.table.sqliteDef.name]);
37
- return rawSqlMutation({ sql, bindValues, writeTables });
38
- };
39
- //# sourceMappingURL=query-info.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"query-info.js","sourceRoot":"","sources":["../src/query-info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,cAAc,EAA4B,MAAM,0BAA0B,CAAA;AAClG,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACvE,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AA2DhD,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,UAAiB,EACjB,KAAgC,EACX,EAAE;IACvB,IAAI,UAAU,CAAC,IAAI,KAAK,cAAc,IAAI,UAAU,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACrE,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAA;IAClC,CAAC;IAED,MAAM,cAAc,GAAG,UAAU,CAAC,KAAK,CAAC,SAAS,CAAA;IACjD,MAAM,EAAE,GAAG,UAAU,CAAC,EAAE,CAAA;IAExB,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,CAAC,GAAG,EAAE;QACxC,IAAI,UAAU,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YAC9B,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YAEtC,MAAM,mBAAmB,GAAG,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,CAAC,CAAA;YAErF,yCAAyC;YACzC,MAAM,iBAAiB,GAAG,MAAM,CAAC,YAAY,CAAC,mBAAmB,CAAC,CAAC,KAAK,CAAC,CAAA;YACzE,IAAI,iBAAiB,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBACtC,OAAO,iBAAiB,CAAC,iBAAiB,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAA;YAC7D,CAAC;iBAAM,CAAC;gBACN,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,iBAAiB,CAAC,KAAK,EAAE,CAAA;YAC7D,CAAC;QACH,CAAC;aAAM,IAAI,UAAU,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YACrC,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAA;YACpC,MAAM,YAAY,GAChB,cAAc,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,MAAM,IAAI,iBAAiB,CAAC,UAAU,UAAU,YAAY,CAAC,CAAA;YACnG,MAAM,UAAU,GAAG,EAAE,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,EAAE,CAAA;YAC3E,OAAO,EAAE,WAAW,EAAE,CAAC,UAAU,CAAC,EAAE,UAAU,EAAE,CAAA;QAClD,CAAC;aAAM,CAAC;YACN,OAAO,iBAAiB,EAAE,CAAA;QAC5B,CAAC;IACH,CAAC,CAAC,EAAE,CAAA;IAEJ,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,GAAG,UAAU,OAAO,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAEjG,MAAM,WAAW,GAAG,eAAe,EAAE,GAAG,CAAA;IACxC,MAAM,GAAG,GAAG,UAAU,cAAc,CAAC,IAAI,QAAQ,YAAY,IAAI,WAAW,EAAE,CAAA;IAC9E,MAAM,WAAW,GAAG,IAAI,GAAG,CAAS,CAAC,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;IAEtE,OAAO,cAAc,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAA;AACzD,CAAC,CAAA"}
package/src/cud.test.ts DELETED
@@ -1,52 +0,0 @@
1
- import { describe, expect, test } from 'vitest'
2
-
3
- import { tables } from './__tests__/react/fixture.js'
4
- import { makeCudMutations } from './cud.js'
5
- import type { MutationEvent } from './index.js'
6
-
7
- describe('cud mutations', () => {
8
- const cud = makeCudMutations(tables)
9
-
10
- test('basic', () => {
11
- expect(patchId(cud.todos.insert({ id: 't1', completed: true, text: 'Task 1' }))).toMatchInlineSnapshot(`
12
- {
13
- "args": {
14
- "bindValues": {
15
- "completed": 1,
16
- "id": "t1",
17
- "text": "Task 1",
18
- },
19
- "sql": "INSERT INTO todos (id, text, completed) VALUES ($id, $text, $completed)",
20
- "writeTables": Set {
21
- "todos",
22
- },
23
- },
24
- "id": "00000000-0000-0000-0000-000000000000",
25
- "mutation": "livestore.RawSql",
26
- }
27
- `)
28
-
29
- expect(patchId(cud.todos.update({ where: { id: 't1' }, values: { text: 'Task 1 - fixed' } })))
30
- .toMatchInlineSnapshot(`
31
- {
32
- "args": {
33
- "bindValues": {
34
- "update_text": "Task 1 - fixed",
35
- "where_id": "t1",
36
- },
37
- "sql": "UPDATE todos SET text = $update_text WHERE id = $where_id",
38
- "writeTables": Set {
39
- "todos",
40
- },
41
- },
42
- "id": "00000000-0000-0000-0000-000000000000",
43
- "mutation": "livestore.RawSql",
44
- }
45
- `)
46
- })
47
- })
48
-
49
- const patchId = (muationEvent: MutationEvent.Any) => {
50
- const id = `00000000-0000-0000-0000-000000000000`
51
- return { ...muationEvent, id }
52
- }
package/src/cud.ts DELETED
@@ -1,88 +0,0 @@
1
- import type { RawSqlMutationEvent } from '@livestore/common/schema'
2
- import { DbSchema, rawSqlMutation } from '@livestore/common/schema'
3
- import { deleteRows, insertRow, updateRows } from '@livestore/common/sql-queries'
4
- import { isIterable } from '@livestore/utils'
5
- import type { SqliteDsl } from 'effect-db-schema'
6
-
7
- import type { RowResult } from './row-query.js'
8
- import { type GetValForKey } from './utils/util.js'
9
-
10
- export const makeCudMutations = <TTableDef extends DbSchema.TableDef>(
11
- tables: Iterable<TTableDef> | Record<string, TTableDef>,
12
- ): CudMutations<TTableDef> => {
13
- const cudMutationRecord: CudMutations<TTableDef> = {} as any
14
-
15
- const tables_ = isIterable(tables) ? tables : Object.values(tables)
16
-
17
- for (const tableDef of tables_) {
18
- const [tableName, cudMutation] = cudMutationsForTable(tableDef)
19
- cudMutationRecord[tableName] = cudMutation as any
20
- }
21
-
22
- return cudMutationRecord
23
- }
24
-
25
- const cudMutationsForTable = <TTableDef extends DbSchema.TableDef>(
26
- tableDef: TTableDef,
27
- ): [TTableDef['sqliteDef']['name'], CudMutation<TTableDef>] => {
28
- const table = tableDef.sqliteDef
29
- const writeTables = new Set([table.name])
30
- const api = {
31
- insert: (values_: any) => {
32
- const values = DbSchema.getDefaultValuesDecoded(tableDef, values_)
33
-
34
- const [sql, bindValues] = insertRow({
35
- tableName: table.name,
36
- columns: table.columns,
37
- options: { orReplace: false },
38
- values: values as any,
39
- })
40
- return rawSqlMutation({ sql, bindValues, writeTables })
41
- },
42
- update: ({ where, values }) => {
43
- const [sql, bindValues] = updateRows({
44
- tableName: table.name,
45
- columns: table.columns,
46
- where: where,
47
- updateValues: values,
48
- })
49
- return rawSqlMutation({ sql, bindValues, writeTables })
50
- },
51
- delete: ({ where }) => {
52
- const [sql, bindValues] = deleteRows({
53
- tableName: table.name,
54
- columns: table.columns,
55
- where: where,
56
- })
57
- return rawSqlMutation({ sql, bindValues, writeTables })
58
- },
59
- } satisfies CudMutation<TTableDef>
60
-
61
- return [tableDef.sqliteDef.name, api]
62
- }
63
-
64
- export type UpdateMutation<TTableDef extends DbSchema.TableDef> = (args: {
65
- // TODO also allow `id` if present in `TTableDef`
66
- where: Partial<RowResult<TTableDef>>
67
- values: Partial<RowResult<TTableDef>>
68
- }) => RawSqlMutationEvent
69
-
70
- export type RowInsert<TTableDef extends DbSchema.TableDef> = TTableDef['isSingleColumn'] extends true
71
- ? GetValForKey<SqliteDsl.FromColumns.InsertRowDecoded<TTableDef['sqliteDef']['columns']>, 'value'>
72
- : SqliteDsl.FromColumns.InsertRowDecoded<TTableDef['sqliteDef']['columns']>
73
-
74
- export type InsertMutation<TTableDef extends DbSchema.TableDef> = (values: RowInsert<TTableDef>) => RawSqlMutationEvent
75
-
76
- export type DeleteMutation<TTableDef extends DbSchema.TableDef> = (args: {
77
- where: Partial<RowResult<TTableDef>>
78
- }) => RawSqlMutationEvent
79
-
80
- export type CudMutation<TTableDef extends DbSchema.TableDef> = {
81
- insert: InsertMutation<TTableDef>
82
- update: UpdateMutation<TTableDef>
83
- delete: DeleteMutation<TTableDef>
84
- }
85
-
86
- export type CudMutations<TTableDef extends DbSchema.TableDef> = {
87
- [TTableName in TTableDef['sqliteDef']['name']]: CudMutation<Extract<TTableDef, { sqliteDef: { name: TTableName } }>>
88
- }
package/src/migrations.ts DELETED
@@ -1,151 +0,0 @@
1
- import { type DatabaseImpl, sql } from '@livestore/common'
2
- import type { LiveStoreSchema, SchemaMetaRow } from '@livestore/common/schema'
3
- import { SCHEMA_META_TABLE, systemTables } from '@livestore/common/schema'
4
- import { Schema as EffectSchema } from '@livestore/utils/effect'
5
- import type * as otel from '@opentelemetry/api'
6
- import { SqliteAst, SqliteDsl } from 'effect-db-schema'
7
- import { memoize } from 'lodash-es'
8
-
9
- import type { ParamsObject } from './utils/util.js'
10
- import { prepareBindValues } from './utils/util.js'
11
-
12
- const getMemoizedTimestamp = memoize(() => new Date().toISOString())
13
-
14
- // TODO bring back statement caching
15
- // const cachedStmts = new Map<string, PreparedStatement>()
16
-
17
- const dbExecute = (db: DatabaseImpl, queryStr: string, bindValues?: ParamsObject) => {
18
- // let stmt = cachedStmts.get(queryStr)
19
- // if (!stmt) {
20
- const stmt = db.mainDb.prepare(queryStr)
21
- // cachedStmts.set(queryStr, stmt)
22
- // }
23
-
24
- const preparedBindValues = bindValues ? prepareBindValues(bindValues, queryStr) : undefined
25
-
26
- stmt.execute(preparedBindValues)
27
-
28
- void db.storageDb.execute(queryStr, preparedBindValues, undefined)
29
- }
30
-
31
- const dbSelect = <T>(db: DatabaseImpl, queryStr: string, bindValues?: ParamsObject) => {
32
- // let stmt = cachedStmts.get(queryStr)
33
- // if (!stmt) {
34
- const stmt = db.mainDb.prepare(queryStr)
35
- // cachedStmts.set(queryStr, stmt)
36
- // }
37
-
38
- return stmt.select<T>(bindValues ? prepareBindValues(bindValues, queryStr) : undefined)
39
- }
40
-
41
- // TODO more graceful DB migration (e.g. backup DB before destructive migrations)
42
- export const migrateDb = ({
43
- db,
44
- otelContext,
45
- schema,
46
- }: {
47
- db: DatabaseImpl
48
- otelContext: otel.Context
49
- schema: LiveStoreSchema
50
- }) => {
51
- dbExecute(
52
- db,
53
- // TODO use schema migration definition from schema.ts instead
54
- sql`create table if not exists ${SCHEMA_META_TABLE} (tableName text primary key, schemaHash text, updatedAt text);`,
55
- )
56
-
57
- const schemaMetaRows = dbSelect<SchemaMetaRow>(db, sql`SELECT * FROM ${SCHEMA_META_TABLE}`)
58
-
59
- const dbSchemaHashByTable = Object.fromEntries(
60
- schemaMetaRows.map(({ tableName, schemaHash }) => [tableName, schemaHash]),
61
- )
62
-
63
- const tableDefs = new Set([
64
- // NOTE it's important the `SCHEMA_META_TABLE` comes first since we're writing to it below
65
- ...systemTables,
66
- ...Array.from(schema.tables.values()).filter((_) => _.sqliteDef.name !== SCHEMA_META_TABLE),
67
- ])
68
-
69
- for (const tableDef of tableDefs) {
70
- const tableAst = tableDef.sqliteDef.ast
71
- const tableName = tableAst.name
72
- const dbSchemaHash = dbSchemaHashByTable[tableName]
73
- const schemaHash = SqliteAst.hash(tableAst)
74
- if (schemaHash !== dbSchemaHash && import.meta.env.VITE_LIVESTORE_SKIP_MIGRATIONS === undefined) {
75
- console.log(
76
- `Schema hash mismatch for table '${tableName}' (DB: ${dbSchemaHash}, expected: ${schemaHash}), migrating table...`,
77
- )
78
-
79
- migrateTable({ db, tableAst, otelContext, schemaHash })
80
- }
81
- }
82
- }
83
-
84
- export const migrateTable = ({
85
- db,
86
- tableAst,
87
- // otelContext,
88
- schemaHash,
89
- }: {
90
- db: DatabaseImpl
91
- tableAst: SqliteAst.Table
92
- otelContext: otel.Context
93
- schemaHash: number
94
- }) => {
95
- console.log(`Migrating table '${tableAst.name}'...`)
96
- const tableName = tableAst.name
97
- const columnSpec = makeColumnSpec(tableAst)
98
-
99
- // TODO need to possibly handle cascading deletes due to foreign keys
100
- dbExecute(db, sql`drop table if exists ${tableName}`)
101
- dbExecute(db, sql`create table if not exists ${tableName} (${columnSpec})`)
102
-
103
- for (const index of tableAst.indexes) {
104
- dbExecute(db, createIndexFromDefinition(tableName, index))
105
- }
106
-
107
- const updatedAt = getMemoizedTimestamp()
108
-
109
- dbExecute(
110
- db,
111
- sql`
112
- INSERT INTO ${SCHEMA_META_TABLE} (tableName, schemaHash, updatedAt) VALUES ($tableName, $schemaHash, $updatedAt)
113
- ON CONFLICT (tableName) DO UPDATE SET schemaHash = $schemaHash, updatedAt = $updatedAt;
114
- `,
115
- { tableName, schemaHash, updatedAt },
116
- )
117
- }
118
-
119
- const createIndexFromDefinition = (tableName: string, index: SqliteAst.Index) => {
120
- const uniqueStr = index.unique ? 'UNIQUE' : ''
121
- return sql`create ${uniqueStr} index ${index.name} on ${tableName} (${index.columns.join(', ')})`
122
- }
123
-
124
- const makeColumnSpec = (tableAst: SqliteAst.Table) => {
125
- const primaryKeys = tableAst.columns.filter((_) => _.primaryKey).map((_) => _.name)
126
- const columnDefStrs = tableAst.columns.map(toSqliteColumnSpec)
127
- if (primaryKeys.length > 0) {
128
- columnDefStrs.push(`PRIMARY KEY (${primaryKeys.join(', ')})`)
129
- }
130
-
131
- return columnDefStrs.join(', ')
132
- }
133
-
134
- /** NOTE primary keys are applied on a table level not on a column level to account for multi-column primary keys */
135
- const toSqliteColumnSpec = (column: SqliteAst.Column) => {
136
- const columnTypeStr = column.type._tag
137
- const nullableStr = column.nullable === false ? 'not null' : ''
138
- const defaultValueStr = (() => {
139
- if (column.default._tag === 'None') return ''
140
-
141
- if (SqliteDsl.isSqlDefaultValue(column.default.value)) return `default ${column.default.value.sql}`
142
-
143
- const encodeValue = EffectSchema.encodeSync(column.schema)
144
- const encodedDefaultValue = encodeValue(column.default.value)
145
-
146
- if (columnTypeStr === 'text') return `default '${encodedDefaultValue}'`
147
- return `default ${encodedDefaultValue}`
148
- })()
149
-
150
- return `${column.name} ${columnTypeStr} ${nullableStr} ${defaultValueStr}`
151
- }
package/src/query-info.ts DELETED
@@ -1,104 +0,0 @@
1
- import { type DbSchema, rawSqlMutation, type RawSqlMutationEvent } from '@livestore/common/schema'
2
- import { notYetImplemented, shouldNeverHappen } from '@livestore/utils'
3
- import { Schema } from '@livestore/utils/effect'
4
-
5
- /**
6
- * Semantic information about a query with supported cases being:
7
- * - a whole row
8
- * - a single column value
9
- * - a sub value in a JSON column
10
- */
11
- export type QueryInfo<TTableDef extends DbSchema.TableDef = DbSchema.TableDef> =
12
- | QueryInfoNone
13
- | QueryInfoRow<TTableDef>
14
- | QueryInfoColJsonValue<TTableDef, GetJsonColumn<TTableDef>>
15
- | QueryInfoCol<TTableDef, keyof TTableDef['sqliteDef']['columns']>
16
-
17
- export type QueryInfoNone = {
18
- _tag: 'None'
19
- }
20
-
21
- export type QueryInfoRow<TTableDef extends DbSchema.TableDef> = {
22
- _tag: 'Row'
23
- table: TTableDef
24
- id: string
25
- }
26
-
27
- export type QueryInfoCol<
28
- TTableDef extends DbSchema.TableDef,
29
- TColName extends keyof TTableDef['sqliteDef']['columns'],
30
- > = {
31
- _tag: 'Col'
32
- table: TTableDef
33
- id: string
34
- column: TColName
35
- }
36
-
37
- export type QueryInfoColJsonValue<TTableDef extends DbSchema.TableDef, TColName extends GetJsonColumn<TTableDef>> = {
38
- _tag: 'ColJsonValue'
39
- table: TTableDef
40
- id: string
41
- column: TColName
42
- /**
43
- * example: `$.tabs[3].items[2]` (`$` referring to the column value)
44
- */
45
- jsonPath: string
46
- }
47
-
48
- type GetJsonColumn<TTableDef extends DbSchema.TableDef> = keyof {
49
- [ColName in keyof TTableDef['sqliteDef']['columns'] as TTableDef['sqliteDef']['columns'][ColName]['columnType'] extends 'text'
50
- ? ColName
51
- : never]: {}
52
- }
53
-
54
- export type UpdateValueForPath<TPath extends QueryInfo> = TPath extends { _tag: 'Row' }
55
- ? Partial<DbSchema.FromTable.RowDecodedAll<TPath['table']>>
56
- : TPath extends { _tag: 'Col' }
57
- ? Schema.Schema.Type<TPath['table']['sqliteDef']['columns'][TPath['column']]['schema']>
58
- : TPath extends { _tag: 'ColJsonValue' }
59
- ? { TODO: true }
60
- : never
61
-
62
- export const mutationForQueryInfo = <const TPath extends QueryInfo>(
63
- updatePath: TPath,
64
- value: UpdateValueForPath<TPath>,
65
- ): RawSqlMutationEvent => {
66
- if (updatePath._tag === 'ColJsonValue' || updatePath._tag === 'None') {
67
- return notYetImplemented('TODO')
68
- }
69
-
70
- const sqliteTableDef = updatePath.table.sqliteDef
71
- const id = updatePath.id
72
-
73
- const { columnNames, bindValues } = (() => {
74
- if (updatePath._tag === 'Row') {
75
- const columnNames = Object.keys(value)
76
-
77
- const partialStructSchema = updatePath.table.schema.pipe(Schema.pick(...columnNames))
78
-
79
- // const columnNames = Object.keys(value)
80
- const encodedBindValues = Schema.encodeEither(partialStructSchema)(value)
81
- if (encodedBindValues._tag === 'Left') {
82
- return shouldNeverHappen(encodedBindValues.left.toString())
83
- } else {
84
- return { columnNames, bindValues: encodedBindValues.right }
85
- }
86
- } else if (updatePath._tag === 'Col') {
87
- const columnName = updatePath.column
88
- const columnSchema =
89
- sqliteTableDef.columns[columnName]?.schema ?? shouldNeverHappen(`Column ${columnName} not found`)
90
- const bindValues = { [columnName]: Schema.encodeSync(columnSchema)(value) }
91
- return { columnNames: [columnName], bindValues }
92
- } else {
93
- return shouldNeverHappen()
94
- }
95
- })()
96
-
97
- const updateClause = columnNames.map((columnName) => `${columnName} = $${columnName}`).join(', ')
98
-
99
- const whereClause = `where id = '${id}'`
100
- const sql = `UPDATE ${sqliteTableDef.name} SET ${updateClause} ${whereClause}`
101
- const writeTables = new Set<string>([updatePath.table.sqliteDef.name])
102
-
103
- return rawSqlMutation({ sql, bindValues, writeTables })
104
- }