@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.
- package/README.md +3 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/MainDatabaseWrapper.d.ts +2 -2
- package/dist/MainDatabaseWrapper.d.ts.map +1 -1
- package/dist/MainDatabaseWrapper.js.map +1 -1
- package/dist/__tests__/react/fixture.d.ts +262 -158
- package/dist/__tests__/react/fixture.d.ts.map +1 -1
- package/dist/__tests__/react/fixture.js +14 -12
- package/dist/__tests__/react/fixture.js.map +1 -1
- package/dist/__tests__/react/utils/otel.d.ts +1 -1
- package/dist/__tests__/react/utils/otel.d.ts.map +1 -1
- package/dist/effect/LiveStore.d.ts +5 -5
- package/dist/effect/LiveStore.d.ts.map +1 -1
- package/dist/effect/LiveStore.js +5 -4
- package/dist/effect/LiveStore.js.map +1 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/react/LiveStoreProvider.d.ts +4 -4
- package/dist/react/LiveStoreProvider.d.ts.map +1 -1
- package/dist/react/LiveStoreProvider.js +8 -8
- package/dist/react/LiveStoreProvider.js.map +1 -1
- package/dist/react/LiveStoreProvider.test.js +3 -4
- package/dist/react/LiveStoreProvider.test.js.map +1 -1
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +1 -0
- package/dist/react/index.js.map +1 -1
- package/dist/react/useAtom.d.ts +5 -2
- package/dist/react/useAtom.d.ts.map +1 -1
- package/dist/react/useAtom.js +20 -4
- package/dist/react/useAtom.js.map +1 -1
- package/dist/react/useLocalId.d.ts +10 -0
- package/dist/react/useLocalId.d.ts.map +1 -0
- package/dist/react/useLocalId.js +20 -0
- package/dist/react/useLocalId.js.map +1 -0
- package/dist/react/useQuery.test.js +7 -7
- package/dist/react/useQuery.test.js.map +1 -1
- package/dist/react/useRow.d.ts +3 -1
- package/dist/react/useRow.d.ts.map +1 -1
- package/dist/react/useRow.js +25 -8
- package/dist/react/useRow.js.map +1 -1
- package/dist/react/useRow.test.js +58 -29
- package/dist/react/useRow.test.js.map +1 -1
- package/dist/react/useTemporaryQuery.d.ts +1 -1
- package/dist/react/useTemporaryQuery.d.ts.map +1 -1
- package/dist/react/useTemporaryQuery.js.map +1 -1
- package/dist/react/useTemporaryQuery.test.js +3 -3
- package/dist/react/useTemporaryQuery.test.js.map +1 -1
- package/dist/react/utils/useStateRefWithReactiveInput.d.ts.map +1 -1
- package/dist/reactive.test.js +1 -1
- package/dist/reactive.test.js.map +1 -1
- package/dist/reactiveQueries/base-class.d.ts +1 -1
- package/dist/reactiveQueries/base-class.d.ts.map +1 -1
- package/dist/reactiveQueries/base-class.js.map +1 -1
- package/dist/reactiveQueries/graphql.d.ts +4 -4
- package/dist/reactiveQueries/graphql.d.ts.map +1 -1
- package/dist/reactiveQueries/graphql.js +2 -1
- package/dist/reactiveQueries/graphql.js.map +1 -1
- package/dist/reactiveQueries/js.d.ts +1 -1
- package/dist/reactiveQueries/js.d.ts.map +1 -1
- package/dist/reactiveQueries/js.js.map +1 -1
- package/dist/reactiveQueries/sql.d.ts +1 -1
- package/dist/reactiveQueries/sql.d.ts.map +1 -1
- package/dist/reactiveQueries/sql.js +2 -2
- package/dist/reactiveQueries/sql.js.map +1 -1
- package/dist/row-query.d.ts +3 -3
- package/dist/row-query.d.ts.map +1 -1
- package/dist/row-query.js +47 -34
- package/dist/row-query.js.map +1 -1
- package/dist/store.d.ts +20 -19
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +67 -41
- package/dist/store.js.map +1 -1
- package/dist/utils/bounded-collections.d.ts +1 -1
- package/dist/utils/bounded-collections.d.ts.map +1 -1
- package/dist/utils/util.d.ts +0 -1
- package/dist/utils/util.d.ts.map +1 -1
- package/dist/utils/util.js.map +1 -1
- package/package.json +16 -16
- package/src/MainDatabaseWrapper.ts +3 -3
- package/src/__tests__/react/fixture.tsx +32 -18
- package/src/effect/LiveStore.ts +9 -8
- package/src/index.ts +7 -5
- package/src/react/LiveStoreProvider.test.tsx +5 -5
- package/src/react/LiveStoreProvider.tsx +11 -11
- package/src/react/index.ts +1 -0
- package/src/react/useAtom.ts +31 -5
- package/src/react/useLocalId.ts +30 -0
- package/src/react/useQuery.test.tsx +8 -8
- package/src/react/useRow.test.tsx +60 -35
- package/src/react/useRow.ts +43 -12
- package/src/react/useTemporaryQuery.test.tsx +4 -4
- package/src/react/useTemporaryQuery.ts +1 -1
- package/src/reactive.test.ts +1 -1
- package/src/reactiveQueries/base-class.ts +1 -1
- package/src/reactiveQueries/graphql.ts +3 -2
- package/src/reactiveQueries/js.ts +1 -1
- package/src/reactiveQueries/sql.ts +3 -3
- package/src/row-query.ts +67 -55
- package/src/store.ts +89 -59
- package/src/utils/util.ts +0 -2
- package/dist/cud.d.ts +0 -28
- package/dist/cud.d.ts.map +0 -1
- package/dist/cud.js +0 -47
- package/dist/cud.js.map +0 -1
- package/dist/cud.test.d.ts +0 -2
- package/dist/cud.test.d.ts.map +0 -1
- package/dist/cud.test.js +0 -47
- package/dist/cud.test.js.map +0 -1
- package/dist/migrations.d.ts +0 -16
- package/dist/migrations.d.ts.map +0 -1
- package/dist/migrations.js +0 -98
- package/dist/migrations.js.map +0 -1
- package/dist/query-info.d.ts +0 -48
- package/dist/query-info.d.ts.map +0 -1
- package/dist/query-info.js +0 -39
- package/dist/query-info.js.map +0 -1
- package/src/cud.test.ts +0 -52
- package/src/cud.ts +0 -88
- package/src/migrations.ts +0 -151
- package/src/query-info.ts +0 -104
package/dist/query-info.d.ts
DELETED
|
@@ -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
|
package/dist/query-info.d.ts.map
DELETED
|
@@ -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"}
|
package/dist/query-info.js
DELETED
|
@@ -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
|
package/dist/query-info.js.map
DELETED
|
@@ -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
|
-
}
|