@livestore/livestore 0.0.58-dev.6 → 0.0.58-dev.8
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/dist/.tsbuildinfo +1 -1
- package/dist/effect/LiveStore.js +1 -1
- package/dist/effect/LiveStore.js.map +1 -1
- package/dist/react/LiveStoreProvider.js +2 -2
- package/dist/react/LiveStoreProvider.js.map +1 -1
- package/dist/react/useLocalId.d.ts.map +1 -1
- package/dist/react/useLocalId.js +1 -0
- package/dist/react/useLocalId.js.map +1 -1
- package/dist/react/useQuery.d.ts.map +1 -1
- package/dist/react/useQuery.js +1 -0
- package/dist/react/useQuery.js.map +1 -1
- package/dist/react/useRow.test.js +5 -359
- package/dist/react/useRow.test.js.map +1 -1
- package/dist/react/useTemporaryQuery.d.ts.map +1 -1
- package/dist/react/useTemporaryQuery.js +12 -7
- package/dist/react/useTemporaryQuery.js.map +1 -1
- package/dist/react/useTemporaryQuery.test.js +23 -1
- package/dist/react/useTemporaryQuery.test.js.map +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/store-devtools.js +1 -1
- package/dist/store-devtools.js.map +1 -1
- package/dist/store.d.ts +17 -13
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +71 -38
- package/dist/store.js.map +1 -1
- package/dist/utils/dev.d.ts.map +1 -1
- package/dist/utils/dev.js +1 -0
- package/dist/utils/dev.js.map +1 -1
- package/package.json +14 -13
- package/src/ambient.d.ts +3 -0
- package/src/effect/LiveStore.ts +1 -1
- package/src/react/LiveStoreProvider.tsx +2 -2
- package/src/react/__snapshots__/useRow.test.tsx.snap +359 -0
- package/src/react/useLocalId.ts +1 -0
- package/src/react/useQuery.ts +1 -0
- package/src/react/useRow.test.tsx +5 -359
- package/src/react/useTemporaryQuery.test.tsx +44 -2
- package/src/react/useTemporaryQuery.ts +23 -13
- package/src/reactiveQueries/sql.ts +2 -2
- package/src/store-devtools.ts +1 -1
- package/src/store.ts +111 -49
- package/src/utils/dev.ts +1 -0
|
@@ -12,7 +12,7 @@ import * as LiveStoreReact from './index.js'
|
|
|
12
12
|
import type { StackInfo } from './utils/stack-info.js'
|
|
13
13
|
|
|
14
14
|
// NOTE running tests concurrently doesn't work with the default global db graph
|
|
15
|
-
describe
|
|
15
|
+
describe('useRow', () => {
|
|
16
16
|
it('should update the data based on component key', () =>
|
|
17
17
|
Effect.gen(function* () {
|
|
18
18
|
const { wrapper, AppComponentSchema, store, reactivityGraph, makeRenderCount } = yield* makeTodoMvc({
|
|
@@ -184,7 +184,7 @@ describe.concurrent('useRow', () => {
|
|
|
184
184
|
|
|
185
185
|
expect(appRouterRenderCount.val).toBe(2)
|
|
186
186
|
expect(renderResult.getByRole('content').innerHTML).toMatchInlineSnapshot(
|
|
187
|
-
`"{"
|
|
187
|
+
`"{"id":"t1","text":"buy milk","completed":false}"`,
|
|
188
188
|
)
|
|
189
189
|
|
|
190
190
|
expect(renderResult.getByRole('current-id').innerHTML).toMatchInlineSnapshot('"Current Task Id: t1"')
|
|
@@ -334,365 +334,11 @@ describe.concurrent('useRow', () => {
|
|
|
334
334
|
})
|
|
335
335
|
}
|
|
336
336
|
|
|
337
|
+
// TODO improve testing setup so "obsolete" warning is avoided
|
|
337
338
|
if (strictMode) {
|
|
338
|
-
expect(getSimplifiedRootSpan(exporter, mapAttributes)).
|
|
339
|
-
{
|
|
340
|
-
"_name": "test",
|
|
341
|
-
"children": [
|
|
342
|
-
{
|
|
343
|
-
"_name": "livestore.in-memory-db:execute",
|
|
344
|
-
"attributes": {
|
|
345
|
-
"sql.query": "
|
|
346
|
-
PRAGMA page_size=32768;
|
|
347
|
-
PRAGMA cache_size=10000;
|
|
348
|
-
PRAGMA journal_mode='MEMORY'; -- we don't flush to disk before committing a write
|
|
349
|
-
PRAGMA synchronous='OFF';
|
|
350
|
-
PRAGMA temp_store='MEMORY';
|
|
351
|
-
PRAGMA foreign_keys='ON'; -- we want foreign key constraints to be enforced
|
|
352
|
-
",
|
|
353
|
-
},
|
|
354
|
-
},
|
|
355
|
-
{
|
|
356
|
-
"_name": "sql-in-memory-select",
|
|
357
|
-
"attributes": {
|
|
358
|
-
"sql.cached": false,
|
|
359
|
-
"sql.query": "select 1 from UserInfo where id = 'u1'",
|
|
360
|
-
"sql.rowsCount": 0,
|
|
361
|
-
},
|
|
362
|
-
},
|
|
363
|
-
{
|
|
364
|
-
"_name": "sql-in-memory-select",
|
|
365
|
-
"attributes": {
|
|
366
|
-
"sql.cached": false,
|
|
367
|
-
"sql.query": "select 1 from UserInfo where id = 'u2'",
|
|
368
|
-
"sql.rowsCount": 1,
|
|
369
|
-
},
|
|
370
|
-
},
|
|
371
|
-
{
|
|
372
|
-
"_name": "LiveStore:mutations",
|
|
373
|
-
"children": [
|
|
374
|
-
{
|
|
375
|
-
"_name": "LiveStore:mutate",
|
|
376
|
-
"attributes": {
|
|
377
|
-
"livestore.mutateLabel": "mutate",
|
|
378
|
-
},
|
|
379
|
-
"children": [
|
|
380
|
-
{
|
|
381
|
-
"_name": "LiveStore:processWrites",
|
|
382
|
-
"attributes": {
|
|
383
|
-
"livestore.mutateLabel": "mutate",
|
|
384
|
-
},
|
|
385
|
-
"children": [
|
|
386
|
-
{
|
|
387
|
-
"_name": "LiveStore:mutateWithoutRefresh",
|
|
388
|
-
"attributes": {
|
|
389
|
-
"livestore.args": "{
|
|
390
|
-
"sql": "INSERT INTO UserInfo (id, username) VALUES ('u2', 'username_u2')"
|
|
391
|
-
}",
|
|
392
|
-
"livestore.mutation": "livestore.RawSql",
|
|
393
|
-
},
|
|
394
|
-
"children": [
|
|
395
|
-
{
|
|
396
|
-
"_name": "livestore.in-memory-db:execute",
|
|
397
|
-
"attributes": {
|
|
398
|
-
"sql.query": "INSERT INTO UserInfo (id, username) VALUES ('u2', 'username_u2')",
|
|
399
|
-
},
|
|
400
|
-
},
|
|
401
|
-
],
|
|
402
|
-
},
|
|
403
|
-
],
|
|
404
|
-
},
|
|
405
|
-
],
|
|
406
|
-
},
|
|
407
|
-
],
|
|
408
|
-
},
|
|
409
|
-
{
|
|
410
|
-
"_name": "LiveStore:queries",
|
|
411
|
-
"children": [
|
|
412
|
-
{
|
|
413
|
-
"_name": "sql:select * from UserInfo where id = 'u1' limit 1",
|
|
414
|
-
"attributes": {
|
|
415
|
-
"sql.query": "select * from UserInfo where id = 'u1' limit 1",
|
|
416
|
-
"sql.rowsCount": 1,
|
|
417
|
-
},
|
|
418
|
-
"children": [
|
|
419
|
-
{
|
|
420
|
-
"_name": "sql-in-memory-select",
|
|
421
|
-
"attributes": {
|
|
422
|
-
"sql.cached": false,
|
|
423
|
-
"sql.query": "select * from UserInfo where id = 'u1' limit 1",
|
|
424
|
-
"sql.rowsCount": 1,
|
|
425
|
-
},
|
|
426
|
-
},
|
|
427
|
-
],
|
|
428
|
-
},
|
|
429
|
-
{
|
|
430
|
-
"_name": "LiveStore:useRow:UserInfo:u1",
|
|
431
|
-
"attributes": {
|
|
432
|
-
"id": "u1",
|
|
433
|
-
},
|
|
434
|
-
"children": [
|
|
435
|
-
{
|
|
436
|
-
"_name": "LiveStore:mutateWithoutRefresh",
|
|
437
|
-
"attributes": {
|
|
438
|
-
"livestore.args": "{
|
|
439
|
-
"id": "u1"
|
|
440
|
-
}",
|
|
441
|
-
"livestore.mutation": "_Derived_Create_UserInfo",
|
|
442
|
-
},
|
|
443
|
-
"children": [
|
|
444
|
-
{
|
|
445
|
-
"_name": "livestore.in-memory-db:execute",
|
|
446
|
-
"attributes": {
|
|
447
|
-
"sql.query": "INSERT INTO UserInfo (username, text, id) VALUES ($username, $text, $id)",
|
|
448
|
-
},
|
|
449
|
-
},
|
|
450
|
-
],
|
|
451
|
-
},
|
|
452
|
-
{
|
|
453
|
-
"_name": "LiveStore:useQuery:sql(rowQuery:query:UserInfo:u1)",
|
|
454
|
-
"attributes": {
|
|
455
|
-
"label": "sql(rowQuery:query:UserInfo:u1)",
|
|
456
|
-
"stackInfo": "{"frames":[{"name":"renderHook.wrapper","filePath":"__REPLACED_FOR_SNAPSHOT__"},{"name":"useRow","filePath":"__REPLACED_FOR_SNAPSHOT__"}]}",
|
|
457
|
-
},
|
|
458
|
-
"children": [
|
|
459
|
-
{
|
|
460
|
-
"_name": "sql:select * from UserInfo where id = 'u1' limit 1",
|
|
461
|
-
"attributes": {
|
|
462
|
-
"sql.query": "select * from UserInfo where id = 'u1' limit 1",
|
|
463
|
-
"sql.rowsCount": 1,
|
|
464
|
-
},
|
|
465
|
-
"children": [
|
|
466
|
-
{
|
|
467
|
-
"_name": "sql-in-memory-select",
|
|
468
|
-
"attributes": {
|
|
469
|
-
"sql.cached": false,
|
|
470
|
-
"sql.query": "select * from UserInfo where id = 'u1' limit 1",
|
|
471
|
-
"sql.rowsCount": 1,
|
|
472
|
-
},
|
|
473
|
-
},
|
|
474
|
-
],
|
|
475
|
-
},
|
|
476
|
-
{
|
|
477
|
-
"_name": "LiveStore.subscribe",
|
|
478
|
-
"attributes": {
|
|
479
|
-
"label": "sql(rowQuery:query:UserInfo:u1)",
|
|
480
|
-
"queryLabel": "sql(rowQuery:query:UserInfo:u1)",
|
|
481
|
-
},
|
|
482
|
-
},
|
|
483
|
-
{
|
|
484
|
-
"_name": "LiveStore.subscribe",
|
|
485
|
-
"attributes": {
|
|
486
|
-
"label": "sql(rowQuery:query:UserInfo:u1)",
|
|
487
|
-
"queryLabel": "sql(rowQuery:query:UserInfo:u1)",
|
|
488
|
-
},
|
|
489
|
-
},
|
|
490
|
-
],
|
|
491
|
-
},
|
|
492
|
-
],
|
|
493
|
-
},
|
|
494
|
-
],
|
|
495
|
-
},
|
|
496
|
-
],
|
|
497
|
-
}
|
|
498
|
-
`)
|
|
499
|
-
// Below: Strict mode disabled
|
|
339
|
+
expect(getSimplifiedRootSpan(exporter, mapAttributes)).toMatchSnapshot('strictMode=true')
|
|
500
340
|
} else {
|
|
501
|
-
expect(getSimplifiedRootSpan(exporter, mapAttributes)).
|
|
502
|
-
{
|
|
503
|
-
"_name": "test",
|
|
504
|
-
"children": [
|
|
505
|
-
{
|
|
506
|
-
"_name": "livestore.in-memory-db:execute",
|
|
507
|
-
"attributes": {
|
|
508
|
-
"sql.query": "
|
|
509
|
-
PRAGMA page_size=32768;
|
|
510
|
-
PRAGMA cache_size=10000;
|
|
511
|
-
PRAGMA journal_mode='MEMORY'; -- we don't flush to disk before committing a write
|
|
512
|
-
PRAGMA synchronous='OFF';
|
|
513
|
-
PRAGMA temp_store='MEMORY';
|
|
514
|
-
PRAGMA foreign_keys='ON'; -- we want foreign key constraints to be enforced
|
|
515
|
-
",
|
|
516
|
-
},
|
|
517
|
-
},
|
|
518
|
-
{
|
|
519
|
-
"_name": "sql-in-memory-select",
|
|
520
|
-
"attributes": {
|
|
521
|
-
"sql.cached": false,
|
|
522
|
-
"sql.query": "select 1 from UserInfo where id = 'u1'",
|
|
523
|
-
"sql.rowsCount": 0,
|
|
524
|
-
},
|
|
525
|
-
},
|
|
526
|
-
{
|
|
527
|
-
"_name": "sql-in-memory-select",
|
|
528
|
-
"attributes": {
|
|
529
|
-
"sql.cached": false,
|
|
530
|
-
"sql.query": "select 1 from UserInfo where id = 'u2'",
|
|
531
|
-
"sql.rowsCount": 1,
|
|
532
|
-
},
|
|
533
|
-
},
|
|
534
|
-
{
|
|
535
|
-
"_name": "LiveStore:mutations",
|
|
536
|
-
"children": [
|
|
537
|
-
{
|
|
538
|
-
"_name": "LiveStore:mutate",
|
|
539
|
-
"attributes": {
|
|
540
|
-
"livestore.mutateLabel": "mutate",
|
|
541
|
-
},
|
|
542
|
-
"children": [
|
|
543
|
-
{
|
|
544
|
-
"_name": "LiveStore:processWrites",
|
|
545
|
-
"attributes": {
|
|
546
|
-
"livestore.mutateLabel": "mutate",
|
|
547
|
-
},
|
|
548
|
-
"children": [
|
|
549
|
-
{
|
|
550
|
-
"_name": "LiveStore:mutateWithoutRefresh",
|
|
551
|
-
"attributes": {
|
|
552
|
-
"livestore.args": "{
|
|
553
|
-
"sql": "INSERT INTO UserInfo (id, username) VALUES ('u2', 'username_u2')"
|
|
554
|
-
}",
|
|
555
|
-
"livestore.mutation": "livestore.RawSql",
|
|
556
|
-
},
|
|
557
|
-
"children": [
|
|
558
|
-
{
|
|
559
|
-
"_name": "livestore.in-memory-db:execute",
|
|
560
|
-
"attributes": {
|
|
561
|
-
"sql.query": "INSERT INTO UserInfo (id, username) VALUES ('u2', 'username_u2')",
|
|
562
|
-
},
|
|
563
|
-
},
|
|
564
|
-
],
|
|
565
|
-
},
|
|
566
|
-
],
|
|
567
|
-
},
|
|
568
|
-
],
|
|
569
|
-
},
|
|
570
|
-
],
|
|
571
|
-
},
|
|
572
|
-
{
|
|
573
|
-
"_name": "LiveStore:queries",
|
|
574
|
-
"children": [
|
|
575
|
-
{
|
|
576
|
-
"_name": "sql:select * from UserInfo where id = 'u1' limit 1",
|
|
577
|
-
"attributes": {
|
|
578
|
-
"sql.query": "select * from UserInfo where id = 'u1' limit 1",
|
|
579
|
-
"sql.rowsCount": 1,
|
|
580
|
-
},
|
|
581
|
-
"children": [
|
|
582
|
-
{
|
|
583
|
-
"_name": "sql-in-memory-select",
|
|
584
|
-
"attributes": {
|
|
585
|
-
"sql.cached": false,
|
|
586
|
-
"sql.query": "select * from UserInfo where id = 'u1' limit 1",
|
|
587
|
-
"sql.rowsCount": 1,
|
|
588
|
-
},
|
|
589
|
-
},
|
|
590
|
-
],
|
|
591
|
-
},
|
|
592
|
-
{
|
|
593
|
-
"_name": "LiveStore:useRow:UserInfo:u1",
|
|
594
|
-
"attributes": {
|
|
595
|
-
"id": "u1",
|
|
596
|
-
},
|
|
597
|
-
"children": [
|
|
598
|
-
{
|
|
599
|
-
"_name": "LiveStore:mutateWithoutRefresh",
|
|
600
|
-
"attributes": {
|
|
601
|
-
"livestore.args": "{
|
|
602
|
-
"id": "u1"
|
|
603
|
-
}",
|
|
604
|
-
"livestore.mutation": "_Derived_Create_UserInfo",
|
|
605
|
-
},
|
|
606
|
-
"children": [
|
|
607
|
-
{
|
|
608
|
-
"_name": "livestore.in-memory-db:execute",
|
|
609
|
-
"attributes": {
|
|
610
|
-
"sql.query": "INSERT INTO UserInfo (username, text, id) VALUES ($username, $text, $id)",
|
|
611
|
-
},
|
|
612
|
-
},
|
|
613
|
-
],
|
|
614
|
-
},
|
|
615
|
-
{
|
|
616
|
-
"_name": "LiveStore:useQuery:sql(rowQuery:query:UserInfo:u1)",
|
|
617
|
-
"attributes": {
|
|
618
|
-
"label": "sql(rowQuery:query:UserInfo:u1)",
|
|
619
|
-
"stackInfo": "{"frames":[{"name":"renderHook.wrapper","filePath":"__REPLACED_FOR_SNAPSHOT__"},{"name":"useRow","filePath":"__REPLACED_FOR_SNAPSHOT__"}]}",
|
|
620
|
-
},
|
|
621
|
-
"children": [
|
|
622
|
-
{
|
|
623
|
-
"_name": "sql:select * from UserInfo where id = 'u1' limit 1",
|
|
624
|
-
"attributes": {
|
|
625
|
-
"sql.query": "select * from UserInfo where id = 'u1' limit 1",
|
|
626
|
-
"sql.rowsCount": 1,
|
|
627
|
-
},
|
|
628
|
-
"children": [
|
|
629
|
-
{
|
|
630
|
-
"_name": "sql-in-memory-select",
|
|
631
|
-
"attributes": {
|
|
632
|
-
"sql.cached": false,
|
|
633
|
-
"sql.query": "select * from UserInfo where id = 'u1' limit 1",
|
|
634
|
-
"sql.rowsCount": 1,
|
|
635
|
-
},
|
|
636
|
-
},
|
|
637
|
-
],
|
|
638
|
-
},
|
|
639
|
-
{
|
|
640
|
-
"_name": "LiveStore.subscribe",
|
|
641
|
-
"attributes": {
|
|
642
|
-
"label": "sql(rowQuery:query:UserInfo:u1)",
|
|
643
|
-
"queryLabel": "sql(rowQuery:query:UserInfo:u1)",
|
|
644
|
-
},
|
|
645
|
-
},
|
|
646
|
-
],
|
|
647
|
-
},
|
|
648
|
-
],
|
|
649
|
-
},
|
|
650
|
-
{
|
|
651
|
-
"_name": "LiveStore:useRow:UserInfo:u2",
|
|
652
|
-
"attributes": {
|
|
653
|
-
"id": "u2",
|
|
654
|
-
},
|
|
655
|
-
"children": [
|
|
656
|
-
{
|
|
657
|
-
"_name": "LiveStore:useQuery:sql(rowQuery:query:UserInfo:u2)",
|
|
658
|
-
"attributes": {
|
|
659
|
-
"label": "sql(rowQuery:query:UserInfo:u2)",
|
|
660
|
-
"stackInfo": "{"frames":[{"name":"renderHook.wrapper","filePath":"__REPLACED_FOR_SNAPSHOT__"},{"name":"useRow","filePath":"__REPLACED_FOR_SNAPSHOT__"}]}",
|
|
661
|
-
},
|
|
662
|
-
"children": [
|
|
663
|
-
{
|
|
664
|
-
"_name": "sql:select * from UserInfo where id = 'u2' limit 1",
|
|
665
|
-
"attributes": {
|
|
666
|
-
"sql.query": "select * from UserInfo where id = 'u2' limit 1",
|
|
667
|
-
"sql.rowsCount": 1,
|
|
668
|
-
},
|
|
669
|
-
"children": [
|
|
670
|
-
{
|
|
671
|
-
"_name": "sql-in-memory-select",
|
|
672
|
-
"attributes": {
|
|
673
|
-
"sql.cached": false,
|
|
674
|
-
"sql.query": "select * from UserInfo where id = 'u2' limit 1",
|
|
675
|
-
"sql.rowsCount": 1,
|
|
676
|
-
},
|
|
677
|
-
},
|
|
678
|
-
],
|
|
679
|
-
},
|
|
680
|
-
{
|
|
681
|
-
"_name": "LiveStore.subscribe",
|
|
682
|
-
"attributes": {
|
|
683
|
-
"label": "sql(rowQuery:query:UserInfo:u2)",
|
|
684
|
-
"queryLabel": "sql(rowQuery:query:UserInfo:u2)",
|
|
685
|
-
},
|
|
686
|
-
},
|
|
687
|
-
],
|
|
688
|
-
},
|
|
689
|
-
],
|
|
690
|
-
},
|
|
691
|
-
],
|
|
692
|
-
},
|
|
693
|
-
],
|
|
694
|
-
}
|
|
695
|
-
`)
|
|
341
|
+
expect(getSimplifiedRootSpan(exporter, mapAttributes)).toMatchSnapshot('strictMode=false')
|
|
696
342
|
}
|
|
697
343
|
})
|
|
698
344
|
})
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { Effect, Schema } from '@livestore/utils/effect'
|
|
2
|
-
import { renderHook } from '@testing-library/react'
|
|
2
|
+
import { render, renderHook } from '@testing-library/react'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
// @ts-expect-error no types
|
|
5
|
+
import * as ReactWindow from 'react-window'
|
|
3
6
|
import { describe, expect, it } from 'vitest'
|
|
4
7
|
|
|
5
8
|
import { makeTodoMvc, tables, todos } from '../__tests__/react/fixture.js'
|
|
6
|
-
import
|
|
9
|
+
import * as LiveStore from '../index.js'
|
|
7
10
|
import { querySQL } from '../reactiveQueries/sql.js'
|
|
8
11
|
import * as LiveStoreReact from './index.js'
|
|
9
12
|
|
|
@@ -53,4 +56,43 @@ describe('useTemporaryQuery', () => {
|
|
|
53
56
|
|
|
54
57
|
expect(queryMap.get('t2')!.runs).toBe(1)
|
|
55
58
|
}).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.runPromise))
|
|
59
|
+
|
|
60
|
+
// NOTE this test covers some special react lifecyle paths which I couldn't easily reproduce without react-window
|
|
61
|
+
// it basically causes a "query swap" in the `useMemo` and both a `useEffect` cleanup call.
|
|
62
|
+
// To handle this properly we introduced the `_tag: 'destroyed'` state in the `spanAlreadyStartedCache`.
|
|
63
|
+
it('should work for a list with react-window', () =>
|
|
64
|
+
Effect.gen(function* () {
|
|
65
|
+
const { wrapper } = yield* makeTodoMvc()
|
|
66
|
+
|
|
67
|
+
const ListWrapper: React.FC<{ numItems: number }> = ({ numItems }) => {
|
|
68
|
+
return (
|
|
69
|
+
<ReactWindow.FixedSizeList
|
|
70
|
+
height={100}
|
|
71
|
+
width={100}
|
|
72
|
+
itemSize={10}
|
|
73
|
+
itemCount={numItems}
|
|
74
|
+
itemData={Array.from({ length: numItems }, (_, i) => i).reverse()}
|
|
75
|
+
>
|
|
76
|
+
{ListItem}
|
|
77
|
+
</ReactWindow.FixedSizeList>
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const ListItem: React.FC<{ data: ReadonlyArray<number>; index: number }> = ({ data: ids, index }) => {
|
|
82
|
+
const id = ids[index]!
|
|
83
|
+
const res = LiveStoreReact.useTemporaryQuery(
|
|
84
|
+
() => LiveStore.computed(() => id, { label: `ListItem.${id}` }),
|
|
85
|
+
id,
|
|
86
|
+
)
|
|
87
|
+
return <div role="listitem">{res}</div>
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const renderResult = render(<ListWrapper numItems={1} />, { wrapper })
|
|
91
|
+
|
|
92
|
+
expect(renderResult.container.textContent).toBe('0')
|
|
93
|
+
|
|
94
|
+
renderResult.rerender(<ListWrapper numItems={2} />)
|
|
95
|
+
|
|
96
|
+
expect(renderResult.container.textContent).toBe('10')
|
|
97
|
+
}).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.runPromise))
|
|
56
98
|
})
|
|
@@ -12,12 +12,16 @@ import { useQueryRef } from './useQuery.js'
|
|
|
12
12
|
// Please definitely open an issue if you see or run into any problems with this approach!
|
|
13
13
|
const cache = new Map<
|
|
14
14
|
string,
|
|
15
|
-
{
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
| {
|
|
16
|
+
_tag: 'active'
|
|
17
|
+
rc: number
|
|
18
|
+
query$: LiveQuery<any, any>
|
|
19
|
+
span: otel.Span
|
|
20
|
+
otelContext: otel.Context
|
|
21
|
+
}
|
|
22
|
+
| {
|
|
23
|
+
_tag: 'destroyed'
|
|
24
|
+
}
|
|
21
25
|
>()
|
|
22
26
|
|
|
23
27
|
export type DepKey = string | number | ReadonlyArray<string | number>
|
|
@@ -60,22 +64,24 @@ export const useMakeTemporaryQuery = <TResult, TQueryInfo extends QueryInfo>(
|
|
|
60
64
|
|
|
61
65
|
const { query$, otelContext } = React.useMemo(() => {
|
|
62
66
|
if (fullKeyRef.current !== undefined && fullKeyRef.current !== fullKey) {
|
|
63
|
-
// console.debug('fullKey changed,
|
|
67
|
+
// console.debug('fullKey changed', 'prev', fullKeyRef.current.split('-')[0]!, '-> new', fullKey.split('-')[0]!)
|
|
64
68
|
|
|
65
69
|
const cachedItem = cache.get(fullKeyRef.current)
|
|
66
|
-
if (cachedItem !== undefined) {
|
|
70
|
+
if (cachedItem !== undefined && cachedItem._tag === 'active') {
|
|
67
71
|
cachedItem.rc--
|
|
68
72
|
|
|
69
73
|
if (cachedItem.rc === 0) {
|
|
74
|
+
// console.debug('rc=0-changed', cachedItem.query$.id, cachedItem.query$.label)
|
|
70
75
|
cachedItem.query$.destroy()
|
|
71
76
|
cachedItem.span.end()
|
|
72
|
-
cache.
|
|
77
|
+
cache.set(fullKeyRef.current, { _tag: 'destroyed' })
|
|
73
78
|
}
|
|
74
79
|
}
|
|
75
80
|
}
|
|
76
81
|
|
|
77
82
|
const cachedItem = cache.get(fullKey)
|
|
78
|
-
if (cachedItem !== undefined) {
|
|
83
|
+
if (cachedItem !== undefined && cachedItem._tag === 'active') {
|
|
84
|
+
// console.debug('rc++', cachedItem.query$.id, cachedItem.query$.label)
|
|
79
85
|
cachedItem.rc++
|
|
80
86
|
|
|
81
87
|
return cachedItem
|
|
@@ -93,7 +99,7 @@ export const useMakeTemporaryQuery = <TResult, TQueryInfo extends QueryInfo>(
|
|
|
93
99
|
|
|
94
100
|
const query$ = makeQuery(otelContext)
|
|
95
101
|
|
|
96
|
-
cache.set(fullKey, { rc: 1, query$, span, otelContext })
|
|
102
|
+
cache.set(fullKey, { _tag: 'active', rc: 1, query$, span, otelContext })
|
|
97
103
|
|
|
98
104
|
return { query$, otelContext }
|
|
99
105
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -103,19 +109,23 @@ export const useMakeTemporaryQuery = <TResult, TQueryInfo extends QueryInfo>(
|
|
|
103
109
|
|
|
104
110
|
React.useEffect(() => {
|
|
105
111
|
return () => {
|
|
112
|
+
const fullKey = fullKeyRef.current!
|
|
106
113
|
const cachedItem = cache.get(fullKey)
|
|
107
114
|
// NOTE in case the fullKey changed then the query was already destroyed in the useMemo above
|
|
108
|
-
if (cachedItem === undefined) return
|
|
115
|
+
if (cachedItem === undefined || cachedItem._tag === 'destroyed') return
|
|
116
|
+
|
|
117
|
+
// console.debug('rc--', cachedItem.query$.id, cachedItem.query$.label)
|
|
109
118
|
|
|
110
119
|
cachedItem.rc--
|
|
111
120
|
|
|
112
121
|
if (cachedItem.rc === 0) {
|
|
122
|
+
// console.debug('rc=0', cachedItem.query$.id, cachedItem.query$.label)
|
|
113
123
|
cachedItem.query$.destroy()
|
|
114
124
|
cachedItem.span.end()
|
|
115
125
|
cache.delete(fullKey)
|
|
116
126
|
}
|
|
117
127
|
}
|
|
118
|
-
}, [
|
|
128
|
+
}, [])
|
|
119
129
|
|
|
120
130
|
return { query$, otelContext }
|
|
121
131
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Bindable, prepareBindValues, type QueryInfo, type QueryInfoNone } from '@livestore/common'
|
|
2
2
|
import { shouldNeverHappen } from '@livestore/utils'
|
|
3
|
-
import { Schema,
|
|
3
|
+
import { Schema, TreeFormatter } from '@livestore/utils/effect'
|
|
4
4
|
import * as otel from '@opentelemetry/api'
|
|
5
5
|
|
|
6
6
|
import { globalReactivityGraph } from '../global-state.js'
|
|
@@ -124,7 +124,7 @@ export class LiveStoreSQLQuery<
|
|
|
124
124
|
|
|
125
125
|
const queriedTablesRef = { current: queriedTables }
|
|
126
126
|
|
|
127
|
-
const schemaEqual =
|
|
127
|
+
const schemaEqual = Schema.equivalence(schema)
|
|
128
128
|
// TODO also support derived equality for `map` (probably will depend on having an easy way to transform a schema without an `encode` step)
|
|
129
129
|
// This would mean dropping the `map` option
|
|
130
130
|
const equal =
|
package/src/store-devtools.ts
CHANGED
|
@@ -56,7 +56,7 @@ export const connectDevtoolsToStore = ({
|
|
|
56
56
|
|
|
57
57
|
const requestId = decodedMessage.requestId
|
|
58
58
|
|
|
59
|
-
const requestIdleCallback =
|
|
59
|
+
const requestIdleCallback = globalThis.requestIdleCallback ?? ((cb: () => void) => cb())
|
|
60
60
|
|
|
61
61
|
switch (decodedMessage._tag) {
|
|
62
62
|
case 'LSD.ReactivityGraphSubscribe': {
|