@livestore/livestore 0.3.0-dev.34 → 0.3.0-dev.37

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.
@@ -0,0 +1,25 @@
1
+ import { Effect } from '@livestore/utils/effect'
2
+ import { Vitest } from '@livestore/utils-dev/node-vitest'
3
+ import { expect } from 'vitest'
4
+
5
+ import { makeTodoMvc } from '../utils/tests/fixture.js'
6
+ import { computed } from './computed.js'
7
+ import { signal } from './signal.js'
8
+
9
+ Vitest.describe('signal', () => {
10
+ Vitest.scopedLive('should be able to create a signal', () =>
11
+ Effect.gen(function* () {
12
+ const num$ = signal(0, { label: 'num$' })
13
+
14
+ const duplicated$ = computed((get) => get(num$) * 2, { label: 'duplicated$' })
15
+
16
+ const store = yield* makeTodoMvc({})
17
+
18
+ expect(store.query(duplicated$)).toBe(0)
19
+
20
+ store.setSignal(num$, 1)
21
+
22
+ expect(store.query(duplicated$)).toBe(2)
23
+ }),
24
+ )
25
+ })
@@ -2,27 +2,25 @@ import { nanoid } from '@livestore/utils/nanoid'
2
2
 
3
3
  import type * as RG from '../reactive.js'
4
4
  import type { RefreshReason } from '../store/store-types.js'
5
- import type { ILiveQueryRef, ILiveQueryRefDef, ReactivityGraph, ReactivityGraphContext } from './base-class.js'
5
+ import type { ISignal, ReactivityGraph, ReactivityGraphContext, SignalDef } from './base-class.js'
6
6
  import { withRCMap } from './base-class.js'
7
7
 
