@livestore/livestore 0.0.0-snapshot-ba33be477be76b68bda6af5d102635024df7a9e4 → 0.0.0-snapshot-d2ade85ddbf2f2a330a2bd289e0255b3189142dc

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.
@@ -1,16 +1,17 @@
1
- import type {
2
- ClientSession,
3
- ClientSessionSyncProcessor,
4
- ParamsObject,
5
- PreparedBindValues,
6
- QueryBuilder,
1
+ import {
2
+ type ClientSession,
3
+ type ClientSessionSyncProcessor,
4
+ type ParamsObject,
5
+ type PreparedBindValues,
6
+ type QueryBuilder,
7
7
  UnexpectedError,
8
8
  } from '@livestore/common'
9
9
  import {
10
10
  Devtools,
11
11
  getDurationMsFromSpan,
12
- getExecArgsFromEvent,
12
+ getExecStatementsFromMaterializer,
13
13
  getResultSchema,
14
+ hashMaterializerResults,
14
15
  IntentionalShutdownCause,
15
16
  isQueryBuilder,
16
17
  liveStoreVersion,
@@ -23,7 +24,7 @@ import type { LiveStoreSchema } from '@livestore/common/schema'
23
24
  import { getEventDef, LiveStoreEvent, SystemTables } from '@livestore/common/schema'
24
25
  import { assertNever, isDevEnv, notYetImplemented } from '@livestore/utils'
25
26
  import type { Scope } from '@livestore/utils/effect'
26
- import { Cause, Effect, Fiber, Inspectable, OtelTracer, Runtime, Schema, Stream } from '@livestore/utils/effect'
27
+ import { Cause, Effect, Fiber, Inspectable, Option, OtelTracer, Runtime, Schema, Stream } from '@livestore/utils/effect'
27
28
  import { nanoid } from '@livestore/utils/nanoid'
28
29
  import * as otel from '@opentelemetry/api'
29
30
 
@@ -114,16 +115,33 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
114
115
  schema,
115
116
  clientSession,
116
117
  runtime: effectContext.runtime,
117
- materializeEvent: (eventDecoded, { otelContext, withChangeset }) => {
118
+ materializeEvent: (eventDecoded, { otelContext, withChangeset, materializerHashLeader }) => {
118
119
  const { eventDef, materializer } = getEventDef(schema, eventDecoded.name)
119
120
 
120
- const execArgsArr = getExecArgsFromEvent({
121
+ const execArgsArr = getExecStatementsFromMaterializer({
121
122
  eventDef,
122
123
  materializer,
123
- db: this.sqliteDbWrapper,
124
+ dbState: this.sqliteDbWrapper,
124
125
  event: { decoded: eventDecoded, encoded: undefined },
125
126
  })
126
127
 
128
+ const materializerHash = isDevEnv() ? Option.some(hashMaterializerResults(execArgsArr)) : Option.none()
129
+
130
+ if (
131
+ materializerHashLeader._tag === 'Some' &&
132
+ materializerHash._tag === 'Some' &&
133
+ materializerHashLeader.value !== materializerHash.value
134
+ ) {
135
+ void this.shutdown(
136
+ Cause.fail(
137
+ UnexpectedError.make({
138
+ cause: `Materializer hash mismatch detected for event "${eventDecoded.name}".`,
139
+ note: `Please make sure your event materializer is a pure function without side effects.`,
140
+ }),
141
+ ),
142
+ )
143
+ }
144
+
127
145
  const writeTablesForEvent = new Set<string>()
128
146
 
129
147
  const exec = () => {
@@ -132,7 +150,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
132
150
  bindValues,
133
151
  writeTables = this.sqliteDbWrapper.getTablesUsed(statementSql),
134
152
  } of execArgsArr) {
135
- this.sqliteDbWrapper.execute(statementSql, bindValues, { otelContext, writeTables })
153
+ this.sqliteDbWrapper.cachedExecute(statementSql, bindValues, { otelContext, writeTables })
136
154
 
137
155
  // durationMsTotal += durationMs
138
156
  for (const table of writeTables) {
@@ -151,7 +169,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
151
169
  exec()
152
170
  }
153
171
 
154
- return { writeTables: writeTablesForEvent, sessionChangeset }
172
+ return { writeTables: writeTablesForEvent, sessionChangeset, materializerHash }
155
173
  },
156
174
  rollback: (changeset) => {
157
175
  this.sqliteDbWrapper.rollback(changeset)
@@ -389,7 +407,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
389
407
  options?: { otelContext?: otel.Context; debugRefreshReason?: RefreshReason },
390
408
  ): TResult => {
391
409
  if (typeof query === 'object' && 'query' in query && 'bindValues' in query) {
392
- return this.sqliteDbWrapper.select(query.query, prepareBindValues(query.bindValues, query.query), {
410
+ return this.sqliteDbWrapper.cachedSelect(query.query, prepareBindValues(query.bindValues, query.query), {
393
411
  otelContext: options?.otelContext,
394
412
  }) as any
395
413
  } else if (isQueryBuilder(query)) {
@@ -405,7 +423,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
405
423
 
406
424
  const sqlRes = query.asSql()
407
425
  const schema = getResultSchema(query)
408
- const rawRes = this.sqliteDbWrapper.select(sqlRes.query, sqlRes.bindValues as any as PreparedBindValues, {
426
+ const rawRes = this.sqliteDbWrapper.cachedSelect(sqlRes.query, sqlRes.bindValues as any as PreparedBindValues, {
409
427
  otelContext: options?.otelContext,
410
428
  queriedTables: new Set([query[QueryBuilderAstSymbol].tableDef.sqliteDef.name]),
411
429
  })