@rocicorp/zero 0.11.2025011402 → 0.11.2025011801
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/out/{chunk-AII6TS5B.js → chunk-QV5ZN4MA.js} +635 -1834
- package/out/chunk-QV5ZN4MA.js.map +7 -0
- package/out/react.js.map +2 -2
- package/out/shared/src/btree-set.d.ts +34 -0
- package/out/shared/src/btree-set.d.ts.map +1 -0
- package/out/shared/src/btree-set.js +528 -0
- package/out/shared/src/btree-set.js.map +1 -0
- package/out/shared/src/expand.d.ts +3 -0
- package/out/shared/src/expand.d.ts.map +1 -1
- package/out/solid.js +7 -2
- package/out/solid.js.map +2 -2
- package/out/zero-advanced/src/mod.d.ts +1 -1
- package/out/zero-advanced/src/mod.d.ts.map +1 -1
- package/out/zero-cache/src/auth/load-schema.d.ts +1 -1
- package/out/zero-cache/src/auth/load-schema.d.ts.map +1 -1
- package/out/zero-cache/src/auth/write-authorizer.d.ts +1 -1
- package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
- package/out/zero-cache/src/auth/write-authorizer.js +3 -6
- package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
- package/out/zero-cache/src/db/lite-tables.d.ts +14 -1
- package/out/zero-cache/src/db/lite-tables.d.ts.map +1 -1
- package/out/zero-cache/src/db/lite-tables.js +89 -6
- package/out/zero-cache/src/db/lite-tables.js.map +1 -1
- package/out/zero-cache/src/db/pg-to-lite.d.ts.map +1 -1
- package/out/zero-cache/src/db/pg-to-lite.js +3 -1
- package/out/zero-cache/src/db/pg-to-lite.js.map +1 -1
- package/out/zero-cache/src/db/postgres-replica-identity-enum.d.ts +9 -0
- package/out/zero-cache/src/db/postgres-replica-identity-enum.d.ts.map +1 -0
- package/out/zero-cache/src/db/postgres-replica-identity-enum.js +7 -0
- package/out/zero-cache/src/db/postgres-replica-identity-enum.js.map +1 -0
- package/out/zero-cache/src/db/specs.d.ts +39 -10
- package/out/zero-cache/src/db/specs.d.ts.map +1 -1
- package/out/zero-cache/src/db/specs.js +8 -1
- package/out/zero-cache/src/db/specs.js.map +1 -1
- package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js +1 -1
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/server/life-cycle.d.ts +2 -2
- package/out/zero-cache/src/server/life-cycle.d.ts.map +1 -1
- package/out/zero-cache/src/server/life-cycle.js +12 -3
- package/out/zero-cache/src/server/life-cycle.js.map +1 -1
- package/out/zero-cache/src/server/main.d.ts.map +1 -1
- package/out/zero-cache/src/server/main.js +11 -6
- package/out/zero-cache/src/server/main.js.map +1 -1
- package/out/zero-cache/src/server/multi/config.d.ts +14 -14
- package/out/zero-cache/src/server/multi/config.d.ts.map +1 -1
- package/out/zero-cache/src/server/multi/config.js +24 -2
- package/out/zero-cache/src/server/multi/config.js.map +1 -1
- package/out/zero-cache/src/server/multi/main.d.ts.map +1 -1
- package/out/zero-cache/src/server/multi/main.js +28 -8
- package/out/zero-cache/src/server/multi/main.js.map +1 -1
- package/out/zero-cache/src/server/multi/tenant-dispatcher.d.ts +1 -1
- package/out/zero-cache/src/server/multi/tenant-dispatcher.d.ts.map +1 -1
- package/out/zero-cache/src/server/multi/tenant-dispatcher.js +15 -3
- package/out/zero-cache/src/server/multi/tenant-dispatcher.js.map +1 -1
- package/out/zero-cache/src/server/replicator.js +2 -3
- package/out/zero-cache/src/server/replicator.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts +4 -4
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.js +50 -32
- package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts +45 -25
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.js +6 -28
- package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts +18 -10
- package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/published.js +14 -7
- package/out/zero-cache/src/services/change-source/pg/schema/published.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts +7 -4
- package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js +29 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/validation.d.ts +2 -2
- package/out/zero-cache/src/services/change-source/pg/schema/validation.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/validation.js +8 -4
- package/out/zero-cache/src/services/change-source/pg/schema/validation.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/sync-schema.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/sync-schema.js +1 -0
- package/out/zero-cache/src/services/change-source/pg/sync-schema.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts +10 -10
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +17 -15
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.js +2 -1
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/mod.d.ts +1 -0
- package/out/zero-cache/src/services/change-source/protocol/current/mod.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/mod.js +1 -0
- package/out/zero-cache/src/services/change-source/protocol/current/mod.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/status.d.ts +38 -0
- package/out/zero-cache/src/services/change-source/protocol/current/status.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-source/protocol/current/status.js +14 -0
- package/out/zero-cache/src/services/change-source/protocol/current/status.js.map +1 -0
- package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts +3 -13
- package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/upstream.js +3 -10
- package/out/zero-cache/src/services/change-source/protocol/current/upstream.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +7 -3
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +30 -24
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +6 -4
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +4 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +5 -5
- package/out/zero-cache/src/services/change-streamer/storer.d.ts +3 -1
- package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.js +18 -10
- package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
- package/out/zero-cache/src/services/dispatcher/websocket-handoff.d.ts.map +1 -1
- package/out/zero-cache/src/services/dispatcher/websocket-handoff.js +2 -16
- package/out/zero-cache/src/services/dispatcher/websocket-handoff.js.map +1 -1
- package/out/zero-cache/src/services/http-service.d.ts +1 -1
- package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
- package/out/zero-cache/src/services/http-service.js +1 -0
- package/out/zero-cache/src/services/http-service.js.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.js +6 -2
- package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.d.ts +1 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.js +15 -5
- package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
- package/out/zero-cache/src/services/replicator/replicator.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/replicator.js +4 -2
- package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.js +20 -51
- package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +0 -5
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +18 -35
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +3 -3
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
- package/out/zero-cache/src/types/processes.d.ts.map +1 -1
- package/out/zero-cache/src/types/processes.js +17 -2
- package/out/zero-cache/src/types/processes.js.map +1 -1
- package/out/zero-cache/src/types/row-key.d.ts.map +1 -1
- package/out/zero-cache/src/types/row-key.js +7 -1
- package/out/zero-cache/src/types/row-key.js.map +1 -1
- package/out/zero-cache/src/types/ws.d.ts +4 -0
- package/out/zero-cache/src/types/ws.d.ts.map +1 -0
- package/out/zero-cache/src/types/ws.js +19 -0
- package/out/zero-cache/src/types/ws.js.map +1 -0
- package/out/zero-client/src/client/context.d.ts.map +1 -1
- package/out/zero-client/src/client/crud.d.ts +3 -4
- package/out/zero-client/src/client/crud.d.ts.map +1 -1
- package/out/zero-client/src/client/keys.d.ts +2 -2
- package/out/zero-client/src/client/keys.d.ts.map +1 -1
- package/out/zero-client/src/client/zero-poke-handler.d.ts +3 -3
- package/out/zero-client/src/client/zero-poke-handler.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.d.ts +1 -1
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/mod.d.ts +5 -4
- package/out/zero-client/src/mod.d.ts.map +1 -1
- package/out/zero-react/src/use-query.d.ts +6 -5
- package/out/zero-react/src/use-query.d.ts.map +1 -1
- package/out/zero-schema/src/builder/relationship-builder.d.ts +50 -0
- package/out/zero-schema/src/builder/relationship-builder.d.ts.map +1 -0
- package/out/zero-schema/src/builder/relationship-builder.js +24 -0
- package/out/zero-schema/src/builder/relationship-builder.js.map +1 -0
- package/out/zero-schema/src/builder/schema-builder.d.ts +40 -0
- package/out/zero-schema/src/builder/schema-builder.d.ts.map +1 -0
- package/out/zero-schema/src/builder/schema-builder.js +51 -0
- package/out/zero-schema/src/builder/schema-builder.js.map +1 -0
- package/out/zero-schema/src/builder/table-builder.d.ts +69 -0
- package/out/zero-schema/src/builder/table-builder.d.ts.map +1 -0
- package/out/zero-schema/src/builder/table-builder.js +102 -0
- package/out/zero-schema/src/builder/table-builder.js.map +1 -0
- package/out/zero-schema/src/mod.d.ts +2 -2
- package/out/zero-schema/src/mod.d.ts.map +1 -1
- package/out/zero-schema/src/permissions.d.ts +11 -12
- package/out/zero-schema/src/permissions.d.ts.map +1 -1
- package/out/zero-schema/src/schema-config.d.ts +2 -4
- package/out/zero-schema/src/schema-config.d.ts.map +1 -1
- package/out/zero-schema/src/schema-config.js +12 -61
- package/out/zero-schema/src/schema-config.js.map +1 -1
- package/out/zero-schema/src/table-schema.d.ts +28 -53
- package/out/zero-schema/src/table-schema.d.ts.map +1 -1
- package/out/zero-schema/src/table-schema.js +6 -13
- package/out/zero-schema/src/table-schema.js.map +1 -1
- package/out/zero-solid/src/solid-view.d.ts +4 -3
- package/out/zero-solid/src/solid-view.d.ts.map +1 -1
- package/out/zero-solid/src/use-query.d.ts +5 -4
- package/out/zero-solid/src/use-query.d.ts.map +1 -1
- package/out/zero.js +17 -7
- package/out/zql/src/ivm/exists.d.ts +1 -1
- package/out/zql/src/ivm/exists.d.ts.map +1 -1
- package/out/zql/src/ivm/exists.js +3 -3
- package/out/zql/src/ivm/exists.js.map +1 -1
- package/out/zql/src/ivm/fan-in.d.ts +1 -1
- package/out/zql/src/ivm/fan-in.d.ts.map +1 -1
- package/out/zql/src/ivm/fan-in.js +3 -2
- package/out/zql/src/ivm/fan-in.js.map +1 -1
- package/out/zql/src/ivm/filter.d.ts +1 -1
- package/out/zql/src/ivm/filter.d.ts.map +1 -1
- package/out/zql/src/ivm/filter.js +3 -3
- package/out/zql/src/ivm/filter.js.map +1 -1
- package/out/zql/src/ivm/join.d.ts +1 -1
- package/out/zql/src/ivm/join.d.ts.map +1 -1
- package/out/zql/src/ivm/join.js +2 -3
- package/out/zql/src/ivm/join.js.map +1 -1
- package/out/zql/src/ivm/memory-source.js +8 -10
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/ivm/memory-storage.d.ts.map +1 -1
- package/out/zql/src/ivm/operator.d.ts +5 -0
- package/out/zql/src/ivm/operator.d.ts.map +1 -1
- package/out/zql/src/ivm/operator.js +9 -0
- package/out/zql/src/ivm/operator.js.map +1 -1
- package/out/zql/src/ivm/skip.d.ts +1 -1
- package/out/zql/src/ivm/skip.d.ts.map +1 -1
- package/out/zql/src/ivm/skip.js +2 -3
- package/out/zql/src/ivm/skip.js.map +1 -1
- package/out/zql/src/ivm/take.d.ts +1 -1
- package/out/zql/src/ivm/take.d.ts.map +1 -1
- package/out/zql/src/ivm/take.js +2 -3
- package/out/zql/src/ivm/take.js.map +1 -1
- package/out/zql/src/ivm/view.d.ts +3 -3
- package/out/zql/src/ivm/view.d.ts.map +1 -1
- package/out/zql/src/query/auth-query.d.ts +9 -10
- package/out/zql/src/query/auth-query.d.ts.map +1 -1
- package/out/zql/src/query/auth-query.js +6 -7
- package/out/zql/src/query/auth-query.js.map +1 -1
- package/out/zql/src/query/expression.d.ts +11 -13
- package/out/zql/src/query/expression.d.ts.map +1 -1
- package/out/zql/src/query/expression.js +1 -1
- package/out/zql/src/query/expression.js.map +1 -1
- package/out/zql/src/query/query-impl.d.ts +26 -25
- package/out/zql/src/query/query-impl.d.ts.map +1 -1
- package/out/zql/src/query/query-impl.js +76 -52
- package/out/zql/src/query/query-impl.js.map +1 -1
- package/out/zql/src/query/query-internal.d.ts +5 -5
- package/out/zql/src/query/query-internal.d.ts.map +1 -1
- package/out/zql/src/query/query.d.ts +37 -80
- package/out/zql/src/query/query.d.ts.map +1 -1
- package/out/zql/src/query/query.js +0 -1
- package/out/zql/src/query/query.js.map +1 -1
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +33 -11
- package/out/zqlite/src/table-source.js.map +1 -1
- package/package.json +4 -4
- package/out/btree/b+tree.d.ts +0 -471
- package/out/btree/b+tree.d.ts.map +0 -1
- package/out/btree/b+tree.js +0 -1708
- package/out/btree/b+tree.js.map +0 -1
- package/out/btree/interfaces.d.ts +0 -270
- package/out/btree/interfaces.d.ts.map +0 -1
- package/out/btree/interfaces.js +0 -3
- package/out/btree/interfaces.js.map +0 -1
- package/out/btree/src/mod.d.ts +0 -2
- package/out/btree/src/mod.d.ts.map +0 -1
- package/out/btree/src/mod.js +0 -2
- package/out/btree/src/mod.js.map +0 -1
- package/out/chunk-AII6TS5B.js.map +0 -7
- package/out/shared/src/sorted-entries.d.ts +0 -2
- package/out/shared/src/sorted-entries.d.ts.map +0 -1
- package/out/shared/src/sorted-entries.js +0 -6
- package/out/shared/src/sorted-entries.js.map +0 -1
- package/out/zero-cache/src/db/queries.d.ts +0 -24
- package/out/zero-cache/src/db/queries.d.ts.map +0 -1
- package/out/zero-cache/src/db/queries.js +0 -60
- package/out/zero-cache/src/db/queries.js.map +0 -1
- package/out/zero-schema/src/column.d.ts +0 -79
- package/out/zero-schema/src/column.d.ts.map +0 -1
- package/out/zero-schema/src/normalize-table-schema.d.ts +0 -51
- package/out/zero-schema/src/normalize-table-schema.d.ts.map +0 -1
- package/out/zero-schema/src/normalize-table-schema.js +0 -122
- package/out/zero-schema/src/normalize-table-schema.js.map +0 -1
- package/out/zero-schema/src/normalized-schema.d.ts +0 -22
- package/out/zero-schema/src/normalized-schema.d.ts.map +0 -1
- package/out/zero-schema/src/normalized-schema.js +0 -48
- package/out/zero-schema/src/normalized-schema.js.map +0 -1
- package/out/zero-schema/src/schema.d.ts +0 -9
- package/out/zero-schema/src/schema.d.ts.map +0 -1
- package/out/zero-schema/src/schema.js +0 -9
- package/out/zero-schema/src/schema.js.map +0 -1
package/out/react.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../zero-react/src/use-query.tsx", "../../shared/src/deep-clone.ts", "../../zero-react/src/use-zero.tsx"],
|
|
4
|
-
"sourcesContent": ["import {useSyncExternalStore} from 'react';\nimport {deepClone} from '../../shared/src/deep-clone.js';\nimport type {Immutable} from '../../shared/src/immutable.js';\nimport type {\n Query,\n
|
|
5
|
-
"mappings": ";;;;;;AAAA,SAAQ,4BAA2B;;;ACG5B,SAAS,UAAU,OAAqC;AAC7D,QAAM,OAAiC,CAAC;AACxC,SAAO,kBAAkB,OAAO,IAAI;AACtC;AAEO,SAAS,kBACd,OACA,MACW;AACX,UAAQ,OAAO,OAAO;AAAA,IACpB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK,UAAU;AACb,UAAI,UAAU,MAAM;AAClB,eAAO;AAAA,MACT;AACA,UAAI,KAAK,SAAS,KAAK,GAAG;AACxB,cAAM,IAAI,MAAM,eAAe;AAAA,MACjC;AACA,WAAK,KAAK,KAAK;AACf,UAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,cAAM,KAAK,MAAM,IAAI,OAAK,kBAAkB,GAAG,IAAI,CAAC;AACpD,aAAK,IAAI;AACT,eAAO;AAAA,MACT;AAEA,YAAM,MAAiB,CAAC;AAExB,iBAAW,KAAK,OAAO;AACrB,YAAI,OAAO,OAAO,CAAC,GAAG;AACpB,gBAAM,IAAK,MAA4C,CAAC;AACxD,cAAI,MAAM,QAAW;AACnB,gBAAI,CAAC,IAAI,kBAAkB,GAAG,IAAI;AAAA,UACpC;AAAA,QACF;AAAA,MACF;AACA,WAAK,IAAI;AACT,aAAO;AAAA,IACT;AAAA,IAEA;AACE,YAAM,IAAI,MAAM,iBAAiB,OAAO,KAAK,EAAE;AAAA,EACnD;AACF;;;ACjDA,SAAQ,eAAe,kBAAiB;AA0B/B;AArBT,IAAM,cAAc,cAAmC,MAAS;AAEzD,SAAS,UAAqC;AACnD,QAAM,OAAO,WAAW,WAAW;AACnC,MAAI,SAAS,QAAW;AACtB,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAC9D;AACA,SAAO;AACT;AAEO,SAAS,gBAAkC;AAChD,SAAO,MAAM,QAAW;AAC1B;AAEO,SAAS,aAA+B;AAAA,EAC7C;AAAA,EACA;AACF,GAGG;AACD,SAAO,oBAAC,YAAY,UAAZ,EAAqB,OAAO,MAAO,UAAS;AACtD;;;
|
|
4
|
+
"sourcesContent": ["import {useSyncExternalStore} from 'react';\nimport {deepClone} from '../../shared/src/deep-clone.js';\nimport type {Immutable} from '../../shared/src/immutable.js';\nimport type {\n Query,\n ReadonlyJSONValue,\n TypedView,\n} from '../../zero-client/src/mod.js';\nimport type {AdvancedQuery} from '../../zql/src/query/query-internal.js';\nimport type {ResultType} from '../../zql/src/query/typed-view.js';\nimport {useZero} from './use-zero.js';\nimport type {HumanReadable} from '../../zql/src/query/query.js';\nimport type {Schema} from '../../zero-client/src/mod.js';\n\nexport type QueryResultDetails = Readonly<{\n type: ResultType;\n}>;\n\nexport type QueryResult<TReturn> = readonly [\n HumanReadable<TReturn>,\n QueryResultDetails,\n];\n\nexport function useQuery<\n TSchema extends Schema,\n TTable extends keyof TSchema['tables'] & string,\n TReturn,\n>(\n q: Query<TSchema, TTable, TReturn>,\n enable: boolean = true,\n): QueryResult<TReturn> {\n const z = useZero();\n const view = viewStore.getView(\n z.clientID,\n q as AdvancedQuery<TSchema, TTable, TReturn>,\n enable && z.server !== null,\n );\n // https://react.dev/reference/react/useSyncExternalStore\n return useSyncExternalStore(\n view.subscribeReactInternals,\n view.getSnapshot,\n view.getSnapshot,\n );\n}\n\nconst emptyArray: unknown[] = [];\nconst disabledSubscriber = () => () => {};\n\nconst defaultSnapshots = {\n singular: [undefined, {type: 'unknown'}] as const,\n plural: [emptyArray, {type: 'unknown'}] as const,\n};\n\nfunction getDefaultSnapshot<TReturn>(singular: boolean): QueryResult<TReturn> {\n return (\n singular ? defaultSnapshots.singular : defaultSnapshots.plural\n ) as QueryResult<TReturn>;\n}\n\n/**\n * A global store of all active views.\n *\n * React subscribes and unsubscribes to these views\n * via `useSyncExternalStore`.\n *\n * Managing views through `useEffect` or `useLayoutEffect` causes\n * inconsistencies because effects run after render.\n *\n * For example, if useQuery used use*Effect in the component below:\n * ```ts\n * function Foo({issueID}) {\n * const issue = useQuery(z.query.issue.where('id', issueID).one());\n * if (issue?.id !== undefined && issue.id !== issueID) {\n * console.log('MISMATCH!', issue.id, issueID);\n * }\n * }\n * ```\n *\n * `MISMATCH` will be printed whenever the `issueID` prop changes.\n *\n * This is because the component will render once with\n * the old state returned from `useQuery`. Then the effect inside\n * `useQuery` will run. The component will render again with the new\n * state. This inconsistent transition can cause unexpected results.\n *\n * Emulating `useEffect` via `useState` and `if` causes resource leaks.\n * That is:\n *\n * ```ts\n * function useQuery(q) {\n * const [oldHash, setOldHash] = useState();\n * if (hash(q) !== oldHash) {\n * // make new view\n * }\n *\n * useEffect(() => {\n * return () => view.destroy();\n * }, []);\n * }\n * ```\n *\n * I'm not sure why but in strict mode the cleanup function\n * fails to be called for the first instance of the view and only\n * cleans up later instances.\n *\n * Swapping `useState` to `useRef` has similar problems.\n */\nclass ViewStore {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n #views = new Map<string, ViewWrapper<any, any, any>>();\n\n getView<\n TSchema extends Schema,\n TTable extends keyof TSchema['tables'] & string,\n TReturn,\n >(\n clientID: string,\n query: AdvancedQuery<TSchema, TTable, TReturn>,\n enabled: boolean,\n ): {\n getSnapshot: () => QueryResult<TReturn>;\n subscribeReactInternals: (internals: () => void) => () => void;\n } {\n if (!enabled) {\n return {\n getSnapshot: () => getDefaultSnapshot(query.format.singular),\n subscribeReactInternals: disabledSubscriber,\n };\n }\n\n const hash = query.hash() + clientID;\n let existing = this.#views.get(hash);\n if (!existing) {\n existing = new ViewWrapper(\n query,\n view => {\n const lastView = this.#views.get(hash);\n // I don't think this can happen\n // but lets guard against it so we don't\n // leak resources.\n if (lastView && lastView !== view) {\n throw new Error('View already exists');\n }\n this.#views.set(hash, view);\n },\n () => {\n this.#views.delete(hash);\n },\n ) as ViewWrapper<TSchema, TTable, TReturn>;\n this.#views.set(hash, existing);\n }\n return existing as ViewWrapper<TSchema, TTable, TReturn>;\n }\n}\n\nconst viewStore = new ViewStore();\n\n/**\n * This wraps and ref counts a view.\n *\n * The only signal we have from React as to whether or not it is\n * done with a view is when it calls `unsubscribe`.\n *\n * In non-strict-mode we can clean up the view as soon\n * as the listener count goes to 0.\n *\n * In strict-mode, the listener cound will go to 0 then a\n * new listener for the same view is immeidatiely added back.\n *\n * This is why the `onMaterialized` and `onDematerialized` callbacks exist --\n * they allow a view which React is still referencing to be added\n * back into the store when React re-subscribes to it.\n *\n * This wrapper also exists to deal with the various\n * `useSyncExternalStore` caveats that cause excessive\n * re-renders and materializations.\n *\n * See: https://react.dev/reference/react/useSyncExternalStore#caveats\n * Especially:\n * 1. The store snapshot returned by getSnapshot must be immutable. If the underlying store has mutable data, return a new immutable snapshot if the data has changed. Otherwise, return a cached last snapshot.\n * 2. If a different subscribe function is passed during a re-render, React will re-subscribe to the store using the newly passed subscribe function. You can prevent this by declaring subscribe outside the component.\n */\nclass ViewWrapper<\n TSchema extends Schema,\n TTable extends keyof TSchema['tables'] & string,\n TReturn,\n> {\n #view: TypedView<HumanReadable<TReturn>> | undefined;\n readonly #onDematerialized;\n readonly #onMaterialized;\n readonly #query: AdvancedQuery<TSchema, TTable, TReturn>;\n #snapshot: QueryResult<TReturn>;\n #reactInternals: Set<() => void>;\n\n constructor(\n query: AdvancedQuery<TSchema, TTable, TReturn>,\n onMaterialized: (view: ViewWrapper<TSchema, TTable, TReturn>) => void,\n onDematerialized: () => void,\n ) {\n this.#snapshot = getDefaultSnapshot(query.format.singular);\n this.#onMaterialized = onMaterialized;\n this.#onDematerialized = onDematerialized;\n this.#reactInternals = new Set();\n this.#query = query;\n }\n\n #onData = (\n snap: Immutable<HumanReadable<TReturn>>,\n resultType: ResultType,\n ) => {\n const data =\n snap === undefined\n ? snap\n : (deepClone(snap as ReadonlyJSONValue) as HumanReadable<TReturn>);\n this.#snapshot = [data, {type: resultType}] as QueryResult<TReturn>;\n for (const internals of this.#reactInternals) {\n internals();\n }\n };\n\n #materializeIfNeeded = () => {\n if (this.#view) {\n return;\n }\n\n this.#view = this.#query.materialize();\n this.#view.addListener(this.#onData);\n\n this.#onMaterialized(this);\n };\n\n getSnapshot = () => this.#snapshot;\n\n subscribeReactInternals = (internals: () => void): (() => void) => {\n this.#reactInternals.add(internals);\n this.#materializeIfNeeded();\n return () => {\n this.#reactInternals.delete(internals);\n if (this.#reactInternals.size === 0) {\n this.#view?.destroy();\n this.#view = undefined;\n this.#onDematerialized();\n }\n };\n };\n}\n", "import {hasOwn} from './has-own.js';\nimport type {JSONValue, ReadonlyJSONValue} from './json.js';\n\nexport function deepClone(value: ReadonlyJSONValue): JSONValue {\n const seen: Array<ReadonlyJSONValue> = [];\n return internalDeepClone(value, seen);\n}\n\nexport function internalDeepClone(\n value: ReadonlyJSONValue,\n seen: Array<ReadonlyJSONValue>,\n): JSONValue {\n switch (typeof value) {\n case 'boolean':\n case 'number':\n case 'string':\n case 'undefined':\n return value;\n case 'object': {\n if (value === null) {\n return null;\n }\n if (seen.includes(value)) {\n throw new Error('Cyclic object');\n }\n seen.push(value);\n if (Array.isArray(value)) {\n const rv = value.map(v => internalDeepClone(v, seen));\n seen.pop();\n return rv;\n }\n\n const obj: JSONValue = {};\n\n for (const k in value) {\n if (hasOwn(value, k)) {\n const v = (value as Record<string, ReadonlyJSONValue>)[k];\n if (v !== undefined) {\n obj[k] = internalDeepClone(v, seen);\n }\n }\n }\n seen.pop();\n return obj;\n }\n\n default:\n throw new Error(`Invalid type: ${typeof value}`);\n }\n}\n", "import {createContext, useContext} from 'react';\nimport type {Zero} from '../../zero-client/src/mod.js';\nimport type {Schema} from '../../zero-schema/src/mod.js';\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst ZeroContext = createContext<unknown | undefined>(undefined);\n\nexport function useZero<S extends Schema>(): Zero<S> {\n const zero = useContext(ZeroContext);\n if (zero === undefined) {\n throw new Error('useZero must be used within a ZeroProvider');\n }\n return zero as Zero<S>;\n}\n\nexport function createUseZero<S extends Schema>() {\n return () => useZero<S>();\n}\n\nexport function ZeroProvider<S extends Schema>({\n children,\n zero,\n}: {\n children: React.ReactNode;\n zero: Zero<S>;\n}) {\n return <ZeroContext.Provider value={zero}>{children}</ZeroContext.Provider>;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
type Comparator<K> = (a: K, b: K) => number;
|
|
2
|
+
export declare class BTreeSet<K> {
|
|
3
|
+
#private;
|
|
4
|
+
size: number;
|
|
5
|
+
readonly comparator: Comparator<K>;
|
|
6
|
+
constructor(comparator: Comparator<K>, entries?: IterableIterator<K>);
|
|
7
|
+
/** Releases the tree so that its size is 0. */
|
|
8
|
+
clear(): void;
|
|
9
|
+
get(key: K): K | undefined;
|
|
10
|
+
add(key: K): this;
|
|
11
|
+
/**
|
|
12
|
+
* Returns true if the key exists in the B+ tree, false if not.
|
|
13
|
+
* Use get() for best performance; use has() if you need to
|
|
14
|
+
* distinguish between "undefined value" and "key not present".
|
|
15
|
+
* @param key Key to detect
|
|
16
|
+
* @description Computational complexity: O(log size)
|
|
17
|
+
*/
|
|
18
|
+
has(key: K): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Removes a single key-value pair from the B+ tree.
|
|
21
|
+
* @param key Key to find
|
|
22
|
+
* @returns true if a pair was found and removed, false otherwise.
|
|
23
|
+
* @description Computational complexity: O(log size)
|
|
24
|
+
*/
|
|
25
|
+
delete(key: K): boolean;
|
|
26
|
+
keys(): IterableIterator<K>;
|
|
27
|
+
values(): IterableIterator<K>;
|
|
28
|
+
valuesFrom(lowestKey?: K, inclusive?: boolean): IterableIterator<K>;
|
|
29
|
+
valuesReversed(): IterableIterator<K>;
|
|
30
|
+
valuesFromReversed(highestKey?: K, inclusive?: boolean): IterableIterator<K>;
|
|
31
|
+
[Symbol.iterator](): IterableIterator<K>;
|
|
32
|
+
}
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=btree-set.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"btree-set.d.ts","sourceRoot":"","sources":["../../../../shared/src/btree-set.ts"],"names":[],"mappings":"AAIA,KAAK,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC;AAC5C,qBAAa,QAAQ,CAAC,CAAC;;IAErB,IAAI,EAAE,MAAM,CAAK;IAEjB,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;gBAEvB,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC;IASpE,+CAA+C;IAC/C,KAAK;IAKL,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS;IAI1B,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI;IASjB;;;;;;OAMG;IACH,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO;IAIpB;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO;IAyBvB,IAAI,IAAI,gBAAgB,CAAC,CAAC,CAAC;IAI3B,MAAM,IAAI,gBAAgB,CAAC,CAAC,CAAC;IAI7B,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,SAAS,GAAE,OAAc,GAAG,gBAAgB,CAAC,CAAC,CAAC;IAIzE,cAAc,IAAI,gBAAgB,CAAC,CAAC,CAAC;IAUrC,kBAAkB,CAChB,UAAU,CAAC,EAAE,CAAC,EACd,SAAS,GAAE,OAAc,GACxB,gBAAgB,CAAC,CAAC,CAAC;IAetB,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,gBAAgB,CAAC,CAAC,CAAC;CAGzC"}
|
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
import { assert } from './asserts.js';
|
|
2
|
+
const MAX_NODE_SIZE = 32;
|
|
3
|
+
export class BTreeSet {
|
|
4
|
+
#root = emptyLeaf;
|
|
5
|
+
size = 0;
|
|
6
|
+
comparator;
|
|
7
|
+
constructor(comparator, entries) {
|
|
8
|
+
this.comparator = comparator;
|
|
9
|
+
if (entries) {
|
|
10
|
+
for (const key of entries) {
|
|
11
|
+
this.add(key);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** Releases the tree so that its size is 0. */
|
|
16
|
+
clear() {
|
|
17
|
+
this.#root = emptyLeaf;
|
|
18
|
+
this.size = 0;
|
|
19
|
+
}
|
|
20
|
+
get(key) {
|
|
21
|
+
return this.#root.get(key, this);
|
|
22
|
+
}
|
|
23
|
+
add(key) {
|
|
24
|
+
if (this.#root.isShared)
|
|
25
|
+
this.#root = this.#root.clone();
|
|
26
|
+
const result = this.#root.set(key, this);
|
|
27
|
+
if (result === null)
|
|
28
|
+
return this;
|
|
29
|
+
// Root node has split, so create a new root node.
|
|
30
|
+
this.#root = new BNodeInternal([this.#root, result]);
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Returns true if the key exists in the B+ tree, false if not.
|
|
35
|
+
* Use get() for best performance; use has() if you need to
|
|
36
|
+
* distinguish between "undefined value" and "key not present".
|
|
37
|
+
* @param key Key to detect
|
|
38
|
+
* @description Computational complexity: O(log size)
|
|
39
|
+
*/
|
|
40
|
+
has(key) {
|
|
41
|
+
return this.#root.has(key, this);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Removes a single key-value pair from the B+ tree.
|
|
45
|
+
* @param key Key to find
|
|
46
|
+
* @returns true if a pair was found and removed, false otherwise.
|
|
47
|
+
* @description Computational complexity: O(log size)
|
|
48
|
+
*/
|
|
49
|
+
delete(key) {
|
|
50
|
+
return this.#delete(key);
|
|
51
|
+
}
|
|
52
|
+
#delete(key) {
|
|
53
|
+
let root = this.#root;
|
|
54
|
+
if (root.isShared) {
|
|
55
|
+
this.#root = root = root.clone();
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
return root.delete(key, this);
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
let isShared;
|
|
62
|
+
while (root.keys.length <= 1 && root.isInternal()) {
|
|
63
|
+
isShared ||= root.isShared;
|
|
64
|
+
this.#root = root =
|
|
65
|
+
root.keys.length === 0 ? emptyLeaf : root.children[0];
|
|
66
|
+
}
|
|
67
|
+
// If any ancestor of the new root was shared, the new root must also be shared
|
|
68
|
+
if (isShared) {
|
|
69
|
+
root.isShared = true;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
keys() {
|
|
74
|
+
return valuesFrom(this.#root, this.comparator, undefined, true);
|
|
75
|
+
}
|
|
76
|
+
values() {
|
|
77
|
+
return valuesFrom(this.#root, this.comparator, undefined, true);
|
|
78
|
+
}
|
|
79
|
+
valuesFrom(lowestKey, inclusive = true) {
|
|
80
|
+
return valuesFrom(this.#root, this.comparator, lowestKey, inclusive);
|
|
81
|
+
}
|
|
82
|
+
valuesReversed() {
|
|
83
|
+
return valuesFromReversed(this.#maxKey(), this.#root, this.comparator, undefined, true);
|
|
84
|
+
}
|
|
85
|
+
valuesFromReversed(highestKey, inclusive = true) {
|
|
86
|
+
return valuesFromReversed(this.#maxKey(), this.#root, this.comparator, highestKey, inclusive);
|
|
87
|
+
}
|
|
88
|
+
/** Gets the highest key in the tree. Complexity: O(1) */
|
|
89
|
+
#maxKey() {
|
|
90
|
+
return this.#root.maxKey();
|
|
91
|
+
}
|
|
92
|
+
[Symbol.iterator]() {
|
|
93
|
+
return this.keys();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function valuesFrom(root, comparator, lowestKey, inclusive) {
|
|
97
|
+
const info = findPath(lowestKey, root, comparator);
|
|
98
|
+
if (info === undefined) {
|
|
99
|
+
return iterator(() => ({ done: true, value: undefined }));
|
|
100
|
+
}
|
|
101
|
+
// eslint-disable-next-line prefer-const
|
|
102
|
+
let [nodeQueue, nodeIndex, leaf] = info;
|
|
103
|
+
let i = lowestKey === undefined
|
|
104
|
+
? -1
|
|
105
|
+
: indexOf(lowestKey, leaf.keys, 0, comparator) - 1;
|
|
106
|
+
if (!inclusive &&
|
|
107
|
+
i < leaf.keys.length &&
|
|
108
|
+
// +1 because we did -1 above.
|
|
109
|
+
comparator(leaf.keys[i + 1], lowestKey) === 0) {
|
|
110
|
+
i++;
|
|
111
|
+
}
|
|
112
|
+
return iterator(() => {
|
|
113
|
+
for (;;) {
|
|
114
|
+
if (++i < leaf.keys.length) {
|
|
115
|
+
return { done: false, value: leaf.keys[i] };
|
|
116
|
+
}
|
|
117
|
+
let level = -1;
|
|
118
|
+
for (;;) {
|
|
119
|
+
if (++level >= nodeQueue.length) {
|
|
120
|
+
return { done: true, value: undefined };
|
|
121
|
+
}
|
|
122
|
+
if (++nodeIndex[level] < nodeQueue[level].length) {
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
for (; level > 0; level--) {
|
|
127
|
+
nodeQueue[level - 1] = nodeQueue[level][nodeIndex[level]].children;
|
|
128
|
+
nodeIndex[level - 1] = 0;
|
|
129
|
+
}
|
|
130
|
+
leaf = nodeQueue[0][nodeIndex[0]];
|
|
131
|
+
i = -1;
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
function valuesFromReversed(maxKey, root, comparator, highestKey, inclusive) {
|
|
136
|
+
if (highestKey === undefined) {
|
|
137
|
+
highestKey = maxKey;
|
|
138
|
+
if (highestKey === undefined)
|
|
139
|
+
return iterator(() => ({ done: true, value: undefined })); // collection is empty
|
|
140
|
+
}
|
|
141
|
+
// eslint-disable-next-line prefer-const
|
|
142
|
+
let [nodeQueue, nodeIndex, leaf] = findPath(highestKey, root, comparator) ||
|
|
143
|
+
findPath(maxKey, root, comparator);
|
|
144
|
+
assert(!nodeQueue[0] || leaf === nodeQueue[0][nodeIndex[0]]);
|
|
145
|
+
let i = indexOf(highestKey, leaf.keys, 0, comparator);
|
|
146
|
+
if (inclusive &&
|
|
147
|
+
i < leaf.keys.length &&
|
|
148
|
+
comparator(leaf.keys[i], highestKey) <= 0) {
|
|
149
|
+
i++;
|
|
150
|
+
}
|
|
151
|
+
return iterator(() => {
|
|
152
|
+
for (;;) {
|
|
153
|
+
if (--i >= 0) {
|
|
154
|
+
return { done: false, value: leaf.keys[i] };
|
|
155
|
+
}
|
|
156
|
+
let level;
|
|
157
|
+
// Advance to the next leaf node
|
|
158
|
+
for (level = -1;;) {
|
|
159
|
+
if (++level >= nodeQueue.length) {
|
|
160
|
+
return { done: true, value: undefined };
|
|
161
|
+
}
|
|
162
|
+
if (--nodeIndex[level] >= 0) {
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
for (; level > 0; level--) {
|
|
167
|
+
nodeQueue[level - 1] = nodeQueue[level][nodeIndex[level]].children;
|
|
168
|
+
nodeIndex[level - 1] = nodeQueue[level - 1].length - 1;
|
|
169
|
+
}
|
|
170
|
+
leaf = nodeQueue[0][nodeIndex[0]];
|
|
171
|
+
i = leaf.keys.length;
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
function findPath(key, root, comparator) {
|
|
176
|
+
let nextNode = root;
|
|
177
|
+
const nodeQueue = [];
|
|
178
|
+
const nodeIndex = [];
|
|
179
|
+
if (nextNode.isInternal()) {
|
|
180
|
+
for (let d = 0; nextNode.isInternal(); d++) {
|
|
181
|
+
nodeQueue[d] = nextNode.children;
|
|
182
|
+
nodeIndex[d] =
|
|
183
|
+
key === undefined ? 0 : indexOf(key, nextNode.keys, 0, comparator);
|
|
184
|
+
if (nodeIndex[d] >= nodeQueue[d].length)
|
|
185
|
+
return; // first key > maxKey()
|
|
186
|
+
nextNode = nodeQueue[d][nodeIndex[d]];
|
|
187
|
+
}
|
|
188
|
+
nodeQueue.reverse();
|
|
189
|
+
nodeIndex.reverse();
|
|
190
|
+
}
|
|
191
|
+
return [nodeQueue, nodeIndex, nextNode];
|
|
192
|
+
}
|
|
193
|
+
function iterator(next) {
|
|
194
|
+
return {
|
|
195
|
+
next,
|
|
196
|
+
[Symbol.iterator]() {
|
|
197
|
+
return this;
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
/** Leaf node / base class. **************************************************/
|
|
202
|
+
class BNode {
|
|
203
|
+
// If this is an internal node, _keys[i] is the highest key in children[i].
|
|
204
|
+
keys;
|
|
205
|
+
// True if this node might be within multiple `BTree`s (or have multiple parents).
|
|
206
|
+
// If so, it must be cloned before being mutated to avoid changing an unrelated tree.
|
|
207
|
+
// This is transitive: if it's true, children are also shared even if `isShared!=true`
|
|
208
|
+
// in those children. (Certain operations will propagate isShared=true to children.)
|
|
209
|
+
isShared;
|
|
210
|
+
constructor(keys) {
|
|
211
|
+
this.keys = keys;
|
|
212
|
+
this.isShared = undefined;
|
|
213
|
+
}
|
|
214
|
+
isInternal() {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
maxKey() {
|
|
218
|
+
return this.keys[this.keys.length - 1];
|
|
219
|
+
}
|
|
220
|
+
minKey() {
|
|
221
|
+
return this.keys[0];
|
|
222
|
+
}
|
|
223
|
+
clone() {
|
|
224
|
+
return new BNode(this.keys.slice(0));
|
|
225
|
+
}
|
|
226
|
+
get(key, tree) {
|
|
227
|
+
const i = indexOf(key, this.keys, -1, tree.comparator);
|
|
228
|
+
return i < 0 ? undefined : this.keys[i];
|
|
229
|
+
}
|
|
230
|
+
has(key, tree) {
|
|
231
|
+
const i = indexOf(key, this.keys, -1, tree.comparator);
|
|
232
|
+
return i >= 0 && i < this.keys.length;
|
|
233
|
+
}
|
|
234
|
+
set(key, tree) {
|
|
235
|
+
let i = indexOf(key, this.keys, -1, tree.comparator);
|
|
236
|
+
if (i < 0) {
|
|
237
|
+
// key does not exist yet
|
|
238
|
+
i = ~i;
|
|
239
|
+
tree.size++;
|
|
240
|
+
if (this.keys.length < MAX_NODE_SIZE) {
|
|
241
|
+
this.keys.splice(i, 0, key);
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
// This leaf node is full and must split
|
|
245
|
+
const newRightSibling = this.splitOffRightSide();
|
|
246
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
247
|
+
let target = this;
|
|
248
|
+
if (i > this.keys.length) {
|
|
249
|
+
i -= this.keys.length;
|
|
250
|
+
target = newRightSibling;
|
|
251
|
+
}
|
|
252
|
+
// target.#insertInLeaf(i, key);
|
|
253
|
+
target.keys.splice(i, 0, key);
|
|
254
|
+
return newRightSibling;
|
|
255
|
+
}
|
|
256
|
+
// usually this is a no-op, but some users may wish to edit the key
|
|
257
|
+
this.keys[i] = key;
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
takeFromRight(rhs) {
|
|
261
|
+
this.keys.push(rhs.keys.shift());
|
|
262
|
+
}
|
|
263
|
+
takeFromLeft(lhs) {
|
|
264
|
+
this.keys.unshift(lhs.keys.pop());
|
|
265
|
+
}
|
|
266
|
+
splitOffRightSide() {
|
|
267
|
+
const half = this.keys.length >> 1;
|
|
268
|
+
const keys = this.keys.splice(half);
|
|
269
|
+
return new BNode(keys);
|
|
270
|
+
}
|
|
271
|
+
delete(key, tree) {
|
|
272
|
+
const cmp = tree.comparator;
|
|
273
|
+
const iLow = indexOf(key, this.keys, -1, cmp);
|
|
274
|
+
const iHigh = iLow + 1;
|
|
275
|
+
if (iLow < 0) {
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
const { keys } = this;
|
|
279
|
+
for (let i = iLow; i < iHigh; i++) {
|
|
280
|
+
const key = keys[i];
|
|
281
|
+
if (key !== keys[i] || this.isShared === true) {
|
|
282
|
+
throw new Error('BTree illegally changed or cloned in delete');
|
|
283
|
+
}
|
|
284
|
+
this.keys.splice(i, 1);
|
|
285
|
+
tree.size--;
|
|
286
|
+
return true;
|
|
287
|
+
}
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
|
+
mergeSibling(rhs, _) {
|
|
291
|
+
this.keys.push(...rhs.keys);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
/** Internal node (non-leaf node) ********************************************/
|
|
295
|
+
class BNodeInternal extends BNode {
|
|
296
|
+
// Note: conventionally B+ trees have one fewer key than the number of
|
|
297
|
+
// children, but I find it easier to keep the array lengths equal: each
|
|
298
|
+
// keys[i] caches the value of children[i].maxKey().
|
|
299
|
+
children;
|
|
300
|
+
/**
|
|
301
|
+
* This does not mark `children` as shared, so it is the responsibility of the caller
|
|
302
|
+
* to ensure children are either marked shared, or aren't included in another tree.
|
|
303
|
+
*/
|
|
304
|
+
constructor(children, keys) {
|
|
305
|
+
if (!keys) {
|
|
306
|
+
keys = [];
|
|
307
|
+
for (let i = 0; i < children.length; i++) {
|
|
308
|
+
keys[i] = children[i].maxKey();
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
super(keys);
|
|
312
|
+
this.children = children;
|
|
313
|
+
}
|
|
314
|
+
isInternal() {
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
317
|
+
clone() {
|
|
318
|
+
const children = this.children.slice(0);
|
|
319
|
+
for (let i = 0; i < children.length; i++) {
|
|
320
|
+
children[i].isShared = true;
|
|
321
|
+
}
|
|
322
|
+
return new BNodeInternal(children, this.keys.slice(0));
|
|
323
|
+
}
|
|
324
|
+
minKey() {
|
|
325
|
+
return this.children[0].minKey();
|
|
326
|
+
}
|
|
327
|
+
get(key, tree) {
|
|
328
|
+
const i = indexOf(key, this.keys, 0, tree.comparator);
|
|
329
|
+
const { children } = this;
|
|
330
|
+
return i < children.length ? children[i].get(key, tree) : undefined;
|
|
331
|
+
}
|
|
332
|
+
has(key, tree) {
|
|
333
|
+
const i = indexOf(key, this.keys, 0, tree.comparator);
|
|
334
|
+
const { children } = this;
|
|
335
|
+
return i < children.length ? children[i].has(key, tree) : false;
|
|
336
|
+
}
|
|
337
|
+
set(key, tree) {
|
|
338
|
+
const c = this.children;
|
|
339
|
+
const cmp = tree.comparator;
|
|
340
|
+
let i = Math.min(indexOf(key, this.keys, 0, cmp), c.length - 1);
|
|
341
|
+
let child = c[i];
|
|
342
|
+
if (child.isShared) {
|
|
343
|
+
c[i] = child = child.clone();
|
|
344
|
+
}
|
|
345
|
+
if (child.keys.length >= MAX_NODE_SIZE) {
|
|
346
|
+
// child is full; inserting anything else will cause a split.
|
|
347
|
+
// Shifting an item to the left or right sibling may avoid a split.
|
|
348
|
+
// We can do a shift if the adjacent node is not full and if the
|
|
349
|
+
// current key can still be placed in the same node after the shift.
|
|
350
|
+
let other;
|
|
351
|
+
if (i > 0 &&
|
|
352
|
+
(other = c[i - 1]).keys.length < MAX_NODE_SIZE &&
|
|
353
|
+
cmp(child.keys[0], key) < 0) {
|
|
354
|
+
if (other.isShared) {
|
|
355
|
+
c[i - 1] = other = other.clone();
|
|
356
|
+
}
|
|
357
|
+
other.takeFromRight(child);
|
|
358
|
+
this.keys[i - 1] = other.maxKey();
|
|
359
|
+
}
|
|
360
|
+
else if ((other = c[i + 1]) !== undefined &&
|
|
361
|
+
other.keys.length < MAX_NODE_SIZE &&
|
|
362
|
+
cmp(child.maxKey(), key) < 0) {
|
|
363
|
+
if (other.isShared)
|
|
364
|
+
c[i + 1] = other = other.clone();
|
|
365
|
+
other.takeFromLeft(child);
|
|
366
|
+
this.keys[i] = c[i].maxKey();
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
const result = child.set(key, tree);
|
|
370
|
+
this.keys[i] = child.maxKey();
|
|
371
|
+
if (result === null)
|
|
372
|
+
return null;
|
|
373
|
+
// The child has split and `result` is a new right child... does it fit?
|
|
374
|
+
if (this.keys.length < MAX_NODE_SIZE) {
|
|
375
|
+
// yes
|
|
376
|
+
this.insert(i + 1, result);
|
|
377
|
+
return null;
|
|
378
|
+
}
|
|
379
|
+
// no, we must split also
|
|
380
|
+
const newRightSibling = this.splitOffRightSide();
|
|
381
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
382
|
+
let target = this;
|
|
383
|
+
if (cmp(result.maxKey(), this.maxKey()) > 0) {
|
|
384
|
+
target = newRightSibling;
|
|
385
|
+
i -= this.keys.length;
|
|
386
|
+
}
|
|
387
|
+
target.insert(i + 1, result);
|
|
388
|
+
return newRightSibling;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Inserts `child` at index `i`.
|
|
392
|
+
* This does not mark `child` as shared, so it is the responsibility of the caller
|
|
393
|
+
* to ensure that either child is marked shared, or it is not included in another tree.
|
|
394
|
+
*/
|
|
395
|
+
insert(i, child) {
|
|
396
|
+
this.children.splice(i, 0, child);
|
|
397
|
+
this.keys.splice(i, 0, child.maxKey());
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Split this node.
|
|
401
|
+
* Modifies this to remove the second half of the items, returning a separate node containing them.
|
|
402
|
+
*/
|
|
403
|
+
splitOffRightSide() {
|
|
404
|
+
const half = this.children.length >> 1;
|
|
405
|
+
return new BNodeInternal(this.children.splice(half), this.keys.splice(half));
|
|
406
|
+
}
|
|
407
|
+
takeFromRight(rhs) {
|
|
408
|
+
this.keys.push(rhs.keys.shift());
|
|
409
|
+
this.children.push(rhs.children.shift());
|
|
410
|
+
}
|
|
411
|
+
takeFromLeft(lhs) {
|
|
412
|
+
this.keys.unshift(lhs.keys.pop());
|
|
413
|
+
this.children.unshift(lhs.children.pop());
|
|
414
|
+
}
|
|
415
|
+
delete(key, tree) {
|
|
416
|
+
const cmp = tree.comparator;
|
|
417
|
+
const { keys } = this;
|
|
418
|
+
const { children } = this;
|
|
419
|
+
let iLow = indexOf(key, this.keys, 0, cmp);
|
|
420
|
+
let i = iLow;
|
|
421
|
+
const iHigh = Math.min(iLow, keys.length - 1);
|
|
422
|
+
if (i <= iHigh) {
|
|
423
|
+
try {
|
|
424
|
+
if (children[i].isShared) {
|
|
425
|
+
children[i] = children[i].clone();
|
|
426
|
+
}
|
|
427
|
+
const result = children[i].delete(key, tree);
|
|
428
|
+
// Note: if children[i] is empty then keys[i]=undefined.
|
|
429
|
+
// This is an invalid state, but it is fixed below.
|
|
430
|
+
keys[i] = children[i].maxKey();
|
|
431
|
+
return result;
|
|
432
|
+
}
|
|
433
|
+
finally {
|
|
434
|
+
// Deletions may have occurred, so look for opportunities to merge nodes.
|
|
435
|
+
const half = MAX_NODE_SIZE >> 1;
|
|
436
|
+
if (iLow > 0)
|
|
437
|
+
iLow--;
|
|
438
|
+
for (i = iHigh; i >= iLow; i--) {
|
|
439
|
+
if (children[i].keys.length <= half) {
|
|
440
|
+
if (children[i].keys.length !== 0) {
|
|
441
|
+
this.tryMerge(i, MAX_NODE_SIZE);
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
// child is empty! delete it!
|
|
445
|
+
keys.splice(i, 1);
|
|
446
|
+
children.splice(i, 1);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return false;
|
|
453
|
+
}
|
|
454
|
+
/** Merges child i with child i+1 if their combined size is not too large */
|
|
455
|
+
tryMerge(i, maxSize) {
|
|
456
|
+
const { children } = this;
|
|
457
|
+
if (i >= 0 && i + 1 < children.length) {
|
|
458
|
+
if (children[i].keys.length + children[i + 1].keys.length <= maxSize) {
|
|
459
|
+
if (children[i].isShared)
|
|
460
|
+
// cloned already UNLESS i is outside scan range
|
|
461
|
+
children[i] = children[i].clone();
|
|
462
|
+
children[i].mergeSibling(children[i + 1], maxSize);
|
|
463
|
+
children.splice(i + 1, 1);
|
|
464
|
+
this.keys.splice(i + 1, 1);
|
|
465
|
+
this.keys[i] = children[i].maxKey();
|
|
466
|
+
return true;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return false;
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Move children from `rhs` into this.
|
|
473
|
+
* `rhs` must be part of this tree, and be removed from it after this call
|
|
474
|
+
* (otherwise isShared for its children could be incorrect).
|
|
475
|
+
*/
|
|
476
|
+
mergeSibling(rhs, maxNodeSize) {
|
|
477
|
+
// assert !this.isShared;
|
|
478
|
+
const oldLength = this.keys.length;
|
|
479
|
+
this.keys.push(...rhs.keys);
|
|
480
|
+
const rhsChildren = rhs.children;
|
|
481
|
+
this.children.push(...rhsChildren);
|
|
482
|
+
if (rhs.isShared && !this.isShared) {
|
|
483
|
+
// All children of a shared node are implicitly shared, and since their new
|
|
484
|
+
// parent is not shared, they must now be explicitly marked as shared.
|
|
485
|
+
for (let i = 0; i < rhsChildren.length; i++) {
|
|
486
|
+
rhsChildren[i].isShared = true;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
// If our children are themselves almost empty due to a mass-delete,
|
|
490
|
+
// they may need to be merged too (but only the oldLength-1 and its
|
|
491
|
+
// right sibling should need this).
|
|
492
|
+
this.tryMerge(oldLength - 1, maxNodeSize);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
// If key not found, returns i^failXor where i is the insertion index.
|
|
496
|
+
// Callers that don't care whether there was a match will set failXor=0.
|
|
497
|
+
function indexOf(key, keys, failXor, comparator) {
|
|
498
|
+
let lo = 0;
|
|
499
|
+
let hi = keys.length;
|
|
500
|
+
let mid = hi >> 1;
|
|
501
|
+
while (lo < hi) {
|
|
502
|
+
const c = comparator(keys[mid], key);
|
|
503
|
+
if (c < 0) {
|
|
504
|
+
lo = mid + 1;
|
|
505
|
+
}
|
|
506
|
+
else if (c > 0) {
|
|
507
|
+
// key < keys[mid]
|
|
508
|
+
hi = mid;
|
|
509
|
+
}
|
|
510
|
+
else if (c === 0) {
|
|
511
|
+
return mid;
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
// c is NaN or otherwise invalid
|
|
515
|
+
if (key === key) {
|
|
516
|
+
// at least the search key is not NaN
|
|
517
|
+
return keys.length;
|
|
518
|
+
}
|
|
519
|
+
throw new Error('NaN was used as a key');
|
|
520
|
+
}
|
|
521
|
+
mid = (lo + hi) >> 1;
|
|
522
|
+
}
|
|
523
|
+
return mid ^ failXor;
|
|
524
|
+
}
|
|
525
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
526
|
+
const emptyLeaf = new BNode([]);
|
|
527
|
+
emptyLeaf.isShared = true;
|
|
528
|
+
//# sourceMappingURL=btree-set.js.map
|