8
- // TODO rename to `signal`
9
-
10
- export const makeRef = <T>(
8
+ export const signal = <T>(
11
9
  defaultValue: T,
12
10
  options?: {
13
11
  label?: string
14
12
  },
15
- ): ILiveQueryRefDef<T> => {
13
+ ): SignalDef<T> => {
16
14
  const id = nanoid()
17
15
  return {
18
- _tag: 'live-ref-def',
16
+ _tag: 'signal-def',
19
17
  defaultValue,
20
- make: withRCMap(id, (ctx) => new LiveQueryRef(defaultValue, ctx.reactivityGraph.deref()!, options)),
18
+ make: withRCMap(id, (ctx) => new Signal(defaultValue, ctx.reactivityGraph.deref()!, options)),
21
19
  }
22
20
  }
23
21
 
24
- export class LiveQueryRef<T> implements ILiveQueryRef<T> {
25
- _tag = 'live-ref' as const
22
+ export class Signal<T> implements ISignal<T> {
23
+ _tag = 'signal' as const
26
24
  readonly ref: RG.Ref<T, ReactivityGraphContext, RefreshReason>
27
25
 
28
26
  constructor(
package/src/mod.ts CHANGED
@@ -13,7 +13,7 @@ export {
13
13
 
14
14
  export { SqliteDbWrapper, emptyDebugInfo } from './SqliteDbWrapper.js'
15
15
 
16
- export { queryDb, computed, makeRef, type LiveQuery, type LiveQueryDef } from './live-queries/mod.js'
16
+ export { queryDb, computed, signal, type LiveQuery, type LiveQueryDef } from './live-queries/mod.js'
17
17
 
18
18
  export * from '@livestore/common/schema'
19
19
  export {
@@ -28,11 +28,11 @@ import { nanoid } from '@livestore/utils/nanoid'
28
28
  import * as otel from '@opentelemetry/api'
29
29
 
30
30
  import type {
31
- ILiveQueryRefDef,
32
31
  LiveQuery,
33
32
  LiveQueryDef,
34
33
  ReactivityGraph,
35
34
  ReactivityGraphContext,
35
+ SignalDef,
36
36
  } from '../live-queries/base-class.js'
37
37
  import { makeReactivityGraph } from '../live-queries/base-class.js'
38
38
  import { makeExecBeforeFirstRun } from '../live-queries/client-document-get-query.js'
@@ -108,10 +108,12 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
108
108
  clientSession,
109
109
  runtime: effectContext.runtime,
110
110
  materializeEvent: (eventDecoded, { otelContext, withChangeset }) => {
111
- const eventDef = getEventDef(schema, eventDecoded.name)
111
+ const { eventDef, materializer } = getEventDef(schema, eventDecoded.name)
112
112
 
113
113
  const execArgsArr = getExecArgsFromEvent({
114
114
  eventDef,
115
+ materializer,
116
+ db: this.sqliteDbWrapper,
115
117
  event: { decoded: eventDecoded, encoded: undefined },
116
118
  })
117
119
 
@@ -203,7 +205,13 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
203
205
  .map((_) => [_.label!.slice('tableRef:'.length), _] as const),
204
206
  )
205
207
  for (const tableName of allTableNames) {
206
- this.tableRefs[tableName] = existingTableRefs.get(tableName) ?? this.makeTableRef(tableName)
208
+ this.tableRefs[tableName] =
209
+ existingTableRefs.get(tableName) ??
210
+ this.reactivityGraph.makeRef(null, {
211
+ equal: () => false,
212
+ label: `tableRef:${tableName}`,
213
+ meta: { liveStoreRefType: 'table' },
214
+ })
207
215
  }
208
216
 
209
217
  this.boot = Effect.gen(this, function* () {
@@ -402,23 +410,18 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
402
410
  }
403
411
  }
404
412
 
405
- atom = (): TODO => {}
406
-
407
- // makeLive: {
408
- // <T>(def: LiveQueryDef<T, any>): LiveQuery<T, any>
409
- // <T>(def: ILiveQueryRefDef<T>): ILiveQueryRef<T>
410
- // } = (def: any) => {
411
- // if (def._tag === 'live-ref-def') {
412
- // return (def as ILiveQueryRefDef<any>).make(this.reactivityGraph.context!)
413
- // } else {
414
- // return (def as LiveQueryDef<any, any>).make(this.reactivityGraph.context!) as any
415
- // }
416
- // }
417
-
418
- setRef = <T>(refDef: ILiveQueryRefDef<T>, value: T): void => {
419
- const ref = refDef.make(this.reactivityGraph.context!)
420
- ref.value.set(value)
421
- ref.deref()
413
+ setSignal = <T>(signalDef: SignalDef<T>, value: T): void => {
414
+ const signalRef = signalDef.make(this.reactivityGraph.context!)
415
+ signalRef.value.set(value)
416
+
417
+ // The current implementation of signals i.e. the separation into `signal-def` and `signal`
418
+ // can lead to a situation where a reffed signal is immediately de-reffed when calling `store.setSignal`,
419
+ // in case there is nothing else holding a reference to the signal which leads to the set value being "lost".
420
+ // To avoid this, we don't deref the signal here if this set call is the only reference to the signal.
421
+ // Hopefully this won't lead to any issues in the future. 🤞
422
+ if (signalRef.rc > 1) {
423
+ signalRef.deref()
424
+ }
422
425
  }
423
426
 
424
427
  // #region commit
@@ -593,12 +596,13 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
593
596
  )
594
597
  }
595
598
 
596
- private makeTableRef = (tableName: string) =>
597
- this.reactivityGraph.makeRef(null, {
598
- equal: () => false,
599
- label: `tableRef:${tableName}`,
600
- meta: { liveStoreRefType: 'table' },
601
- })
599
+ /**
600
+ * Shuts down the store and closes the client session.
601
+ *
602
+ * This is called automatically when the store was created using the React or Effect API.
603
+ */
604
+ shutdown = (cause?: Cause.Cause<UnexpectedError>) =>
605
+ this.clientSession.shutdown(cause ?? Cause.fail(IntentionalShutdownCause.make({ reason: 'manual' })))
602
606
 
603
607
  /**
604
608
  * Helper methods useful during development
@@ -638,9 +642,6 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
638
642
  }).pipe(this.runEffectFork)
639
643
  },
640
644
 
641
- shutdown: (cause?: Cause.Cause<UnexpectedError>) =>
642
- this.clientSession.shutdown(cause ?? Cause.fail(IntentionalShutdownCause.make({ reason: 'manual' }))),
643
-
644
645
  version: liveStoreVersion,
645
646
  }
646
647