@livestore/common 0.0.56-dev.2 → 0.0.56

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.
@@ -6,7 +6,7 @@ import type { LiveStoreSchema, MutationEvent } from './schema/index.js'
6
6
  import type { PreparedBindValues } from './util.js'
7
7
 
8
8
  export interface PreparedStatement {
9
- execute(bindValues: PreparedBindValues | undefined): GetRowsChangedCount
9
+ execute(bindValues: PreparedBindValues | undefined, options?: { onRowsChanged?: (rowsChanged: number) => void }): void
10
10
  select<T>(bindValues: PreparedBindValues | undefined): ReadonlyArray<T>
11
11
  finalize(): void
12
12
  }
@@ -21,7 +21,12 @@ export type StoreAdapter = {
21
21
  export type SynchronousDatabase = {
22
22
  _tag: 'SynchronousDatabase'
23
23
  prepare(queryStr: string): PreparedStatement
24
- execute(queryStr: string, bindValues: PreparedBindValues | undefined): GetRowsChangedCount
24
+ execute(
25
+ queryStr: string,
26
+ bindValues?: PreparedBindValues | undefined,
27
+ options?: { onRowsChanged?: (rowsChanged: number) => void },
28
+ ): void
29
+ select<T>(queryStr: string, bindValues?: PreparedBindValues | undefined): ReadonlyArray<T>
25
30
  export(): Uint8Array
26
31
  }
27
32
 
@@ -62,18 +67,11 @@ export type Coordinator = {
62
67
  syncMutations: Stream.Stream<MutationEvent.AnyEncoded, UnexpectedError>
63
68
  execute(queryStr: string, bindValues: PreparedBindValues | undefined): Effect.Effect<void, UnexpectedError>
64
69
  mutate(mutationEventEncoded: MutationEvent.Any, options: { persisted: boolean }): Effect.Effect<void, UnexpectedError>
65
- dangerouslyReset(mode: ResetMode): Effect.Effect<void, UnexpectedError>
66
70
  export: Effect.Effect<Uint8Array | undefined, UnexpectedError>
67
- /**
68
- * This is different from `export` since in `getInitialSnapshot` is usually the place for migrations etc to happen
69
- */
70
- getInitialSnapshot: Effect.Effect<Uint8Array, UnexpectedError>
71
71
  getMutationLogData: Effect.Effect<Uint8Array, UnexpectedError>
72
72
  networkStatus: SubscriptionRef.SubscriptionRef<NetworkStatus>
73
73
  }
74
74
 
75
- export type GetRowsChangedCount = () => number
76
-
77
75
  export type LockStatus = 'has-lock' | 'no-lock'
78
76
 
79
77
  export type BootDb = {
@@ -102,11 +100,22 @@ export class UnexpectedError extends Schema.TaggedError<UnexpectedError>()('Live
102
100
  )
103
101
  }
104
102
 
103
+ export class IntentionalShutdownCause extends Schema.TaggedError<IntentionalShutdownCause>()(
104
+ 'LiveStore.IntentionalShutdownCause',
105
+ {
106
+ reason: Schema.Literal('devtools-reset', 'devtools-import'),
107
+ },
108
+ ) {}
109
+
105
110
  export class SqliteError extends Schema.TaggedError<SqliteError>()('LiveStore.SqliteError', {
106
- sql: Schema.String,
107
- bindValues: Schema.Record({ key: Schema.String, value: Schema.Any }),
111
+ query: Schema.optional(
112
+ Schema.Struct({
113
+ sql: Schema.String,
114
+ bindValues: Schema.Union(Schema.Record({ key: Schema.String, value: Schema.Any }), Schema.Array(Schema.Any)),
115
+ }),
116
+ ),
108
117
  /** The SQLite result code */
109
- code: Schema.Number,
118
+ code: Schema.optional(Schema.Number),
110
119
  /** The original SQLite3 error */
111
120
  cause: Schema.Defect,
112
121
  }) {}
@@ -124,9 +124,14 @@ export class ResetAllDataRes extends LSDReqResMessage('LSD.ResetAllDataRes', {})
124
124
 
125
125
  export class DatabaseFileInfoReq extends LSDReqResMessage('LSD.DatabaseFileInfoReq', {}) {}
126
126
 
127
+ export class DatabaseFileInfo extends Schema.Struct({
128
+ fileSize: Schema.Number,
129
+ persistenceInfo: Schema.Struct({ fileName: Schema.String }, { key: Schema.String, value: Schema.Any }),
130
+ }) {}
131
+
127
132
  export class DatabaseFileInfoRes extends LSDReqResMessage('LSD.DatabaseFileInfoRes', {
128
- dbFileSize: Schema.Number,
129
- mutationLogFileSize: Schema.Number,
133
+ db: DatabaseFileInfo,
134
+ mutationLog: DatabaseFileInfo,
130
135
  }) {}
131
136
 
132
137
  export class MessagePortForStoreReq extends LSDReqResMessage('LSD.MessagePortForStoreReq', {}) {}
@@ -1,12 +1,7 @@
1
1
  import { memoizeByRef, shouldNeverHappen } from '@livestore/utils'
2
2
  import { Chunk, Effect, Option, Schema, Stream } from '@livestore/utils/effect'
3
3
 
4
- import {
5
- type MigrationOptionsFromMutationLog,
6
- SqliteError,
7
- type SynchronousDatabase,
8
- UnexpectedError,
9
- } from './adapter-types.js'
4
+ import { type MigrationOptionsFromMutationLog, type SynchronousDatabase, UnexpectedError } from './adapter-types.js'
10
5
  import { getExecArgsFromMutation } from './mutation.js'
11
6
  import type { LiveStoreSchema, MutationDef, MutationLogMetaRow } from './schema/index.js'
12
7
  import { MUTATION_LOG_META_TABLE } from './schema/index.js'
@@ -27,9 +22,9 @@ export const rehydrateFromMutationLog = ({
27
22
  onProgress: (_: { done: number; total: number }) => Effect.Effect<void>
28
23
  }) =>
29
24
  Effect.gen(function* () {
30
- const mutationsCount = logDb
31
- .prepare(`SELECT COUNT(*) AS count FROM ${MUTATION_LOG_META_TABLE}`)
32
- .select<{ count: number }>(undefined)[0]!.count
25
+ const mutationsCount = logDb.select<{ count: number }>(
26
+ `SELECT COUNT(*) AS count FROM ${MUTATION_LOG_META_TABLE}`,
27
+ )[0]!.count
33
28
 
34
29
  const hashMutation = memoizeByRef((mutation: MutationDef.Any) => Schema.hash(mutation.schema))
35
30
 
@@ -63,36 +58,25 @@ This likely means the schema has changed in an incompatible way.
63
58
  mutation: row.mutation,
64
59
  args: argsDecoded,
65
60
  }
66
- // const argsEncoded = JSON.parse(row.args_json)
67
- // const mutationSqlRes =
68
- // typeof mutation.sql === 'string'
69
- // ? mutation.sql
70
- // : mutation.sql(Schema.decodeUnknownSync(mutation.schema)(argsEncoded))
71
- // const mutationSql = typeof mutationSqlRes === 'string' ? mutationSqlRes : mutationSqlRes.sql
72
- // const bindValues = typeof mutationSqlRes === 'string' ? argsEncoded : mutationSqlRes.bindValues
73
61
 
74
62
  const execArgsArr = getExecArgsFromMutation({ mutationDef, mutationEventDecoded })
75
63
 
76
- for (const { statementSql, bindValues } of execArgsArr) {
77
- try {
78
- // TODO cache prepared statements for mutations
79
- const getRowsChanged = db.execute(statementSql, bindValues)
80
- if (
81
- import.meta.env.DEV &&
82
- getRowsChanged() === 0 &&
83
- migrationOptions.logging?.excludeAffectedRows?.(statementSql) !== true
84
- ) {
64
+ const makeExecuteOptions = (statementSql: string, bindValues: any) => ({
65
+ onRowsChanged: (rowsChanged: number) => {
66
+ if (rowsChanged === 0 && migrationOptions.logging?.excludeAffectedRows?.(statementSql) !== true) {
85
67
  console.warn(`Mutation "${mutationDef.name}" did not affect any rows:`, statementSql, bindValues)
86
68
  }
87
- // console.log(`Re-executed mutation ${mutationSql}`, bindValues)
88
- } catch (e) {
89
- yield* new SqliteError({
90
- sql: statementSql,
91
- bindValues,
92
- code: (e as any).resultCode,
93
- cause: e,
94
- })
95
- }
69
+ },
70
+ })
71
+
72
+ for (const { statementSql, bindValues } of execArgsArr) {
73
+ // TODO cache prepared statements for mutations
74
+ db.execute(
75
+ statementSql,
76
+ bindValues,
77
+ import.meta.env.DEV ? makeExecuteOptions(statementSql, bindValues) : undefined,
78
+ )
79
+ // console.log(`Re-executed mutation ${mutationSql}`, bindValues)
96
80
  }
97
81
  }).pipe(Effect.withSpan(`@livestore/common:rehydrateFromMutationLog:processMutation`))
98
82
 
@@ -39,6 +39,9 @@ export type LiveStoreSchema<
39
39
 
40
40
  migrationOptions: MigrationOptions
41
41
 
42
+ /**
43
+ * @default 'default'
44
+ */
42
45
  key: string
43
46
  }
44
47
 
@@ -47,9 +50,6 @@ export type InputSchema = {
47
50
  readonly mutations?: ReadonlyArray<MutationDef.Any> | Record<string, MutationDef.Any>
48
51
  /**
49
52
  * Can be used to isolate multiple LiveStore apps running in the same origin
50
- *
51
- * Make sure you also use this key in the `storage` options (e.g. directory, prefix etc) to make sure
52
- * different instances of LiveStore aren't overlapping on the storage level.
53
53
  */
54
54
  readonly key?: string
55
55
  }
@@ -118,7 +118,7 @@ export const makeSchema = <TInputSchema extends InputSchema>(
118
118
  mutations,
119
119
  migrationOptions: inputSchema.migrations ?? { strategy: 'hard-reset' },
120
120
  hash,
121
- key: inputSchema.key ?? '',
121
+ key: inputSchema.key ?? 'default',
122
122
  } satisfies LiveStoreSchema
123
123
  }
124
124
 
@@ -16,6 +16,8 @@ export const dbExecute = (db: SynchronousDatabase, queryStr: string, bindValues?
16
16
  const preparedBindValues = bindValues ? prepareBindValues(bindValues, queryStr) : undefined
17
17
 
18
18
  stmt.execute(preparedBindValues)
19
+
20
+ stmt.finalize()
19
21
  }
20
22
 
21
23
  export const dbSelect = <T>(db: SynchronousDatabase, queryStr: string, bindValues?: ParamsObject) => {
@@ -25,7 +27,9 @@ export const dbSelect = <T>(db: SynchronousDatabase, queryStr: string, bindValue
25
27
  // cachedStmts.set(queryStr, stmt)
26
28
  // }
27
29
 
28
- return stmt.select<T>(bindValues ? prepareBindValues(bindValues, queryStr) : undefined)
30
+ const res = stmt.select<T>(bindValues ? prepareBindValues(bindValues, queryStr) : undefined)
31
+ stmt.finalize()
32
+ return res
29
33
  }
30
34
 
31
35
  export interface SchemaManager {
@@ -28,14 +28,9 @@ export const makeSchemaManager = (db: SynchronousDatabase): Effect.Effect<Schema
28
28
  })
29
29
 
30
30
  return {
31
- getMutationDefInfos: () => {
32
- const schemaMutationsMetaRows = dbSelect<SchemaMutationsMetaRow>(
33
- db,
34
- sql`SELECT * FROM ${SCHEMA_MUTATIONS_META_TABLE}`,
35
- )
31
+ getMutationDefInfos: () =>
32
+ dbSelect<SchemaMutationsMetaRow>(db, sql`SELECT * FROM ${SCHEMA_MUTATIONS_META_TABLE}`),
36
33
 
37
- return schemaMutationsMetaRows
38
- },
39
34
  setMutationDefInfo: (info) => {
40
35
  dbExecute(
41
36
  db,
@@ -128,7 +123,7 @@ export const migrateTable = ({
128
123
  skipMetaTable?: boolean
129
124
  }) =>
130
125
  Effect.gen(function* () {
131
- console.log(`Migrating table '${tableAst.name}'...`)
126
+ // console.log(`Migrating table '${tableAst.name}'...`)
132
127
  const tableName = tableAst.name
133
128
  const columnSpec = makeColumnSpec(tableAst)
134
129