@rocicorp/zero 0.25.0-canary.12 → 0.25.0-canary.14
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/zero/package.json.js +1 -1
- package/out/zero/src/pg.js +4 -2
- package/out/zero/src/server.js +4 -2
- package/out/zero-cache/src/config/zero-config.d.ts +0 -4
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +5 -15
- package/out/zero-cache/src/config/zero-config.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 +2 -8
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/server/otel-diag-logger.js +1 -0
- package/out/zero-cache/src/server/otel-diag-logger.js.map +1 -1
- 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 +62 -42
- package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/control.d.ts +1 -0
- package/out/zero-cache/src/services/change-source/protocol/current/control.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/control.js +5 -1
- package/out/zero-cache/src/services/change-source/protocol/current/control.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +2 -0
- 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/json.d.ts +8 -0
- package/out/zero-cache/src/services/change-source/protocol/current/json.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-source/protocol/current/json.js +19 -0
- package/out/zero-cache/src/services/change-source/protocol/current/json.js.map +1 -0
- package/out/zero-cache/src/services/change-source/protocol/current.d.ts +1 -0
- package/out/zero-cache/src/services/change-source/protocol/current.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current.js +3 -0
- package/out/zero-cache/src/services/change-source/protocol/current.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +0 -2
- 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 +0 -5
- 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.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +8 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -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 +2 -3
- package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
- package/out/zero-cache/src/services/http-service.d.ts +0 -1
- package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
- package/out/zero-cache/src/services/http-service.js +0 -4
- package/out/zero-cache/src/services/http-service.js.map +1 -1
- package/out/zero-cache/src/services/replicator/replication-status.d.ts +2 -0
- package/out/zero-cache/src/services/replicator/replication-status.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/replication-status.js +14 -1
- package/out/zero-cache/src/services/replicator/replication-status.js.map +1 -1
- package/out/zero-client/src/client/connection-manager.d.ts +3 -3
- package/out/zero-client/src/client/connection-manager.d.ts.map +1 -1
- package/out/zero-client/src/client/connection-manager.js.map +1 -1
- package/out/zero-client/src/client/connection.d.ts.map +1 -1
- package/out/zero-client/src/client/connection.js +8 -1
- package/out/zero-client/src/client/connection.js.map +1 -1
- package/out/zero-client/src/client/custom.d.ts.map +1 -1
- package/out/zero-client/src/client/custom.js +4 -3
- package/out/zero-client/src/client/custom.js.map +1 -1
- package/out/zero-client/src/client/error.d.ts +6 -1
- package/out/zero-client/src/client/error.d.ts.map +1 -1
- package/out/zero-client/src/client/error.js +2 -2
- package/out/zero-client/src/client/error.js.map +1 -1
- package/out/zero-client/src/client/make-mutate-property.d.ts +6 -9
- package/out/zero-client/src/client/make-mutate-property.d.ts.map +1 -1
- package/out/zero-client/src/client/make-mutate-property.js +3 -8
- package/out/zero-client/src/client/make-mutate-property.js.map +1 -1
- package/out/zero-client/src/client/mutator-proxy.d.ts +3 -2
- package/out/zero-client/src/client/mutator-proxy.d.ts.map +1 -1
- package/out/zero-client/src/client/mutator-proxy.js +15 -3
- package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.js +8 -8
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-events/src/status.d.ts +1 -1
- package/out/zero-events/src/status.d.ts.map +1 -1
- package/out/zero-schema/src/permissions.d.ts +3 -0
- package/out/zero-schema/src/permissions.d.ts.map +1 -1
- package/out/zero-schema/src/permissions.js.map +1 -1
- package/out/zero-server/src/custom.d.ts +2 -2
- package/out/zero-server/src/custom.d.ts.map +1 -1
- package/out/zero-server/src/custom.js +40 -4
- package/out/zero-server/src/custom.js.map +1 -1
- package/out/zero-server/src/mod.d.ts +1 -1
- package/out/zero-server/src/mod.d.ts.map +1 -1
- package/out/zero-server/src/process-mutations.d.ts +10 -6
- package/out/zero-server/src/process-mutations.d.ts.map +1 -1
- package/out/zero-server/src/process-mutations.js +9 -18
- package/out/zero-server/src/process-mutations.js.map +1 -1
- package/out/zero-server/src/push-processor.d.ts.map +1 -1
- package/out/zero-server/src/push-processor.js +10 -8
- package/out/zero-server/src/push-processor.js.map +1 -1
- package/out/zero-server/src/queries/process-queries.d.ts +14 -2
- package/out/zero-server/src/queries/process-queries.d.ts.map +1 -1
- package/out/zero-server/src/queries/process-queries.js +18 -15
- package/out/zero-server/src/queries/process-queries.js.map +1 -1
- package/out/zero-server/src/zql-database.d.ts.map +1 -1
- package/out/zero-server/src/zql-database.js +1 -5
- package/out/zero-server/src/zql-database.js.map +1 -1
- package/out/zql/src/builder/builder.d.ts.map +1 -1
- package/out/zql/src/builder/builder.js +0 -1
- package/out/zql/src/builder/builder.js.map +1 -1
- package/out/zql/src/ivm/data.js +0 -11
- package/out/zql/src/ivm/data.js.map +1 -1
- package/out/zql/src/ivm/exists.d.ts +2 -2
- package/out/zql/src/ivm/exists.d.ts.map +1 -1
- package/out/zql/src/ivm/exists.js +34 -20
- 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 +4 -2
- package/out/zql/src/ivm/fan-in.js.map +1 -1
- package/out/zql/src/ivm/fan-out.d.ts +1 -1
- package/out/zql/src/ivm/fan-out.d.ts.map +1 -1
- package/out/zql/src/ivm/fan-out.js +9 -3
- package/out/zql/src/ivm/fan-out.js.map +1 -1
- package/out/zql/src/ivm/filter-operators.d.ts +4 -6
- package/out/zql/src/ivm/filter-operators.d.ts.map +1 -1
- package/out/zql/src/ivm/filter-operators.js +14 -27
- package/out/zql/src/ivm/filter-operators.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 +4 -2
- package/out/zql/src/ivm/filter.js.map +1 -1
- package/out/zql/src/ivm/flipped-join.d.ts +0 -1
- package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
- package/out/zql/src/ivm/flipped-join.js +0 -2
- package/out/zql/src/ivm/flipped-join.js.map +1 -1
- package/out/zql/src/ivm/join.d.ts +2 -15
- package/out/zql/src/ivm/join.d.ts.map +1 -1
- package/out/zql/src/ivm/join.js +33 -96
- package/out/zql/src/ivm/join.js.map +1 -1
- package/out/zql/src/ivm/memory-source.d.ts +4 -3
- package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-source.js +24 -23
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/ivm/operator.d.ts +0 -12
- package/out/zql/src/ivm/operator.d.ts.map +1 -1
- package/out/zql/src/ivm/operator.js.map +1 -1
- package/out/zql/src/ivm/skip.d.ts +0 -1
- package/out/zql/src/ivm/skip.d.ts.map +1 -1
- package/out/zql/src/ivm/skip.js +3 -11
- package/out/zql/src/ivm/skip.js.map +1 -1
- package/out/zql/src/ivm/take.d.ts +0 -1
- package/out/zql/src/ivm/take.d.ts.map +1 -1
- package/out/zql/src/ivm/take.js +0 -17
- package/out/zql/src/ivm/take.js.map +1 -1
- package/out/zql/src/ivm/union-fan-in.d.ts +0 -1
- package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
- package/out/zql/src/ivm/union-fan-in.js +0 -3
- package/out/zql/src/ivm/union-fan-in.js.map +1 -1
- package/out/zql/src/ivm/union-fan-out.d.ts +0 -1
- package/out/zql/src/ivm/union-fan-out.d.ts.map +1 -1
- package/out/zql/src/ivm/union-fan-out.js +0 -3
- package/out/zql/src/ivm/union-fan-out.js.map +1 -1
- package/out/zql/src/ivm/view-apply-change.d.ts.map +1 -1
- package/out/zql/src/ivm/view-apply-change.js +1 -2
- package/out/zql/src/ivm/view-apply-change.js.map +1 -1
- package/out/zql/src/mutate/mutator.d.ts +2 -2
- package/out/zql/src/mutate/mutator.d.ts.map +1 -1
- package/out/zql/src/mutate/mutator.js.map +1 -1
- package/out/zql/src/query/create-builder.d.ts +2 -2
- package/out/zql/src/query/create-builder.d.ts.map +1 -1
- package/out/zql/src/query/create-builder.js +12 -3
- package/out/zql/src/query/create-builder.js.map +1 -1
- package/out/zql/src/query/measure-push-operator.d.ts +0 -1
- package/out/zql/src/query/measure-push-operator.d.ts.map +1 -1
- package/out/zql/src/query/measure-push-operator.js +0 -3
- package/out/zql/src/query/measure-push-operator.js.map +1 -1
- package/out/zql/src/query/query.d.ts +18 -5
- package/out/zql/src/query/query.d.ts.map +1 -1
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +6 -10
- package/out/zqlite/src/table-source.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-source.js","sources":["../../../../../zql/src/ivm/memory-source.ts"],"sourcesContent":["import {assert, unreachable} from '../../../shared/src/asserts.ts';\nimport {BTreeSet} from '../../../shared/src/btree-set.ts';\nimport {hasOwn} from '../../../shared/src/has-own.ts';\nimport {once} from '../../../shared/src/iterables.ts';\nimport type {\n Condition,\n Ordering,\n OrderPart,\n} from '../../../zero-protocol/src/ast.ts';\nimport type {Row, Value} from '../../../zero-protocol/src/data.ts';\nimport type {PrimaryKey} from '../../../zero-protocol/src/primary-key.ts';\nimport type {SchemaValue} from '../../../zero-types/src/schema-value.ts';\nimport type {DebugDelegate} from '../builder/debug-delegate.ts';\nimport {\n createPredicate,\n transformFilters,\n type NoSubqueryCondition,\n} from '../builder/filter.ts';\nimport {assertOrderingIncludesPK} from '../query/complete-ordering.ts';\nimport type {Change} from './change.ts';\nimport {\n constraintMatchesPrimaryKey,\n constraintMatchesRow,\n primaryKeyConstraintFromFilters,\n type Constraint,\n} from './constraint.ts';\nimport {\n compareValues,\n makeComparator,\n valuesEqual,\n type Comparator,\n type Node,\n} from './data.ts';\nimport {filterPush} from './filter-push.ts';\nimport {\n skipYields,\n type FetchRequest,\n type Input,\n type Output,\n type Start,\n} from './operator.ts';\nimport type {SourceSchema} from './schema.ts';\nimport type {\n Source,\n SourceChange,\n SourceChangeAdd,\n SourceChangeEdit,\n SourceChangeRemove,\n SourceInput,\n} from './source.ts';\nimport type {Stream} from './stream.ts';\n\nexport type Overlay = {\n outputIndex: number;\n change: SourceChange;\n};\n\nexport type Overlays = {\n add: Row | undefined;\n remove: Row | undefined;\n};\n\ntype Index = {\n comparator: Comparator;\n data: BTreeSet<Row>;\n usedBy: Set<Connection>;\n};\n\nexport type Connection = {\n input: Input;\n output: Output | undefined;\n sort: Ordering;\n splitEditKeys: Set<string> | undefined;\n compareRows: Comparator;\n filters:\n | {\n condition: NoSubqueryCondition;\n predicate: (row: Row) => boolean;\n }\n | undefined;\n readonly debug?: DebugDelegate | undefined;\n};\n\n/**\n * A `MemorySource` is a source that provides data to the pipeline from an\n * in-memory data source.\n *\n * This data is kept in sorted order as downstream pipelines will always expect\n * the data they receive from `pull` to be in sorted order.\n */\nexport class MemorySource implements Source {\n readonly #tableName: string;\n readonly #columns: Record<string, SchemaValue>;\n readonly #primaryKey: PrimaryKey;\n readonly #primaryIndexSort: Ordering;\n readonly #indexes: Map<string, Index> = new Map();\n readonly #connections: Connection[] = [];\n\n #overlay: Overlay | undefined;\n\n constructor(\n tableName: string,\n columns: Record<string, SchemaValue>,\n primaryKey: PrimaryKey,\n primaryIndexData?: BTreeSet<Row>,\n ) {\n this.#tableName = tableName;\n this.#columns = columns;\n this.#primaryKey = primaryKey;\n this.#primaryIndexSort = primaryKey.map(k => [k, 'asc']);\n const comparator = makeBoundComparator(this.#primaryIndexSort);\n this.#indexes.set(JSON.stringify(this.#primaryIndexSort), {\n comparator,\n data: primaryIndexData ?? new BTreeSet<Row>(comparator),\n usedBy: new Set(),\n });\n }\n\n get tableSchema() {\n return {\n name: this.#tableName,\n columns: this.#columns,\n primaryKey: this.#primaryKey,\n };\n }\n\n fork() {\n const primaryIndex = this.#getPrimaryIndex();\n return new MemorySource(\n this.#tableName,\n this.#columns,\n this.#primaryKey,\n primaryIndex.data.clone(),\n );\n }\n\n get data(): BTreeSet<Row> {\n return this.#getPrimaryIndex().data;\n }\n\n #getSchema(connection: Connection): SourceSchema {\n return {\n tableName: this.#tableName,\n columns: this.#columns,\n primaryKey: this.#primaryKey,\n sort: connection.sort,\n system: 'client',\n relationships: {},\n isHidden: false,\n compareRows: connection.compareRows,\n };\n }\n\n connect(\n sort: Ordering,\n filters?: Condition,\n splitEditKeys?: Set<string>,\n ): SourceInput {\n const transformedFilters = transformFilters(filters);\n\n const input: SourceInput = {\n getSchema: () => schema,\n fetch: req => this.#fetch(req, connection),\n cleanup: req => this.#cleanup(req, connection),\n setOutput: output => {\n connection.output = output;\n },\n destroy: () => {\n this.#disconnect(input);\n },\n fullyAppliedFilters: !transformedFilters.conditionsRemoved,\n };\n\n const connection: Connection = {\n input,\n output: undefined,\n sort,\n splitEditKeys,\n compareRows: makeComparator(sort),\n filters: transformedFilters.filters\n ? {\n condition: transformedFilters.filters,\n predicate: createPredicate(transformedFilters.filters),\n }\n : undefined,\n };\n const schema = this.#getSchema(connection);\n assertOrderingIncludesPK(sort, this.#primaryKey);\n this.#connections.push(connection);\n return input;\n }\n\n #disconnect(input: Input): void {\n const idx = this.#connections.findIndex(c => c.input === input);\n assert(idx !== -1, 'Connection not found');\n this.#connections.splice(idx, 1);\n\n // TODO: We used to delete unused indexes here. But in common cases like\n // navigating into issue detail pages it caused a ton of constantly\n // building and destroying indexes.\n //\n // Perhaps some intelligent LRU or something is needed here but for now,\n // the opposite extreme of keeping all indexes for the lifetime of the\n // page seems better.\n }\n\n #getPrimaryIndex(): Index {\n const index = this.#indexes.get(JSON.stringify(this.#primaryIndexSort));\n assert(index, 'Primary index not found');\n return index;\n }\n\n #getOrCreateIndex(sort: Ordering, usedBy: Connection): Index {\n const key = JSON.stringify(sort);\n const index = this.#indexes.get(key);\n // Future optimization could use existing index if it's the same just sorted\n // in reverse of needed.\n if (index) {\n index.usedBy.add(usedBy);\n return index;\n }\n\n const comparator = makeBoundComparator(sort);\n\n // When creating these synchronously becomes a problem, a few options:\n // 1. Allow users to specify needed indexes up front\n // 2. Create indexes in a different thread asynchronously (this would require\n // modifying the BTree to be able to be passed over structured-clone, or using\n // a different library.)\n // 3. We could even theoretically do (2) on multiple threads and then merge the\n // results!\n const data = new BTreeSet<Row>(comparator);\n\n // I checked, there's no special path for adding data in bulk faster.\n // The constructor takes an array, but it just calls add/set over and over.\n for (const row of this.#getPrimaryIndex().data) {\n data.add(row);\n }\n\n const newIndex = {comparator, data, usedBy: new Set([usedBy])};\n this.#indexes.set(key, newIndex);\n return newIndex;\n }\n\n // For unit testing that we correctly clean up indexes.\n getIndexKeys(): string[] {\n return [...this.#indexes.keys()];\n }\n\n *#fetch(req: FetchRequest, from: Connection): Stream<Node | 'yield'> {\n const callingConnectionIndex = this.#connections.indexOf(from);\n assert(callingConnectionIndex !== -1, 'Output not found');\n const conn = this.#connections[callingConnectionIndex];\n const {sort: requestedSort, compareRows} = conn;\n const connectionComparator = (r1: Row, r2: Row) =>\n compareRows(r1, r2) * (req.reverse ? -1 : 1);\n\n const pkConstraint = primaryKeyConstraintFromFilters(\n conn.filters?.condition,\n this.#primaryKey,\n );\n // The primary key constraint will be more limiting than the constraint\n // so swap out to that if it exists.\n const fetchOrPkConstraint = pkConstraint ?? req.constraint;\n\n // If there is a constraint, we need an index sorted by it first.\n const indexSort: OrderPart[] = [];\n if (fetchOrPkConstraint) {\n for (const key of Object.keys(fetchOrPkConstraint)) {\n indexSort.push([key, 'asc']);\n }\n }\n\n // For the special case of constraining by PK, we don't need to worry about\n // any requested sort since there can only be one result. Otherwise we also\n // need the index sorted by the requested sort.\n if (\n this.#primaryKey.length > 1 ||\n !fetchOrPkConstraint ||\n !constraintMatchesPrimaryKey(fetchOrPkConstraint, this.#primaryKey)\n ) {\n indexSort.push(...requestedSort);\n }\n\n const index = this.#getOrCreateIndex(indexSort, from);\n const {data, comparator: compare} = index;\n const indexComparator = (r1: Row, r2: Row) =>\n compare(r1, r2) * (req.reverse ? -1 : 1);\n\n const startAt = req.start?.row;\n\n // If there is a constraint, we want to start our scan at the first row that\n // matches the constraint. But because the next OrderPart can be `desc`,\n // it's not true that {[constraintKey]: constraintValue} is the first\n // matching row. Because in that case, the other fields will all be\n // `undefined`, and in Zero `undefined` is always less than any other value.\n // So if the second OrderPart is descending then `undefined` values will\n // actually be the *last* row. We need a way to stay \"start at the first row\n // with this constraint value\". RowBound with the corresponding compareBound\n // comparator accomplishes this. The right thing is probably to teach the\n // btree library to support this concept.\n let scanStart: RowBound | undefined;\n\n if (fetchOrPkConstraint) {\n scanStart = {};\n for (const [key, dir] of indexSort) {\n if (hasOwn(fetchOrPkConstraint, key)) {\n scanStart[key] = fetchOrPkConstraint[key];\n } else {\n if (req.reverse) {\n scanStart[key] = dir === 'asc' ? maxValue : minValue;\n } else {\n scanStart[key] = dir === 'asc' ? minValue : maxValue;\n }\n }\n }\n } else {\n scanStart = startAt;\n }\n\n const rowsIterable = generateRows(data, scanStart, req.reverse);\n const withOverlay = generateWithOverlay(\n startAt,\n pkConstraint ? once(rowsIterable) : rowsIterable,\n // use `req.constraint` here and not `fetchOrPkConstraint` since `fetchOrPkConstraint` could be the\n // primary key constraint. The primary key constraint comes from filters and is acting as a filter\n // rather than as the fetch constraint.\n req.constraint,\n this.#overlay,\n callingConnectionIndex,\n // Use indexComparator, generateWithOverlayInner has a subtle dependency\n // on this. Since generateWithConstraint is done after\n // generateWithOverlay, the generator consumed by generateWithOverlayInner\n // does not end when the constraint stops matching and so the final\n // check to yield an add overlay if not yet yielded is not reached.\n // However, using the indexComparator the add overlay will be less than\n // the first row that does not match the constraint, and so any\n // not yet yielded add overlay will be yielded when the first row\n // not matching the constraint is reached.\n indexComparator,\n conn.filters?.predicate,\n );\n\n const withConstraint = generateWithConstraint(\n skipYields(\n generateWithStart(withOverlay, req.start, connectionComparator),\n ),\n // we use `req.constraint` and not `fetchOrPkConstraint` here because we need to\n // AND the constraint with what could have been the primary key constraint\n req.constraint,\n );\n\n yield* conn.filters\n ? generateWithFilter(withConstraint, conn.filters.predicate)\n : withConstraint;\n }\n\n #cleanup(req: FetchRequest, connection: Connection): Stream<Node> {\n return this.#fetch(req, connection) as Stream<Node>;\n }\n\n push(change: SourceChange): void {\n for (const _ of this.genPush(change)) {\n // Nothing to do.\n }\n }\n\n *genPush(change: SourceChange) {\n const primaryIndex = this.#getPrimaryIndex();\n const {data} = primaryIndex;\n const exists = (row: Row) => data.has(row);\n const setOverlay = (o: Overlay | undefined) => (this.#overlay = o);\n const writeChange = (c: SourceChange) => this.#writeChange(c);\n yield* genPushAndWriteWithSplitEdit(\n this.#connections,\n change,\n exists,\n setOverlay,\n writeChange,\n );\n }\n\n #writeChange(change: SourceChange) {\n for (const {data} of this.#indexes.values()) {\n switch (change.type) {\n case 'add': {\n const added = data.add(change.row);\n // must succeed since we checked has() above.\n assert(added);\n break;\n }\n case 'remove': {\n const removed = data.delete(change.row);\n // must succeed since we checked has() above.\n assert(removed);\n break;\n }\n case 'edit': {\n // TODO: We could see if the PK (form the index tree's perspective)\n // changed and if not we could use set.\n // We cannot just do `set` with the new value since the `oldRow` might\n // not map to the same entry as the new `row` in the index btree.\n const removed = data.delete(change.oldRow);\n // must succeed since we checked has() above.\n assert(removed);\n data.add(change.row);\n break;\n }\n default:\n unreachable(change);\n }\n }\n }\n}\n\nfunction* generateWithConstraint(\n it: Stream<Node>,\n constraint: Constraint | undefined,\n) {\n for (const node of it) {\n if (constraint && !constraintMatchesRow(constraint, node.row)) {\n break;\n }\n yield node;\n }\n}\n\nfunction* generateWithFilter(it: Stream<Node>, filter: (row: Row) => boolean) {\n for (const node of it) {\n if (filter(node.row)) {\n yield node;\n }\n }\n}\n\nexport function* genPushAndWriteWithSplitEdit(\n connections: readonly Connection[],\n change: SourceChange,\n exists: (row: Row) => boolean,\n setOverlay: (o: Overlay | undefined) => Overlay | undefined,\n writeChange: (c: SourceChange) => void,\n) {\n let shouldSplitEdit = false;\n if (change.type === 'edit') {\n for (const {splitEditKeys} of connections) {\n if (splitEditKeys) {\n for (const key of splitEditKeys) {\n if (!valuesEqual(change.row[key], change.oldRow[key])) {\n shouldSplitEdit = true;\n break;\n }\n }\n }\n }\n }\n\n if (change.type === 'edit' && shouldSplitEdit) {\n yield* genPushAndWrite(\n connections,\n {\n type: 'remove',\n row: change.oldRow,\n },\n exists,\n setOverlay,\n writeChange,\n );\n yield* genPushAndWrite(\n connections,\n {\n type: 'add',\n row: change.row,\n },\n exists,\n setOverlay,\n writeChange,\n );\n } else {\n yield* genPushAndWrite(\n connections,\n change,\n exists,\n setOverlay,\n writeChange,\n );\n }\n}\n\nfunction* genPushAndWrite(\n connections: readonly Connection[],\n change: SourceChangeAdd | SourceChangeRemove | SourceChangeEdit,\n exists: (row: Row) => boolean,\n setOverlay: (o: Overlay | undefined) => Overlay | undefined,\n writeChange: (c: SourceChange) => void,\n) {\n for (const x of genPush(connections, change, exists, setOverlay)) {\n yield x;\n }\n writeChange(change);\n}\n\nfunction* genPush(\n connections: readonly Connection[],\n change: SourceChange,\n exists: (row: Row) => boolean,\n setOverlay: (o: Overlay | undefined) => void,\n) {\n switch (change.type) {\n case 'add':\n assert(\n !exists(change.row),\n () => `Row already exists ${stringify(change)}`,\n );\n break;\n case 'remove':\n assert(exists(change.row), () => `Row not found ${stringify(change)}`);\n break;\n case 'edit':\n assert(exists(change.oldRow), () => `Row not found ${stringify(change)}`);\n break;\n default:\n unreachable(change);\n }\n\n for (const [outputIndex, {output, filters, input}] of connections.entries()) {\n if (output) {\n setOverlay({outputIndex, change});\n const outputChange: Change =\n change.type === 'edit'\n ? {\n type: change.type,\n oldNode: {\n row: change.oldRow,\n relationships: {},\n },\n node: {\n row: change.row,\n relationships: {},\n },\n }\n : {\n type: change.type,\n node: {\n row: change.row,\n relationships: {},\n },\n };\n filterPush(outputChange, output, input, filters?.predicate);\n yield;\n }\n }\n\n setOverlay(undefined);\n}\n\nexport function* generateWithStart(\n nodes: Iterable<Node | 'yield'>,\n start: Start | undefined,\n compare: (r1: Row, r2: Row) => number,\n): Stream<Node | 'yield'> {\n if (!start) {\n yield* nodes;\n return;\n }\n let started = false;\n for (const node of nodes) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n if (!started) {\n if (start.basis === 'at') {\n if (compare(node.row, start.row) >= 0) {\n started = true;\n }\n } else if (start.basis === 'after') {\n if (compare(node.row, start.row) > 0) {\n started = true;\n }\n }\n }\n if (started) {\n yield node;\n }\n }\n}\n\n/**\n * Takes an iterator and overlay.\n * Splices the overlay into the iterator at the correct position.\n *\n * @param startAt - if there is a lower bound to the stream. If the lower bound of the stream\n * is above the overlay, the overlay will be skipped.\n * @param rows - the stream into which the overlay should be spliced\n * @param constraint - constraint that was applied to the rowIterator and should\n * also be applied to the overlay.\n * @param overlay - the overlay values to splice in\n * @param compare - the comparator to use to find the position for the overlay\n */\nexport function* generateWithOverlay(\n startAt: Row | undefined,\n rows: Iterable<Row>,\n constraint: Constraint | undefined,\n overlay: Overlay | undefined,\n connectionIndex: number,\n compare: Comparator,\n filterPredicate?: (row: Row) => boolean | undefined,\n) {\n let overlayToApply: Overlay | undefined = undefined;\n if (overlay && connectionIndex <= overlay.outputIndex) {\n overlayToApply = overlay;\n }\n const overlays = computeOverlays(\n startAt,\n constraint,\n overlayToApply,\n compare,\n filterPredicate,\n );\n yield* generateWithOverlayInner(rows, overlays, compare);\n}\n\nfunction computeOverlays(\n startAt: Row | undefined,\n constraint: Constraint | undefined,\n overlay: Overlay | undefined,\n compare: Comparator,\n filterPredicate?: (row: Row) => boolean | undefined,\n): Overlays {\n let overlays: Overlays = {\n add: undefined,\n remove: undefined,\n };\n switch (overlay?.change.type) {\n case 'add':\n overlays = {\n add: overlay.change.row,\n remove: undefined,\n };\n break;\n case 'remove':\n overlays = {\n add: undefined,\n remove: overlay.change.row,\n };\n break;\n case 'edit':\n overlays = {\n add: overlay.change.row,\n remove: overlay.change.oldRow,\n };\n break;\n }\n\n if (startAt) {\n overlays = overlaysForStartAt(overlays, startAt, compare);\n }\n\n if (constraint) {\n overlays = overlaysForConstraint(overlays, constraint);\n }\n\n if (filterPredicate) {\n overlays = overlaysForFilterPredicate(overlays, filterPredicate);\n }\n\n return overlays;\n}\n\nexport {overlaysForStartAt as overlaysForStartAtForTest};\n\nfunction overlaysForStartAt(\n {add, remove}: Overlays,\n startAt: Row,\n compare: Comparator,\n): Overlays {\n const undefinedIfBeforeStartAt = (row: Row | undefined) =>\n row === undefined || compare(row, startAt) < 0 ? undefined : row;\n return {\n add: undefinedIfBeforeStartAt(add),\n remove: undefinedIfBeforeStartAt(remove),\n };\n}\n\nexport {overlaysForConstraint as overlaysForConstraintForTest};\n\nfunction overlaysForConstraint(\n {add, remove}: Overlays,\n constraint: Constraint,\n): Overlays {\n const undefinedIfDoesntMatchConstraint = (row: Row | undefined) =>\n row === undefined || !constraintMatchesRow(constraint, row)\n ? undefined\n : row;\n\n return {\n add: undefinedIfDoesntMatchConstraint(add),\n remove: undefinedIfDoesntMatchConstraint(remove),\n };\n}\n\nfunction overlaysForFilterPredicate(\n {add, remove}: Overlays,\n filterPredicate: (row: Row) => boolean | undefined,\n): Overlays {\n const undefinedIfDoesntMatchFilter = (row: Row | undefined) =>\n row === undefined || !filterPredicate(row) ? undefined : row;\n\n return {\n add: undefinedIfDoesntMatchFilter(add),\n remove: undefinedIfDoesntMatchFilter(remove),\n };\n}\n\nexport function* generateWithOverlayInner(\n rowIterator: Iterable<Row>,\n overlays: Overlays,\n compare: (r1: Row, r2: Row) => number,\n) {\n let addOverlayYielded = false;\n let removeOverlaySkipped = false;\n for (const row of rowIterator) {\n if (!addOverlayYielded && overlays.add) {\n const cmp = compare(overlays.add, row);\n if (cmp < 0) {\n addOverlayYielded = true;\n yield {row: overlays.add, relationships: {}};\n }\n }\n\n if (!removeOverlaySkipped && overlays.remove) {\n const cmp = compare(overlays.remove, row);\n if (cmp === 0) {\n removeOverlaySkipped = true;\n continue;\n }\n }\n yield {row, relationships: {}};\n }\n\n if (!addOverlayYielded && overlays.add) {\n yield {row: overlays.add, relationships: {}};\n }\n}\n\n/**\n * A location to begin scanning an index from. Can either be a specific value\n * or the min or max possible value for the type. This is used to start a scan\n * at the beginning of the rows matching a constraint.\n */\ntype Bound = Value | MinValue | MaxValue;\ntype RowBound = Record<string, Bound>;\nconst minValue = Symbol('min-value');\ntype MinValue = typeof minValue;\nconst maxValue = Symbol('max-value');\ntype MaxValue = typeof maxValue;\n\nfunction makeBoundComparator(sort: Ordering) {\n return (a: RowBound, b: RowBound) => {\n // Hot! Do not use destructuring\n for (const entry of sort) {\n const key = entry[0];\n const cmp = compareBounds(a[key], b[key]);\n if (cmp !== 0) {\n return entry[1] === 'asc' ? cmp : -cmp;\n }\n }\n return 0;\n };\n}\n\nfunction compareBounds(a: Bound, b: Bound): number {\n if (a === b) {\n return 0;\n }\n if (a === minValue) {\n return -1;\n }\n if (b === minValue) {\n return 1;\n }\n if (a === maxValue) {\n return 1;\n }\n if (b === maxValue) {\n return -1;\n }\n return compareValues(a, b);\n}\n\nfunction* generateRows(\n data: BTreeSet<Row>,\n scanStart: RowBound | undefined,\n reverse: boolean | undefined,\n) {\n yield* data[reverse ? 'valuesFromReversed' : 'valuesFrom'](\n scanStart as Row | undefined,\n );\n}\n\nexport function stringify(change: SourceChange) {\n return JSON.stringify(change, (_, v) =>\n typeof v === 'bigint' ? v.toString() : v,\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"memory-source.js","sources":["../../../../../zql/src/ivm/memory-source.ts"],"sourcesContent":["import {assert, unreachable} from '../../../shared/src/asserts.ts';\nimport {BTreeSet} from '../../../shared/src/btree-set.ts';\nimport {hasOwn} from '../../../shared/src/has-own.ts';\nimport {once} from '../../../shared/src/iterables.ts';\nimport type {\n Condition,\n Ordering,\n OrderPart,\n} from '../../../zero-protocol/src/ast.ts';\nimport type {Row, Value} from '../../../zero-protocol/src/data.ts';\nimport type {PrimaryKey} from '../../../zero-protocol/src/primary-key.ts';\nimport type {SchemaValue} from '../../../zero-types/src/schema-value.ts';\nimport type {DebugDelegate} from '../builder/debug-delegate.ts';\nimport {\n createPredicate,\n transformFilters,\n type NoSubqueryCondition,\n} from '../builder/filter.ts';\nimport {assertOrderingIncludesPK} from '../query/complete-ordering.ts';\nimport type {Change} from './change.ts';\nimport {\n constraintMatchesPrimaryKey,\n constraintMatchesRow,\n primaryKeyConstraintFromFilters,\n type Constraint,\n} from './constraint.ts';\nimport {\n compareValues,\n makeComparator,\n valuesEqual,\n type Comparator,\n type Node,\n} from './data.ts';\nimport {filterPush} from './filter-push.ts';\nimport {\n skipYields,\n type FetchRequest,\n type Input,\n type Output,\n type Start,\n} from './operator.ts';\nimport type {SourceSchema} from './schema.ts';\nimport type {\n Source,\n SourceChange,\n SourceChangeAdd,\n SourceChangeEdit,\n SourceChangeRemove,\n SourceInput,\n} from './source.ts';\nimport type {Stream} from './stream.ts';\n\nexport type Overlay = {\n epoch: number;\n change: SourceChange;\n};\n\nexport type Overlays = {\n add: Row | undefined;\n remove: Row | undefined;\n};\n\ntype Index = {\n comparator: Comparator;\n data: BTreeSet<Row>;\n usedBy: Set<Connection>;\n};\n\nexport type Connection = {\n input: Input;\n output: Output | undefined;\n sort: Ordering;\n splitEditKeys: Set<string> | undefined;\n compareRows: Comparator;\n filters:\n | {\n condition: NoSubqueryCondition;\n predicate: (row: Row) => boolean;\n }\n | undefined;\n readonly debug?: DebugDelegate | undefined;\n lastPushedEpoch: number;\n};\n\n/**\n * A `MemorySource` is a source that provides data to the pipeline from an\n * in-memory data source.\n *\n * This data is kept in sorted order as downstream pipelines will always expect\n * the data they receive from `pull` to be in sorted order.\n */\nexport class MemorySource implements Source {\n readonly #tableName: string;\n readonly #columns: Record<string, SchemaValue>;\n readonly #primaryKey: PrimaryKey;\n readonly #primaryIndexSort: Ordering;\n readonly #indexes: Map<string, Index> = new Map();\n readonly #connections: Connection[] = [];\n\n #overlay: Overlay | undefined;\n #pushEpoch = 0;\n\n constructor(\n tableName: string,\n columns: Record<string, SchemaValue>,\n primaryKey: PrimaryKey,\n primaryIndexData?: BTreeSet<Row>,\n ) {\n this.#tableName = tableName;\n this.#columns = columns;\n this.#primaryKey = primaryKey;\n this.#primaryIndexSort = primaryKey.map(k => [k, 'asc']);\n const comparator = makeBoundComparator(this.#primaryIndexSort);\n this.#indexes.set(JSON.stringify(this.#primaryIndexSort), {\n comparator,\n data: primaryIndexData ?? new BTreeSet<Row>(comparator),\n usedBy: new Set(),\n });\n }\n\n get tableSchema() {\n return {\n name: this.#tableName,\n columns: this.#columns,\n primaryKey: this.#primaryKey,\n };\n }\n\n fork() {\n const primaryIndex = this.#getPrimaryIndex();\n return new MemorySource(\n this.#tableName,\n this.#columns,\n this.#primaryKey,\n primaryIndex.data.clone(),\n );\n }\n\n get data(): BTreeSet<Row> {\n return this.#getPrimaryIndex().data;\n }\n\n #getSchema(connection: Connection): SourceSchema {\n return {\n tableName: this.#tableName,\n columns: this.#columns,\n primaryKey: this.#primaryKey,\n sort: connection.sort,\n system: 'client',\n relationships: {},\n isHidden: false,\n compareRows: connection.compareRows,\n };\n }\n\n connect(\n sort: Ordering,\n filters?: Condition,\n splitEditKeys?: Set<string>,\n ): SourceInput {\n const transformedFilters = transformFilters(filters);\n\n const input: SourceInput = {\n getSchema: () => schema,\n fetch: req => this.#fetch(req, connection),\n setOutput: output => {\n connection.output = output;\n },\n destroy: () => {\n this.#disconnect(input);\n },\n fullyAppliedFilters: !transformedFilters.conditionsRemoved,\n };\n\n const connection: Connection = {\n input,\n output: undefined,\n sort,\n splitEditKeys,\n compareRows: makeComparator(sort),\n filters: transformedFilters.filters\n ? {\n condition: transformedFilters.filters,\n predicate: createPredicate(transformedFilters.filters),\n }\n : undefined,\n lastPushedEpoch: 0,\n };\n const schema = this.#getSchema(connection);\n assertOrderingIncludesPK(sort, this.#primaryKey);\n this.#connections.push(connection);\n return input;\n }\n\n #disconnect(input: Input): void {\n const idx = this.#connections.findIndex(c => c.input === input);\n assert(idx !== -1, 'Connection not found');\n this.#connections.splice(idx, 1);\n\n // TODO: We used to delete unused indexes here. But in common cases like\n // navigating into issue detail pages it caused a ton of constantly\n // building and destroying indexes.\n //\n // Perhaps some intelligent LRU or something is needed here but for now,\n // the opposite extreme of keeping all indexes for the lifetime of the\n // page seems better.\n }\n\n #getPrimaryIndex(): Index {\n const index = this.#indexes.get(JSON.stringify(this.#primaryIndexSort));\n assert(index, 'Primary index not found');\n return index;\n }\n\n #getOrCreateIndex(sort: Ordering, usedBy: Connection): Index {\n const key = JSON.stringify(sort);\n const index = this.#indexes.get(key);\n // Future optimization could use existing index if it's the same just sorted\n // in reverse of needed.\n if (index) {\n index.usedBy.add(usedBy);\n return index;\n }\n\n const comparator = makeBoundComparator(sort);\n\n // When creating these synchronously becomes a problem, a few options:\n // 1. Allow users to specify needed indexes up front\n // 2. Create indexes in a different thread asynchronously (this would require\n // modifying the BTree to be able to be passed over structured-clone, or using\n // a different library.)\n // 3. We could even theoretically do (2) on multiple threads and then merge the\n // results!\n const data = new BTreeSet<Row>(comparator);\n\n // I checked, there's no special path for adding data in bulk faster.\n // The constructor takes an array, but it just calls add/set over and over.\n for (const row of this.#getPrimaryIndex().data) {\n data.add(row);\n }\n\n const newIndex = {comparator, data, usedBy: new Set([usedBy])};\n this.#indexes.set(key, newIndex);\n return newIndex;\n }\n\n // For unit testing that we correctly clean up indexes.\n getIndexKeys(): string[] {\n return [...this.#indexes.keys()];\n }\n\n *#fetch(req: FetchRequest, conn: Connection): Stream<Node | 'yield'> {\n const {sort: requestedSort, compareRows} = conn;\n const connectionComparator = (r1: Row, r2: Row) =>\n compareRows(r1, r2) * (req.reverse ? -1 : 1);\n\n const pkConstraint = primaryKeyConstraintFromFilters(\n conn.filters?.condition,\n this.#primaryKey,\n );\n // The primary key constraint will be more limiting than the constraint\n // so swap out to that if it exists.\n const fetchOrPkConstraint = pkConstraint ?? req.constraint;\n\n // If there is a constraint, we need an index sorted by it first.\n const indexSort: OrderPart[] = [];\n if (fetchOrPkConstraint) {\n for (const key of Object.keys(fetchOrPkConstraint)) {\n indexSort.push([key, 'asc']);\n }\n }\n\n // For the special case of constraining by PK, we don't need to worry about\n // any requested sort since there can only be one result. Otherwise we also\n // need the index sorted by the requested sort.\n if (\n this.#primaryKey.length > 1 ||\n !fetchOrPkConstraint ||\n !constraintMatchesPrimaryKey(fetchOrPkConstraint, this.#primaryKey)\n ) {\n indexSort.push(...requestedSort);\n }\n\n const index = this.#getOrCreateIndex(indexSort, conn);\n const {data, comparator: compare} = index;\n const indexComparator = (r1: Row, r2: Row) =>\n compare(r1, r2) * (req.reverse ? -1 : 1);\n\n const startAt = req.start?.row;\n\n // If there is a constraint, we want to start our scan at the first row that\n // matches the constraint. But because the next OrderPart can be `desc`,\n // it's not true that {[constraintKey]: constraintValue} is the first\n // matching row. Because in that case, the other fields will all be\n // `undefined`, and in Zero `undefined` is always less than any other value.\n // So if the second OrderPart is descending then `undefined` values will\n // actually be the *last* row. We need a way to stay \"start at the first row\n // with this constraint value\". RowBound with the corresponding compareBound\n // comparator accomplishes this. The right thing is probably to teach the\n // btree library to support this concept.\n let scanStart: RowBound | undefined;\n\n if (fetchOrPkConstraint) {\n scanStart = {};\n for (const [key, dir] of indexSort) {\n if (hasOwn(fetchOrPkConstraint, key)) {\n scanStart[key] = fetchOrPkConstraint[key];\n } else {\n if (req.reverse) {\n scanStart[key] = dir === 'asc' ? maxValue : minValue;\n } else {\n scanStart[key] = dir === 'asc' ? minValue : maxValue;\n }\n }\n }\n } else {\n scanStart = startAt;\n }\n\n const rowsIterable = generateRows(data, scanStart, req.reverse);\n const withOverlay = generateWithOverlay(\n startAt,\n pkConstraint ? once(rowsIterable) : rowsIterable,\n // use `req.constraint` here and not `fetchOrPkConstraint` since `fetchOrPkConstraint` could be the\n // primary key constraint. The primary key constraint comes from filters and is acting as a filter\n // rather than as the fetch constraint.\n req.constraint,\n this.#overlay,\n conn.lastPushedEpoch,\n // Use indexComparator, generateWithOverlayInner has a subtle dependency\n // on this. Since generateWithConstraint is done after\n // generateWithOverlay, the generator consumed by generateWithOverlayInner\n // does not end when the constraint stops matching and so the final\n // check to yield an add overlay if not yet yielded is not reached.\n // However, using the indexComparator the add overlay will be less than\n // the first row that does not match the constraint, and so any\n // not yet yielded add overlay will be yielded when the first row\n // not matching the constraint is reached.\n indexComparator,\n conn.filters?.predicate,\n );\n\n const withConstraint = generateWithConstraint(\n skipYields(\n generateWithStart(withOverlay, req.start, connectionComparator),\n ),\n // we use `req.constraint` and not `fetchOrPkConstraint` here because we need to\n // AND the constraint with what could have been the primary key constraint\n req.constraint,\n );\n\n yield* conn.filters\n ? generateWithFilter(withConstraint, conn.filters.predicate)\n : withConstraint;\n }\n\n push(change: SourceChange): void {\n for (const _ of this.genPush(change)) {\n // Nothing to do.\n }\n }\n\n *genPush(change: SourceChange) {\n const primaryIndex = this.#getPrimaryIndex();\n const {data} = primaryIndex;\n const exists = (row: Row) => data.has(row);\n const setOverlay = (o: Overlay | undefined) => (this.#overlay = o);\n const writeChange = (c: SourceChange) => this.#writeChange(c);\n yield* genPushAndWriteWithSplitEdit(\n this.#connections,\n change,\n exists,\n setOverlay,\n writeChange,\n () => ++this.#pushEpoch,\n );\n }\n\n #writeChange(change: SourceChange) {\n for (const {data} of this.#indexes.values()) {\n switch (change.type) {\n case 'add': {\n const added = data.add(change.row);\n // must succeed since we checked has() above.\n assert(added);\n break;\n }\n case 'remove': {\n const removed = data.delete(change.row);\n // must succeed since we checked has() above.\n assert(removed);\n break;\n }\n case 'edit': {\n // TODO: We could see if the PK (form the index tree's perspective)\n // changed and if not we could use set.\n // We cannot just do `set` with the new value since the `oldRow` might\n // not map to the same entry as the new `row` in the index btree.\n const removed = data.delete(change.oldRow);\n // must succeed since we checked has() above.\n assert(removed);\n data.add(change.row);\n break;\n }\n default:\n unreachable(change);\n }\n }\n }\n}\n\nfunction* generateWithConstraint(\n it: Stream<Node>,\n constraint: Constraint | undefined,\n) {\n for (const node of it) {\n if (constraint && !constraintMatchesRow(constraint, node.row)) {\n break;\n }\n yield node;\n }\n}\n\nfunction* generateWithFilter(it: Stream<Node>, filter: (row: Row) => boolean) {\n for (const node of it) {\n if (filter(node.row)) {\n yield node;\n }\n }\n}\n\nexport function* genPushAndWriteWithSplitEdit(\n connections: readonly Connection[],\n change: SourceChange,\n exists: (row: Row) => boolean,\n setOverlay: (o: Overlay | undefined) => Overlay | undefined,\n writeChange: (c: SourceChange) => void,\n getNextEpoch: () => number,\n) {\n let shouldSplitEdit = false;\n if (change.type === 'edit') {\n for (const {splitEditKeys} of connections) {\n if (splitEditKeys) {\n for (const key of splitEditKeys) {\n if (!valuesEqual(change.row[key], change.oldRow[key])) {\n shouldSplitEdit = true;\n break;\n }\n }\n }\n }\n }\n\n if (change.type === 'edit' && shouldSplitEdit) {\n yield* genPushAndWrite(\n connections,\n {\n type: 'remove',\n row: change.oldRow,\n },\n exists,\n setOverlay,\n writeChange,\n getNextEpoch(),\n );\n yield* genPushAndWrite(\n connections,\n {\n type: 'add',\n row: change.row,\n },\n exists,\n setOverlay,\n writeChange,\n getNextEpoch(),\n );\n } else {\n yield* genPushAndWrite(\n connections,\n change,\n exists,\n setOverlay,\n writeChange,\n getNextEpoch(),\n );\n }\n}\n\nfunction* genPushAndWrite(\n connections: readonly Connection[],\n change: SourceChangeAdd | SourceChangeRemove | SourceChangeEdit,\n exists: (row: Row) => boolean,\n setOverlay: (o: Overlay | undefined) => Overlay | undefined,\n writeChange: (c: SourceChange) => void,\n pushEpoch: number,\n) {\n for (const x of genPush(connections, change, exists, setOverlay, pushEpoch)) {\n yield x;\n }\n writeChange(change);\n}\n\nfunction* genPush(\n connections: readonly Connection[],\n change: SourceChange,\n exists: (row: Row) => boolean,\n setOverlay: (o: Overlay | undefined) => void,\n pushEpoch: number,\n) {\n switch (change.type) {\n case 'add':\n assert(\n !exists(change.row),\n () => `Row already exists ${stringify(change)}`,\n );\n break;\n case 'remove':\n assert(exists(change.row), () => `Row not found ${stringify(change)}`);\n break;\n case 'edit':\n assert(exists(change.oldRow), () => `Row not found ${stringify(change)}`);\n break;\n default:\n unreachable(change);\n }\n\n for (const conn of connections) {\n const {output, filters, input} = conn;\n if (output) {\n conn.lastPushedEpoch = pushEpoch;\n setOverlay({epoch: pushEpoch, change});\n const outputChange: Change =\n change.type === 'edit'\n ? {\n type: change.type,\n oldNode: {\n row: change.oldRow,\n relationships: {},\n },\n node: {\n row: change.row,\n relationships: {},\n },\n }\n : {\n type: change.type,\n node: {\n row: change.row,\n relationships: {},\n },\n };\n filterPush(outputChange, output, input, filters?.predicate);\n yield;\n }\n }\n\n setOverlay(undefined);\n}\n\nexport function* generateWithStart(\n nodes: Iterable<Node | 'yield'>,\n start: Start | undefined,\n compare: (r1: Row, r2: Row) => number,\n): Stream<Node | 'yield'> {\n if (!start) {\n yield* nodes;\n return;\n }\n let started = false;\n for (const node of nodes) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n if (!started) {\n if (start.basis === 'at') {\n if (compare(node.row, start.row) >= 0) {\n started = true;\n }\n } else if (start.basis === 'after') {\n if (compare(node.row, start.row) > 0) {\n started = true;\n }\n }\n }\n if (started) {\n yield node;\n }\n }\n}\n\n/**\n * Takes an iterator and overlay.\n * Splices the overlay into the iterator at the correct position.\n *\n * @param startAt - if there is a lower bound to the stream. If the lower bound of the stream\n * is above the overlay, the overlay will be skipped.\n * @param rows - the stream into which the overlay should be spliced\n * @param constraint - constraint that was applied to the rowIterator and should\n * also be applied to the overlay.\n * @param overlay - the overlay values to splice in\n * @param compare - the comparator to use to find the position for the overlay\n */\nexport function* generateWithOverlay(\n startAt: Row | undefined,\n rows: Iterable<Row>,\n constraint: Constraint | undefined,\n overlay: Overlay | undefined,\n lastPushedEpoch: number,\n compare: Comparator,\n filterPredicate?: (row: Row) => boolean | undefined,\n) {\n let overlayToApply: Overlay | undefined = undefined;\n if (overlay && lastPushedEpoch >= overlay.epoch) {\n overlayToApply = overlay;\n }\n const overlays = computeOverlays(\n startAt,\n constraint,\n overlayToApply,\n compare,\n filterPredicate,\n );\n yield* generateWithOverlayInner(rows, overlays, compare);\n}\n\nfunction computeOverlays(\n startAt: Row | undefined,\n constraint: Constraint | undefined,\n overlay: Overlay | undefined,\n compare: Comparator,\n filterPredicate?: (row: Row) => boolean | undefined,\n): Overlays {\n let overlays: Overlays = {\n add: undefined,\n remove: undefined,\n };\n switch (overlay?.change.type) {\n case 'add':\n overlays = {\n add: overlay.change.row,\n remove: undefined,\n };\n break;\n case 'remove':\n overlays = {\n add: undefined,\n remove: overlay.change.row,\n };\n break;\n case 'edit':\n overlays = {\n add: overlay.change.row,\n remove: overlay.change.oldRow,\n };\n break;\n }\n\n if (startAt) {\n overlays = overlaysForStartAt(overlays, startAt, compare);\n }\n\n if (constraint) {\n overlays = overlaysForConstraint(overlays, constraint);\n }\n\n if (filterPredicate) {\n overlays = overlaysForFilterPredicate(overlays, filterPredicate);\n }\n\n return overlays;\n}\n\nexport {overlaysForStartAt as overlaysForStartAtForTest};\n\nfunction overlaysForStartAt(\n {add, remove}: Overlays,\n startAt: Row,\n compare: Comparator,\n): Overlays {\n const undefinedIfBeforeStartAt = (row: Row | undefined) =>\n row === undefined || compare(row, startAt) < 0 ? undefined : row;\n return {\n add: undefinedIfBeforeStartAt(add),\n remove: undefinedIfBeforeStartAt(remove),\n };\n}\n\nexport {overlaysForConstraint as overlaysForConstraintForTest};\n\nfunction overlaysForConstraint(\n {add, remove}: Overlays,\n constraint: Constraint,\n): Overlays {\n const undefinedIfDoesntMatchConstraint = (row: Row | undefined) =>\n row === undefined || !constraintMatchesRow(constraint, row)\n ? undefined\n : row;\n\n return {\n add: undefinedIfDoesntMatchConstraint(add),\n remove: undefinedIfDoesntMatchConstraint(remove),\n };\n}\n\nfunction overlaysForFilterPredicate(\n {add, remove}: Overlays,\n filterPredicate: (row: Row) => boolean | undefined,\n): Overlays {\n const undefinedIfDoesntMatchFilter = (row: Row | undefined) =>\n row === undefined || !filterPredicate(row) ? undefined : row;\n\n return {\n add: undefinedIfDoesntMatchFilter(add),\n remove: undefinedIfDoesntMatchFilter(remove),\n };\n}\n\nexport function* generateWithOverlayInner(\n rowIterator: Iterable<Row>,\n overlays: Overlays,\n compare: (r1: Row, r2: Row) => number,\n) {\n let addOverlayYielded = false;\n let removeOverlaySkipped = false;\n for (const row of rowIterator) {\n if (!addOverlayYielded && overlays.add) {\n const cmp = compare(overlays.add, row);\n if (cmp < 0) {\n addOverlayYielded = true;\n yield {row: overlays.add, relationships: {}};\n }\n }\n\n if (!removeOverlaySkipped && overlays.remove) {\n const cmp = compare(overlays.remove, row);\n if (cmp === 0) {\n removeOverlaySkipped = true;\n continue;\n }\n }\n yield {row, relationships: {}};\n }\n\n if (!addOverlayYielded && overlays.add) {\n yield {row: overlays.add, relationships: {}};\n }\n}\n\n/**\n * A location to begin scanning an index from. Can either be a specific value\n * or the min or max possible value for the type. This is used to start a scan\n * at the beginning of the rows matching a constraint.\n */\ntype Bound = Value | MinValue | MaxValue;\ntype RowBound = Record<string, Bound>;\nconst minValue = Symbol('min-value');\ntype MinValue = typeof minValue;\nconst maxValue = Symbol('max-value');\ntype MaxValue = typeof maxValue;\n\nfunction makeBoundComparator(sort: Ordering) {\n return (a: RowBound, b: RowBound) => {\n // Hot! Do not use destructuring\n for (const entry of sort) {\n const key = entry[0];\n const cmp = compareBounds(a[key], b[key]);\n if (cmp !== 0) {\n return entry[1] === 'asc' ? cmp : -cmp;\n }\n }\n return 0;\n };\n}\n\nfunction compareBounds(a: Bound, b: Bound): number {\n if (a === b) {\n return 0;\n }\n if (a === minValue) {\n return -1;\n }\n if (b === minValue) {\n return 1;\n }\n if (a === maxValue) {\n return 1;\n }\n if (b === maxValue) {\n return -1;\n }\n return compareValues(a, b);\n}\n\nfunction* generateRows(\n data: BTreeSet<Row>,\n scanStart: RowBound | undefined,\n reverse: boolean | undefined,\n) {\n yield* data[reverse ? 'valuesFromReversed' : 'valuesFrom'](\n scanStart as Row | undefined,\n );\n}\n\nexport function stringify(change: SourceChange) {\n return JSON.stringify(change, (_, v) =>\n typeof v === 'bigint' ? v.toString() : v,\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -33,18 +33,6 @@ export interface Input extends InputBase {
|
|
|
33
33
|
* - During push: If a fetch to an input yields 'yield', it can be skipped/ignored.
|
|
34
34
|
*/
|
|
35
35
|
fetch(req: FetchRequest): Stream<Node | 'yield'>;
|
|
36
|
-
/**
|
|
37
|
-
* Cleanup maintained state. This is called when `output` will no longer need
|
|
38
|
-
* the data returned by {@linkcode fetch}. The receiving operator should clean up any
|
|
39
|
-
* resources it has allocated to service such requests.
|
|
40
|
-
*
|
|
41
|
-
* This is different from {@linkcode destroy} which means this input will no longer
|
|
42
|
-
* be called at all, for any input.
|
|
43
|
-
*
|
|
44
|
-
* Returns the same thing as {@linkcode fetch}. This allows callers to properly
|
|
45
|
-
* propagate the cleanup message through the graph.
|
|
46
|
-
*/
|
|
47
|
-
cleanup(req: FetchRequest): Stream<Node>;
|
|
48
36
|
}
|
|
49
37
|
export type FetchRequest = {
|
|
50
38
|
readonly constraint?: Constraint | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operator.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/operator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,6BAA6B,CAAC;AAC3D,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,oCAAoC,CAAC;AAC5D,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AAExC;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,iDAAiD;IACjD,SAAS,IAAI,YAAY,CAAC;IAE1B;;;;OAIG;IACH,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,KAAM,SAAQ,SAAS;IACtC,+CAA+C;IAC/C,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAEhC;;;;;;;;;;OAUG;IACH,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"operator.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/operator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,6BAA6B,CAAC;AAC3D,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,oCAAoC,CAAC;AAC5D,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AAExC;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,iDAAiD;IACjD,SAAS,IAAI,YAAY,CAAC;IAE1B;;;;OAIG;IACH,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,KAAM,SAAQ,SAAS;IACtC,+CAA+C;IAC/C,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAEhC;;;;;;;;;;OAUG;IACH,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;CAClD;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAC7C,kFAAkF;IAClF,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;IAEnC,oEAAoE;IACpE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAClB,QAAQ,CAAC,KAAK,EAAE,IAAI,GAAG,OAAO,CAAC;CAChC,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,MAAM;IACrB;;;;;;;OAOG;IACH,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;CAC/C;AAED;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,MAIzB,CAAC;AAEF,wBAAiB,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAMxE;AAED;;;;;GAKG;AACH,MAAM,WAAW,QAAS,SAAQ,KAAK,EAAE,MAAM;CAAG;AAElD;;;GAGG;AACH,MAAM,WAAW,OAAO;IACtB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IACzC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;IACzD;;OAEG;IACH,IAAI,CAAC,OAAO,CAAC,EAAE;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,GAAG,MAAM,CAAC,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IAC9D,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operator.js","sources":["../../../../../zql/src/ivm/operator.ts"],"sourcesContent":["import type {JSONValue} from '../../../shared/src/json.ts';\nimport type {Row} from '../../../zero-protocol/src/data.ts';\nimport type {Change} from './change.ts';\nimport type {Constraint} from './constraint.ts';\nimport type {Node} from './data.ts';\nimport type {SourceSchema} from './schema.ts';\nimport type {Stream} from './stream.ts';\n\n/**\n * Input to an operator.\n */\nexport interface InputBase {\n /** The schema of the data this input returns. */\n getSchema(): SourceSchema;\n\n /**\n * Completely destroy the input. Destroying an input\n * causes it to call destroy on its upstreams, fully\n * cleaning up a pipeline.\n */\n destroy(): void;\n}\n\nexport interface Input extends InputBase {\n /** Tell the input where to send its output. */\n setOutput(output: Output): void;\n\n /**\n * Fetch data. May modify the data in place.\n * Returns nodes sorted in order of `SourceSchema.compareRows`.\n *\n * The stream may contain 'yield' to indicate the operator has yielded control.\n *\n * Contract:\n * - During fetch: If an input yields 'yield', 'yield' must be yielded to the\n * caller of fetch immediately.\n * - During push: If a fetch to an input yields 'yield', it can be skipped/ignored.\n */\n fetch(req: FetchRequest): Stream<Node | 'yield'>;\n
|
|
1
|
+
{"version":3,"file":"operator.js","sources":["../../../../../zql/src/ivm/operator.ts"],"sourcesContent":["import type {JSONValue} from '../../../shared/src/json.ts';\nimport type {Row} from '../../../zero-protocol/src/data.ts';\nimport type {Change} from './change.ts';\nimport type {Constraint} from './constraint.ts';\nimport type {Node} from './data.ts';\nimport type {SourceSchema} from './schema.ts';\nimport type {Stream} from './stream.ts';\n\n/**\n * Input to an operator.\n */\nexport interface InputBase {\n /** The schema of the data this input returns. */\n getSchema(): SourceSchema;\n\n /**\n * Completely destroy the input. Destroying an input\n * causes it to call destroy on its upstreams, fully\n * cleaning up a pipeline.\n */\n destroy(): void;\n}\n\nexport interface Input extends InputBase {\n /** Tell the input where to send its output. */\n setOutput(output: Output): void;\n\n /**\n * Fetch data. May modify the data in place.\n * Returns nodes sorted in order of `SourceSchema.compareRows`.\n *\n * The stream may contain 'yield' to indicate the operator has yielded control.\n *\n * Contract:\n * - During fetch: If an input yields 'yield', 'yield' must be yielded to the\n * caller of fetch immediately.\n * - During push: If a fetch to an input yields 'yield', it can be skipped/ignored.\n */\n fetch(req: FetchRequest): Stream<Node | 'yield'>;\n}\n\nexport type FetchRequest = {\n readonly constraint?: Constraint | undefined;\n /** If supplied, `start.row` must have previously been output by fetch or push. */\n readonly start?: Start | undefined;\n\n /** Whether to fetch in reverse order of the SourceSchema's sort. */\n readonly reverse?: boolean | undefined;\n};\n\nexport type Start = {\n readonly row: Row;\n readonly basis: 'at' | 'after';\n};\n\n/**\n * An output for an operator. Typically another Operator but can also be\n * the code running the pipeline.\n */\nexport interface Output {\n /**\n * Push incremental changes to data previously received with fetch().\n * Consumers must apply all pushed changes or incremental result will\n * be incorrect.\n * Callers must maintain some invariants for correct operation:\n * - Only add rows which do not already exist (by deep equality).\n * - Only remove rows which do exist (by deep equality).\n */\n push(change: Change, pusher: InputBase): void;\n}\n\n/**\n * An implementation of Output that throws if pushed to. It is used as the\n * initial value for for an operator's output before it is set.\n */\nexport const throwOutput: Output = {\n push(_change: Change): void {\n throw new Error('Output not set');\n },\n};\n\nexport function* skipYields(stream: Stream<Node | 'yield'>): Stream<Node> {\n for (const node of stream) {\n if (node !== 'yield') {\n yield node;\n }\n }\n}\n\n/**\n * Operators are arranged into pipelines.\n * They are stateful.\n * Each operator is an input to the next operator in the chain and an output\n * to the previous.\n */\nexport interface Operator extends Input, Output {}\n\n/**\n * Operators get access to storage that they can store their internal\n * state in.\n */\nexport interface Storage {\n set(key: string, value: JSONValue): void;\n get(key: string, def?: JSONValue): JSONValue | undefined;\n /**\n * If options is not specified, defaults to scanning all entries.\n */\n scan(options?: {prefix: string}): Stream<[string, JSONValue]>;\n del(key: string): void;\n}\n"],"names":[],"mappings":"AA2EO,MAAM,cAAsB;AAAA,EACjC,KAAK,SAAuB;AAC1B,UAAM,IAAI,MAAM,gBAAgB;AAAA,EAClC;AACF;AAEO,UAAU,WAAW,QAA8C;AACxE,aAAW,QAAQ,QAAQ;AACzB,QAAI,SAAS,SAAS;AACpB,YAAM;AAAA,IACR;AAAA,EACF;AACF;"}
|
|
@@ -17,7 +17,6 @@ export declare class Skip implements Operator {
|
|
|
17
17
|
constructor(input: Input, bound: Bound);
|
|
18
18
|
getSchema(): SourceSchema;
|
|
19
19
|
fetch(req: FetchRequest): Stream<Node | 'yield'>;
|
|
20
|
-
cleanup(req: FetchRequest): Stream<Node>;
|
|
21
20
|
setOutput(output: Output): void;
|
|
22
21
|
destroy(): void;
|
|
23
22
|
push(change: Change): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skip.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/skip.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,oCAAoC,CAAC;AAC5D,OAAO,KAAK,EAAY,MAAM,EAA4B,MAAM,aAAa,CAAC;AAC9E,OAAO,KAAK,EAAa,IAAI,EAAC,MAAM,WAAW,CAAC;AAEhD,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,MAAM,EAEZ,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AAExC,MAAM,MAAM,KAAK,GAAG;IAClB,GAAG,EAAE,GAAG,CAAC;IACT,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF;;;GAGG;AACH,qBAAa,IAAK,YAAW,QAAQ;;gBAOvB,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK;IAOtC,SAAS,IAAI,YAAY;
|
|
1
|
+
{"version":3,"file":"skip.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/skip.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,oCAAoC,CAAC;AAC5D,OAAO,KAAK,EAAY,MAAM,EAA4B,MAAM,aAAa,CAAC;AAC9E,OAAO,KAAK,EAAa,IAAI,EAAC,MAAM,WAAW,CAAC;AAEhD,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,MAAM,EAEZ,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AAExC,MAAM,MAAM,KAAK,GAAG;IAClB,GAAG,EAAE,GAAG,CAAC;IACT,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF;;;GAGG;AACH,qBAAa,IAAK,YAAW,QAAQ;;gBAOvB,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK;IAOtC,SAAS,IAAI,YAAY;IAIxB,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC;IAsBjD,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/B,OAAO,IAAI,IAAI;IASf,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;CA0E3B"}
|
package/out/zql/src/ivm/skip.js
CHANGED
|
@@ -14,27 +14,19 @@ class Skip {
|
|
|
14
14
|
getSchema() {
|
|
15
15
|
return this.#input.getSchema();
|
|
16
16
|
}
|
|
17
|
-
fetch(req) {
|
|
18
|
-
return this.#fetchOrCleanup("fetch", req);
|
|
19
|
-
}
|
|
20
|
-
cleanup(req) {
|
|
21
|
-
return this.#fetchOrCleanup("cleanup", req);
|
|
22
|
-
}
|
|
23
|
-
*#fetchOrCleanup(method, req) {
|
|
17
|
+
*fetch(req) {
|
|
24
18
|
const start = this.#getStart(req);
|
|
25
19
|
if (start === "empty") {
|
|
26
20
|
return;
|
|
27
21
|
}
|
|
28
|
-
const nodes = this.#input
|
|
22
|
+
const nodes = this.#input.fetch({ ...req, start });
|
|
29
23
|
if (!req.reverse) {
|
|
30
24
|
yield* nodes;
|
|
31
25
|
return;
|
|
32
26
|
}
|
|
33
27
|
for (const node of nodes) {
|
|
34
28
|
if (node === "yield") {
|
|
35
|
-
|
|
36
|
-
yield node;
|
|
37
|
-
}
|
|
29
|
+
yield node;
|
|
38
30
|
continue;
|
|
39
31
|
}
|
|
40
32
|
if (!this.#shouldBePresent(node.row)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skip.js","sources":["../../../../../zql/src/ivm/skip.ts"],"sourcesContent":["import type {Row} from '../../../zero-protocol/src/data.ts';\nimport type {AddChange, Change, ChildChange, RemoveChange} from './change.ts';\nimport type {Comparator, Node} from './data.ts';\nimport {maybeSplitAndPushEditChange} from './maybe-split-and-push-edit-change.ts';\nimport {\n throwOutput,\n type FetchRequest,\n type Input,\n type Operator,\n type Output,\n type Start,\n} from './operator.ts';\nimport type {SourceSchema} from './schema.ts';\nimport type {Stream} from './stream.ts';\n\nexport type Bound = {\n row: Row;\n exclusive: boolean;\n};\n\n/**\n * Skip sets the start position for the pipeline. No rows before the bound will\n * be output.\n */\nexport class Skip implements Operator {\n readonly #input: Input;\n readonly #bound: Bound;\n readonly #comparator: Comparator;\n\n #output: Output = throwOutput;\n\n constructor(input: Input, bound: Bound) {\n this.#input = input;\n this.#bound = bound;\n this.#comparator = input.getSchema().compareRows;\n input.setOutput(this);\n }\n\n getSchema(): SourceSchema {\n return this.#input.getSchema();\n }\n\n fetch(req: FetchRequest): Stream<Node | 'yield'> {\n
|
|
1
|
+
{"version":3,"file":"skip.js","sources":["../../../../../zql/src/ivm/skip.ts"],"sourcesContent":["import type {Row} from '../../../zero-protocol/src/data.ts';\nimport type {AddChange, Change, ChildChange, RemoveChange} from './change.ts';\nimport type {Comparator, Node} from './data.ts';\nimport {maybeSplitAndPushEditChange} from './maybe-split-and-push-edit-change.ts';\nimport {\n throwOutput,\n type FetchRequest,\n type Input,\n type Operator,\n type Output,\n type Start,\n} from './operator.ts';\nimport type {SourceSchema} from './schema.ts';\nimport type {Stream} from './stream.ts';\n\nexport type Bound = {\n row: Row;\n exclusive: boolean;\n};\n\n/**\n * Skip sets the start position for the pipeline. No rows before the bound will\n * be output.\n */\nexport class Skip implements Operator {\n readonly #input: Input;\n readonly #bound: Bound;\n readonly #comparator: Comparator;\n\n #output: Output = throwOutput;\n\n constructor(input: Input, bound: Bound) {\n this.#input = input;\n this.#bound = bound;\n this.#comparator = input.getSchema().compareRows;\n input.setOutput(this);\n }\n\n getSchema(): SourceSchema {\n return this.#input.getSchema();\n }\n\n *fetch(req: FetchRequest): Stream<Node | 'yield'> {\n const start = this.#getStart(req);\n if (start === 'empty') {\n return;\n }\n const nodes = this.#input.fetch({...req, start});\n if (!req.reverse) {\n yield* nodes;\n return;\n }\n for (const node of nodes) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n if (!this.#shouldBePresent(node.row)) {\n return;\n }\n yield node;\n }\n }\n\n setOutput(output: Output): void {\n this.#output = output;\n }\n\n destroy(): void {\n this.#input.destroy();\n }\n\n #shouldBePresent(row: Row): boolean {\n const cmp = this.#comparator(this.#bound.row, row);\n return cmp < 0 || (cmp === 0 && !this.#bound.exclusive);\n }\n\n push(change: Change): void {\n const shouldBePresent = (row: Row) => this.#shouldBePresent(row);\n if (change.type === 'edit') {\n maybeSplitAndPushEditChange(change, shouldBePresent, this.#output, this);\n return;\n }\n\n change satisfies AddChange | RemoveChange | ChildChange;\n\n if (shouldBePresent(change.node.row)) {\n this.#output.push(change, this);\n }\n }\n\n #getStart(req: FetchRequest): Start | undefined | 'empty' {\n const boundStart = {\n row: this.#bound.row,\n basis: this.#bound.exclusive ? 'after' : 'at',\n } as const;\n\n if (!req.start) {\n if (req.reverse) {\n return undefined;\n }\n return boundStart;\n }\n\n const cmp = this.#comparator(this.#bound.row, req.start.row);\n\n if (!req.reverse) {\n // The skip bound is after the requested bound. The requested bound cannot\n // be relevant because even if it was basis: 'after', the skip bound is\n // itself after the requested bound. Return the skip bound.\n if (cmp > 0) {\n return boundStart;\n }\n\n // The skip bound and requested bound are equal. If either is exclusive,\n // return that bound with exclusive. Otherwise, return the skip bound.\n if (cmp === 0) {\n if (this.#bound.exclusive || req.start.basis === 'after') {\n return {\n row: this.#bound.row,\n basis: 'after',\n };\n }\n return boundStart;\n }\n\n return req.start;\n }\n\n req.reverse satisfies true;\n\n // bound is after the start, but request is for reverse so results\n // must be empty\n if (cmp > 0) {\n return 'empty';\n }\n\n if (cmp === 0) {\n // if both are inclusive, the result can be the single row at bound\n // return it as start\n if (!this.#bound.exclusive && req.start.basis === 'at') {\n return boundStart;\n }\n // otherwise the results must be empty, one or both are exclusive\n // in opposite directions\n return 'empty';\n }\n\n // bound is before the start, return start\n return req.start;\n }\n}\n"],"names":[],"mappings":";;AAwBO,MAAM,KAAyB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EAET,UAAkB;AAAA,EAElB,YAAY,OAAc,OAAc;AACtC,SAAK,SAAS;AACd,SAAK,SAAS;AACd,SAAK,cAAc,MAAM,UAAA,EAAY;AACrC,UAAM,UAAU,IAAI;AAAA,EACtB;AAAA,EAEA,YAA0B;AACxB,WAAO,KAAK,OAAO,UAAA;AAAA,EACrB;AAAA,EAEA,CAAC,MAAM,KAA2C;AAChD,UAAM,QAAQ,KAAK,UAAU,GAAG;AAChC,QAAI,UAAU,SAAS;AACrB;AAAA,IACF;AACA,UAAM,QAAQ,KAAK,OAAO,MAAM,EAAC,GAAG,KAAK,OAAM;AAC/C,QAAI,CAAC,IAAI,SAAS;AAChB,aAAO;AACP;AAAA,IACF;AACA,eAAW,QAAQ,OAAO;AACxB,UAAI,SAAS,SAAS;AACpB,cAAM;AACN;AAAA,MACF;AACA,UAAI,CAAC,KAAK,iBAAiB,KAAK,GAAG,GAAG;AACpC;AAAA,MACF;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,UAAU,QAAsB;AAC9B,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,UAAgB;AACd,SAAK,OAAO,QAAA;AAAA,EACd;AAAA,EAEA,iBAAiB,KAAmB;AAClC,UAAM,MAAM,KAAK,YAAY,KAAK,OAAO,KAAK,GAAG;AACjD,WAAO,MAAM,KAAM,QAAQ,KAAK,CAAC,KAAK,OAAO;AAAA,EAC/C;AAAA,EAEA,KAAK,QAAsB;AACzB,UAAM,kBAAkB,CAAC,QAAa,KAAK,iBAAiB,GAAG;AAC/D,QAAI,OAAO,SAAS,QAAQ;AAC1B,kCAA4B,QAAQ,iBAAiB,KAAK,SAAS,IAAI;AACvE;AAAA,IACF;AAIA,QAAI,gBAAgB,OAAO,KAAK,GAAG,GAAG;AACpC,WAAK,QAAQ,KAAK,QAAQ,IAAI;AAAA,IAChC;AAAA,EACF;AAAA,EAEA,UAAU,KAAgD;AACxD,UAAM,aAAa;AAAA,MACjB,KAAK,KAAK,OAAO;AAAA,MACjB,OAAO,KAAK,OAAO,YAAY,UAAU;AAAA,IAAA;AAG3C,QAAI,CAAC,IAAI,OAAO;AACd,UAAI,IAAI,SAAS;AACf,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAEA,UAAM,MAAM,KAAK,YAAY,KAAK,OAAO,KAAK,IAAI,MAAM,GAAG;AAE3D,QAAI,CAAC,IAAI,SAAS;AAIhB,UAAI,MAAM,GAAG;AACX,eAAO;AAAA,MACT;AAIA,UAAI,QAAQ,GAAG;AACb,YAAI,KAAK,OAAO,aAAa,IAAI,MAAM,UAAU,SAAS;AACxD,iBAAO;AAAA,YACL,KAAK,KAAK,OAAO;AAAA,YACjB,OAAO;AAAA,UAAA;AAAA,QAEX;AACA,eAAO;AAAA,MACT;AAEA,aAAO,IAAI;AAAA,IACb;AAEA,QAAI;AAIJ,QAAI,MAAM,GAAG;AACX,aAAO;AAAA,IACT;AAEA,QAAI,QAAQ,GAAG;AAGb,UAAI,CAAC,KAAK,OAAO,aAAa,IAAI,MAAM,UAAU,MAAM;AACtD,eAAO;AAAA,MACT;AAGA,aAAO;AAAA,IACT;AAGA,WAAO,IAAI;AAAA,EACb;AACF;"}
|
|
@@ -22,7 +22,6 @@ export declare class Take implements Operator {
|
|
|
22
22
|
setOutput(output: Output): void;
|
|
23
23
|
getSchema(): SourceSchema;
|
|
24
24
|
fetch(req: FetchRequest): Stream<Node | 'yield'>;
|
|
25
|
-
cleanup(req: FetchRequest): Stream<Node>;
|
|
26
25
|
push(change: Change): void;
|
|
27
26
|
destroy(): void;
|
|
28
27
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"take.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/take.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,2CAA2C,CAAC;AAE1E,OAAO,EAAC,KAAK,MAAM,EAAqC,MAAM,aAAa,CAAC;AAE5E,OAAO,EAAiC,KAAK,IAAI,EAAC,MAAM,WAAW,CAAC;AACpE,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,MAAM,EACX,KAAK,OAAO,EACb,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAc,KAAK,MAAM,EAAC,MAAM,aAAa,CAAC;AAiBrD,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC;AAEtC;;;;;;;;;;GAUG;AACH,qBAAa,IAAK,YAAW,QAAQ;;gBAYjC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,YAAY;IAgB7B,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/B,SAAS,IAAI,YAAY;IAIxB,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"take.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/take.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,2CAA2C,CAAC;AAE1E,OAAO,EAAC,KAAK,MAAM,EAAqC,MAAM,aAAa,CAAC;AAE5E,OAAO,EAAiC,KAAK,IAAI,EAAC,MAAM,WAAW,CAAC;AACpE,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,MAAM,EACX,KAAK,OAAO,EACb,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAc,KAAK,MAAM,EAAC,MAAM,aAAa,CAAC;AAiBrD,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC;AAEtC;;;;;;;;;;GAUG;AACH,qBAAa,IAAK,YAAW,QAAQ;;gBAYjC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,YAAY;IAgB7B,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/B,SAAS,IAAI,YAAY;IAIxB,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC;IAyJjD,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAsb1B,OAAO,IAAI,IAAI;CAGhB"}
|
package/out/zql/src/ivm/take.js
CHANGED
|
@@ -133,23 +133,6 @@ class Take {
|
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
|
-
*cleanup(req) {
|
|
137
|
-
assert(req.start === void 0, "Start should be undefined");
|
|
138
|
-
assert(
|
|
139
|
-
constraintMatchesPartitionKey(req.constraint, this.#partitionKey),
|
|
140
|
-
"Constraint should match partition key"
|
|
141
|
-
);
|
|
142
|
-
const takeStateKey = getTakeStateKey(this.#partitionKey, req.constraint);
|
|
143
|
-
this.#storage.del(takeStateKey);
|
|
144
|
-
let size = 0;
|
|
145
|
-
for (const inputNode of this.#input.cleanup(req)) {
|
|
146
|
-
if (size === this.#limit) {
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
size++;
|
|
150
|
-
yield inputNode;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
136
|
#getStateAndConstraint(row) {
|
|
154
137
|
const takeStateKey = getTakeStateKey(this.#partitionKey, row);
|
|
155
138
|
const takeState = this.#storage.get(takeStateKey);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"take.js","sources":["../../../../../zql/src/ivm/take.ts"],"sourcesContent":["import {assert, unreachable} from '../../../shared/src/asserts.ts';\nimport {hasOwn} from '../../../shared/src/has-own.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport type {Row, Value} from '../../../zero-protocol/src/data.ts';\nimport type {PrimaryKey} from '../../../zero-protocol/src/primary-key.ts';\nimport {assertOrderingIncludesPK} from '../query/complete-ordering.ts';\nimport {type Change, type EditChange, type RemoveChange} from './change.ts';\nimport type {Constraint} from './constraint.ts';\nimport {compareValues, type Comparator, type Node} from './data.ts';\nimport {\n skipYields,\n throwOutput,\n type FetchRequest,\n type Input,\n type Operator,\n type Output,\n type Storage,\n} from './operator.ts';\nimport type {SourceSchema} from './schema.ts';\nimport {first, take, type Stream} from './stream.ts';\n\nconst MAX_BOUND_KEY = 'maxBound';\n\ntype TakeState = {\n size: number;\n bound: Row | undefined;\n};\n\ninterface TakeStorage {\n get(key: typeof MAX_BOUND_KEY): Row | undefined;\n get(key: string): TakeState | undefined;\n set(key: typeof MAX_BOUND_KEY, value: Row): void;\n set(key: string, value: TakeState): void;\n del(key: string): void;\n}\n\nexport type PartitionKey = PrimaryKey;\n\n/**\n * The Take operator is for implementing limit queries. It takes the first n\n * nodes of its input as determined by the input’s comparator. It then keeps\n * a *bound* of the last item it has accepted so that it can evaluate whether\n * new incoming pushes should be accepted or rejected.\n *\n * Take can count rows globally or by unique value of some field.\n *\n * Maintains the invariant that its output size is always <= limit, even\n * mid processing of a push.\n */\nexport class Take implements Operator {\n readonly #input: Input;\n readonly #storage: TakeStorage;\n readonly #limit: number;\n readonly #partitionKey: PartitionKey | undefined;\n readonly #partitionKeyComparator: Comparator | undefined;\n // Fetch overlay needed for some split push cases.\n #rowHiddenFromFetch: Row | undefined;\n\n #output: Output = throwOutput;\n\n constructor(\n input: Input,\n storage: Storage,\n limit: number,\n partitionKey?: PartitionKey,\n ) {\n assert(limit >= 0, 'Limit must be non-negative');\n assertOrderingIncludesPK(\n input.getSchema().sort,\n input.getSchema().primaryKey,\n );\n input.setOutput(this);\n this.#input = input;\n this.#storage = storage as TakeStorage;\n this.#limit = limit;\n this.#partitionKey = partitionKey;\n this.#partitionKeyComparator =\n partitionKey && makePartitionKeyComparator(partitionKey);\n }\n\n setOutput(output: Output): void {\n this.#output = output;\n }\n\n getSchema(): SourceSchema {\n return this.#input.getSchema();\n }\n\n *fetch(req: FetchRequest): Stream<Node | 'yield'> {\n if (\n !this.#partitionKey ||\n (req.constraint &&\n constraintMatchesPartitionKey(req.constraint, this.#partitionKey))\n ) {\n const takeStateKey = getTakeStateKey(this.#partitionKey, req.constraint);\n const takeState = this.#storage.get(takeStateKey);\n if (!takeState) {\n yield* this.#initialFetch(req);\n return;\n }\n if (takeState.bound === undefined) {\n return;\n }\n for (const inputNode of this.#input.fetch(req)) {\n if (inputNode === 'yield') {\n yield inputNode;\n continue;\n }\n if (this.getSchema().compareRows(takeState.bound, inputNode.row) < 0) {\n return;\n }\n if (\n this.#rowHiddenFromFetch &&\n this.getSchema().compareRows(\n this.#rowHiddenFromFetch,\n inputNode.row,\n ) === 0\n ) {\n continue;\n }\n yield inputNode;\n }\n return;\n }\n // There is a partition key, but the fetch is not constrained or constrained\n // on a different key. Thus we don't have a single take state to bound by.\n // This currently only happens with nested sub-queries\n // e.g. issues include issuelabels include label. We could remove this\n // case if we added a translation layer (powered by some state) in join.\n // Specifically we need joinKeyValue => parent constraint key\n const maxBound = this.#storage.get(MAX_BOUND_KEY);\n if (maxBound === undefined) {\n return;\n }\n for (const inputNode of this.#input.fetch(req)) {\n if (inputNode === 'yield') {\n yield inputNode;\n continue;\n }\n if (this.getSchema().compareRows(inputNode.row, maxBound) > 0) {\n return;\n }\n const takeStateKey = getTakeStateKey(this.#partitionKey, inputNode.row);\n const takeState = this.#storage.get(takeStateKey);\n if (\n takeState?.bound !== undefined &&\n this.getSchema().compareRows(takeState.bound, inputNode.row) >= 0\n ) {\n yield inputNode;\n }\n }\n }\n\n *#initialFetch(req: FetchRequest): Stream<Node | 'yield'> {\n assert(req.start === undefined, 'Start should be undefined');\n assert(!req.reverse, 'Reverse should be false');\n assert(\n constraintMatchesPartitionKey(req.constraint, this.#partitionKey),\n 'Constraint should match partition key',\n );\n\n if (this.#limit === 0) {\n return;\n }\n\n const takeStateKey = getTakeStateKey(this.#partitionKey, req.constraint);\n assert(\n this.#storage.get(takeStateKey) === undefined,\n 'Take state should be undefined',\n );\n\n let size = 0;\n let bound: Row | undefined;\n let downstreamEarlyReturn = true;\n let exceptionThrown = false;\n try {\n for (const inputNode of this.#input.fetch(req)) {\n if (inputNode === 'yield') {\n yield 'yield';\n continue;\n }\n yield inputNode;\n bound = inputNode.row;\n size++;\n if (size === this.#limit) {\n break;\n }\n }\n downstreamEarlyReturn = false;\n } catch (e) {\n exceptionThrown = true;\n throw e;\n } finally {\n if (!exceptionThrown) {\n this.#setTakeState(\n takeStateKey,\n size,\n bound,\n this.#storage.get(MAX_BOUND_KEY),\n );\n // If it becomes necessary to support downstream early return, this\n // assert should be removed, and replaced with code that consumes\n // the input stream until limit is reached or the input stream is\n // exhausted so that takeState is properly hydrated.\n assert(\n !downstreamEarlyReturn,\n 'Unexpected early return prevented full hydration',\n );\n }\n }\n }\n\n *cleanup(req: FetchRequest): Stream<Node> {\n assert(req.start === undefined, 'Start should be undefined');\n assert(\n constraintMatchesPartitionKey(req.constraint, this.#partitionKey),\n 'Constraint should match partition key',\n );\n const takeStateKey = getTakeStateKey(this.#partitionKey, req.constraint);\n this.#storage.del(takeStateKey);\n let size = 0;\n for (const inputNode of this.#input.cleanup(req)) {\n if (size === this.#limit) {\n return;\n }\n size++;\n yield inputNode;\n }\n }\n\n #getStateAndConstraint(row: Row) {\n const takeStateKey = getTakeStateKey(this.#partitionKey, row);\n const takeState = this.#storage.get(takeStateKey);\n let maxBound: Row | undefined;\n let constraint: Constraint | undefined;\n if (takeState) {\n maxBound = this.#storage.get(MAX_BOUND_KEY);\n constraint =\n this.#partitionKey &&\n Object.fromEntries(\n this.#partitionKey.map(key => [key, row[key]] as const),\n );\n }\n\n return {takeState, takeStateKey, maxBound, constraint} as\n | {\n takeState: undefined;\n takeStateKey: string;\n maxBound: undefined;\n constraint: undefined;\n }\n | {\n takeState: TakeState;\n takeStateKey: string;\n maxBound: Row | undefined;\n constraint: Constraint | undefined;\n };\n }\n\n push(change: Change): void {\n if (change.type === 'edit') {\n this.#pushEditChange(change);\n return;\n }\n\n const {takeState, takeStateKey, maxBound, constraint} =\n this.#getStateAndConstraint(change.node.row);\n if (!takeState) {\n return;\n }\n\n const {compareRows} = this.getSchema();\n\n if (change.type === 'add') {\n if (takeState.size < this.#limit) {\n this.#setTakeState(\n takeStateKey,\n takeState.size + 1,\n takeState.bound === undefined ||\n compareRows(takeState.bound, change.node.row) < 0\n ? change.node.row\n : takeState.bound,\n maxBound,\n );\n this.#output.push(change, this);\n return;\n }\n // size === limit\n if (\n takeState.bound === undefined ||\n compareRows(change.node.row, takeState.bound) >= 0\n ) {\n return;\n }\n // added row < bound\n let beforeBoundNode: Node | undefined;\n let boundNode: Node;\n if (this.#limit === 1) {\n boundNode = must(\n first(\n skipYields(\n this.#input.fetch({\n start: {\n row: takeState.bound,\n basis: 'at',\n },\n constraint,\n }),\n ),\n ),\n );\n } else {\n [boundNode, beforeBoundNode] = take(\n skipYields(\n this.#input.fetch({\n start: {\n row: takeState.bound,\n basis: 'at',\n },\n constraint,\n reverse: true,\n }),\n ),\n 2,\n );\n }\n const removeChange: RemoveChange = {\n type: 'remove',\n node: boundNode,\n };\n // Remove before add to maintain invariant that\n // output size <= limit.\n this.#setTakeState(\n takeStateKey,\n takeState.size,\n beforeBoundNode === undefined ||\n compareRows(change.node.row, beforeBoundNode.row) > 0\n ? change.node.row\n : beforeBoundNode.row,\n maxBound,\n );\n this.#withRowHiddenFromFetch(change.node.row, () => {\n this.#output.push(removeChange, this);\n });\n this.#output.push(change, this);\n } else if (change.type === 'remove') {\n if (takeState.bound === undefined) {\n // change is after bound\n return;\n }\n const compToBound = compareRows(change.node.row, takeState.bound);\n if (compToBound > 0) {\n // change is after bound\n return;\n }\n const [beforeBoundNode] = take(\n skipYields(\n this.#input.fetch({\n start: {\n row: takeState.bound,\n basis: 'after',\n },\n constraint,\n reverse: true,\n }),\n ),\n 1,\n );\n\n let newBound: {node: Node; push: boolean} | undefined;\n if (beforeBoundNode) {\n const push = compareRows(beforeBoundNode.row, takeState.bound) > 0;\n newBound = {\n node: beforeBoundNode,\n push,\n };\n }\n if (!newBound?.push) {\n for (const node of skipYields(\n this.#input.fetch({\n start: {\n row: takeState.bound,\n basis: 'at',\n },\n constraint,\n }),\n )) {\n const push = compareRows(node.row, takeState.bound) > 0;\n newBound = {\n node,\n push,\n };\n if (push) {\n break;\n }\n }\n }\n\n if (newBound?.push) {\n this.#output.push(change, this);\n this.#setTakeState(\n takeStateKey,\n takeState.size,\n newBound.node.row,\n maxBound,\n );\n this.#output.push(\n {\n type: 'add',\n node: newBound.node,\n },\n this,\n );\n return;\n }\n this.#setTakeState(\n takeStateKey,\n takeState.size - 1,\n newBound?.node.row,\n maxBound,\n );\n this.#output.push(change, this);\n } else if (change.type === 'child') {\n // A 'child' change should be pushed to output if its row\n // is <= bound.\n if (\n takeState.bound &&\n compareRows(change.node.row, takeState.bound) <= 0\n ) {\n this.#output.push(change, this);\n }\n }\n }\n\n #pushEditChange(change: EditChange): void {\n assert(\n !this.#partitionKeyComparator ||\n this.#partitionKeyComparator(change.oldNode.row, change.node.row) === 0,\n 'Unexpected change of partition key',\n );\n\n const {takeState, takeStateKey, maxBound, constraint} =\n this.#getStateAndConstraint(change.oldNode.row);\n if (!takeState) {\n return;\n }\n\n assert(takeState.bound, 'Bound should be set');\n const {compareRows} = this.getSchema();\n const oldCmp = compareRows(change.oldNode.row, takeState.bound);\n const newCmp = compareRows(change.node.row, takeState.bound);\n\n const replaceBoundAndForwardChange = () => {\n this.#setTakeState(\n takeStateKey,\n takeState.size,\n change.node.row,\n maxBound,\n );\n this.#output.push(change, this);\n };\n\n // The bounds row was changed.\n if (oldCmp === 0) {\n // The new row is the new bound.\n if (newCmp === 0) {\n // no need to update the state since we are keeping the bounds\n this.#output.push(change, this);\n return;\n }\n\n if (newCmp < 0) {\n if (this.#limit === 1) {\n replaceBoundAndForwardChange();\n return;\n }\n\n // New row will be in the result but it might not be the bounds any\n // more. We need to find the row before the bounds to determine the new\n // bounds.\n\n const beforeBoundNode = must(\n first(\n skipYields(\n this.#input.fetch({\n start: {\n row: takeState.bound,\n basis: 'after',\n },\n constraint,\n reverse: true,\n }),\n ),\n ),\n );\n\n this.#setTakeState(\n takeStateKey,\n takeState.size,\n beforeBoundNode.row,\n maxBound,\n );\n this.#output.push(change, this);\n return;\n }\n\n assert(newCmp > 0, 'New comparison must be greater than 0');\n // Find the first item at the old bounds. This will be the new bounds.\n const newBoundNode = must(\n first(\n skipYields(\n this.#input.fetch({\n start: {\n row: takeState.bound,\n basis: 'at',\n },\n constraint,\n }),\n ),\n ),\n );\n\n // The next row is the new row. We can replace the bounds and keep the\n // edit change.\n if (compareRows(newBoundNode.row, change.node.row) === 0) {\n replaceBoundAndForwardChange();\n return;\n }\n\n // The new row is now outside the bounds, so we need to remove the old\n // row and add the new bounds row.\n this.#setTakeState(\n takeStateKey,\n takeState.size,\n newBoundNode.row,\n maxBound,\n );\n this.#withRowHiddenFromFetch(newBoundNode.row, () => {\n this.#output.push(\n {\n type: 'remove',\n node: change.oldNode,\n },\n this,\n );\n });\n this.#output.push(\n {\n type: 'add',\n node: newBoundNode,\n },\n this,\n );\n return;\n }\n\n if (oldCmp > 0) {\n assert(newCmp !== 0, 'Invalid state. Row has duplicate primary key');\n\n // Both old and new outside of bounds\n if (newCmp > 0) {\n return;\n }\n\n // old was outside, new is inside. Pushing out the old bounds\n assert(newCmp < 0, 'New comparison must be less than 0');\n\n const [oldBoundNode, newBoundNode] = take(\n skipYields(\n this.#input.fetch({\n start: {\n row: takeState.bound,\n basis: 'at',\n },\n constraint,\n reverse: true,\n }),\n ),\n 2,\n );\n // Remove before add to maintain invariant that\n // output size <= limit.\n this.#setTakeState(\n takeStateKey,\n takeState.size,\n newBoundNode.row,\n maxBound,\n );\n this.#withRowHiddenFromFetch(change.node.row, () => {\n this.#output.push(\n {\n type: 'remove',\n node: oldBoundNode,\n },\n this,\n );\n });\n this.#output.push(\n {\n type: 'add',\n node: change.node,\n },\n this,\n );\n\n return;\n }\n\n if (oldCmp < 0) {\n assert(newCmp !== 0, 'Invalid state. Row has duplicate primary key');\n\n // Both old and new inside of bounds\n if (newCmp < 0) {\n this.#output.push(change, this);\n return;\n }\n\n // old was inside, new is larger than old bound\n\n assert(newCmp > 0, 'New comparison must be greater than 0');\n\n // at this point we need to find the row after the bound and use that or\n // the newRow as the new bound.\n const afterBoundNode = must(\n first(\n skipYields(\n this.#input.fetch({\n start: {\n row: takeState.bound,\n basis: 'after',\n },\n constraint,\n }),\n ),\n ),\n );\n\n // The new row is the new bound. Use an edit change.\n if (compareRows(afterBoundNode.row, change.node.row) === 0) {\n replaceBoundAndForwardChange();\n return;\n }\n\n this.#output.push(\n {\n type: 'remove',\n node: change.oldNode,\n },\n this,\n );\n this.#setTakeState(\n takeStateKey,\n takeState.size,\n afterBoundNode.row,\n maxBound,\n );\n this.#output.push(\n {\n type: 'add',\n node: afterBoundNode,\n },\n this,\n );\n return;\n }\n\n unreachable();\n }\n\n #withRowHiddenFromFetch(row: Row, fn: () => void) {\n this.#rowHiddenFromFetch = row;\n try {\n fn();\n } finally {\n this.#rowHiddenFromFetch = undefined;\n }\n }\n\n #setTakeState(\n takeStateKey: string,\n size: number,\n bound: Row | undefined,\n maxBound: Row | undefined,\n ) {\n this.#storage.set(takeStateKey, {\n size,\n bound,\n });\n if (\n bound !== undefined &&\n (maxBound === undefined ||\n this.getSchema().compareRows(bound, maxBound) > 0)\n ) {\n this.#storage.set(MAX_BOUND_KEY, bound);\n }\n }\n\n destroy(): void {\n this.#input.destroy();\n }\n}\n\nfunction getTakeStateKey(\n partitionKey: PartitionKey | undefined,\n rowOrConstraint: Row | Constraint | undefined,\n): string {\n // The order must be consistent. We always use the order as defined by the\n // partition key.\n const partitionValues: Value[] = [];\n\n if (partitionKey && rowOrConstraint) {\n for (const key of partitionKey) {\n partitionValues.push(rowOrConstraint[key]);\n }\n }\n\n return JSON.stringify(['take', ...partitionValues]);\n}\n\nfunction constraintMatchesPartitionKey(\n constraint: Constraint | undefined,\n partitionKey: PartitionKey | undefined,\n): boolean {\n if (constraint === undefined || partitionKey === undefined) {\n return constraint === partitionKey;\n }\n if (partitionKey.length !== Object.keys(constraint).length) {\n return false;\n }\n for (const key of partitionKey) {\n if (!hasOwn(constraint, key)) {\n return false;\n }\n }\n return true;\n}\n\nfunction makePartitionKeyComparator(partitionKey: PartitionKey): Comparator {\n return (a, b) => {\n for (const key of partitionKey) {\n const cmp = compareValues(a[key], b[key]);\n if (cmp !== 0) {\n return cmp;\n }\n }\n return 0;\n };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"take.js","sources":["../../../../../zql/src/ivm/take.ts"],"sourcesContent":["import {assert, unreachable} from '../../../shared/src/asserts.ts';\nimport {hasOwn} from '../../../shared/src/has-own.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport type {Row, Value} from '../../../zero-protocol/src/data.ts';\nimport type {PrimaryKey} from '../../../zero-protocol/src/primary-key.ts';\nimport {assertOrderingIncludesPK} from '../query/complete-ordering.ts';\nimport {type Change, type EditChange, type RemoveChange} from './change.ts';\nimport type {Constraint} from './constraint.ts';\nimport {compareValues, type Comparator, type Node} from './data.ts';\nimport {\n skipYields,\n throwOutput,\n type FetchRequest,\n type Input,\n type Operator,\n type Output,\n type Storage,\n} from './operator.ts';\nimport type {SourceSchema} from './schema.ts';\nimport {first, take, type Stream} from './stream.ts';\n\nconst MAX_BOUND_KEY = 'maxBound';\n\ntype TakeState = {\n size: number;\n bound: Row | undefined;\n};\n\ninterface TakeStorage {\n get(key: typeof MAX_BOUND_KEY): Row | undefined;\n get(key: string): TakeState | undefined;\n set(key: typeof MAX_BOUND_KEY, value: Row): void;\n set(key: string, value: TakeState): void;\n del(key: string): void;\n}\n\nexport type PartitionKey = PrimaryKey;\n\n/**\n * The Take operator is for implementing limit queries. It takes the first n\n * nodes of its input as determined by the input’s comparator. It then keeps\n * a *bound* of the last item it has accepted so that it can evaluate whether\n * new incoming pushes should be accepted or rejected.\n *\n * Take can count rows globally or by unique value of some field.\n *\n * Maintains the invariant that its output size is always <= limit, even\n * mid processing of a push.\n */\nexport class Take implements Operator {\n readonly #input: Input;\n readonly #storage: TakeStorage;\n readonly #limit: number;\n readonly #partitionKey: PartitionKey | undefined;\n readonly #partitionKeyComparator: Comparator | undefined;\n // Fetch overlay needed for some split push cases.\n #rowHiddenFromFetch: Row | undefined;\n\n #output: Output = throwOutput;\n\n constructor(\n input: Input,\n storage: Storage,\n limit: number,\n partitionKey?: PartitionKey,\n ) {\n assert(limit >= 0, 'Limit must be non-negative');\n assertOrderingIncludesPK(\n input.getSchema().sort,\n input.getSchema().primaryKey,\n );\n input.setOutput(this);\n this.#input = input;\n this.#storage = storage as TakeStorage;\n this.#limit = limit;\n this.#partitionKey = partitionKey;\n this.#partitionKeyComparator =\n partitionKey && makePartitionKeyComparator(partitionKey);\n }\n\n setOutput(output: Output): void {\n this.#output = output;\n }\n\n getSchema(): SourceSchema {\n return this.#input.getSchema();\n }\n\n *fetch(req: FetchRequest): Stream<Node | 'yield'> {\n if (\n !this.#partitionKey ||\n (req.constraint &&\n constraintMatchesPartitionKey(req.constraint, this.#partitionKey))\n ) {\n const takeStateKey = getTakeStateKey(this.#partitionKey, req.constraint);\n const takeState = this.#storage.get(takeStateKey);\n if (!takeState) {\n yield* this.#initialFetch(req);\n return;\n }\n if (takeState.bound === undefined) {\n return;\n }\n for (const inputNode of this.#input.fetch(req)) {\n if (inputNode === 'yield') {\n yield inputNode;\n continue;\n }\n if (this.getSchema().compareRows(takeState.bound, inputNode.row) < 0) {\n return;\n }\n if (\n this.#rowHiddenFromFetch &&\n this.getSchema().compareRows(\n this.#rowHiddenFromFetch,\n inputNode.row,\n ) === 0\n ) {\n continue;\n }\n yield inputNode;\n }\n return;\n }\n // There is a partition key, but the fetch is not constrained or constrained\n // on a different key. Thus we don't have a single take state to bound by.\n // This currently only happens with nested sub-queries\n // e.g. issues include issuelabels include label. We could remove this\n // case if we added a translation layer (powered by some state) in join.\n // Specifically we need joinKeyValue => parent constraint key\n const maxBound = this.#storage.get(MAX_BOUND_KEY);\n if (maxBound === undefined) {\n return;\n }\n for (const inputNode of this.#input.fetch(req)) {\n if (inputNode === 'yield') {\n yield inputNode;\n continue;\n }\n if (this.getSchema().compareRows(inputNode.row, maxBound) > 0) {\n return;\n }\n const takeStateKey = getTakeStateKey(this.#partitionKey, inputNode.row);\n const takeState = this.#storage.get(takeStateKey);\n if (\n takeState?.bound !== undefined &&\n this.getSchema().compareRows(takeState.bound, inputNode.row) >= 0\n ) {\n yield inputNode;\n }\n }\n }\n\n *#initialFetch(req: FetchRequest): Stream<Node | 'yield'> {\n assert(req.start === undefined, 'Start should be undefined');\n assert(!req.reverse, 'Reverse should be false');\n assert(\n constraintMatchesPartitionKey(req.constraint, this.#partitionKey),\n 'Constraint should match partition key',\n );\n\n if (this.#limit === 0) {\n return;\n }\n\n const takeStateKey = getTakeStateKey(this.#partitionKey, req.constraint);\n assert(\n this.#storage.get(takeStateKey) === undefined,\n 'Take state should be undefined',\n );\n\n let size = 0;\n let bound: Row | undefined;\n let downstreamEarlyReturn = true;\n let exceptionThrown = false;\n try {\n for (const inputNode of this.#input.fetch(req)) {\n if (inputNode === 'yield') {\n yield 'yield';\n continue;\n }\n yield inputNode;\n bound = inputNode.row;\n size++;\n if (size === this.#limit) {\n break;\n }\n }\n downstreamEarlyReturn = false;\n } catch (e) {\n exceptionThrown = true;\n throw e;\n } finally {\n if (!exceptionThrown) {\n this.#setTakeState(\n takeStateKey,\n size,\n bound,\n this.#storage.get(MAX_BOUND_KEY),\n );\n // If it becomes necessary to support downstream early return, this\n // assert should be removed, and replaced with code that consumes\n // the input stream until limit is reached or the input stream is\n // exhausted so that takeState is properly hydrated.\n assert(\n !downstreamEarlyReturn,\n 'Unexpected early return prevented full hydration',\n );\n }\n }\n }\n\n #getStateAndConstraint(row: Row) {\n const takeStateKey = getTakeStateKey(this.#partitionKey, row);\n const takeState = this.#storage.get(takeStateKey);\n let maxBound: Row | undefined;\n let constraint: Constraint | undefined;\n if (takeState) {\n maxBound = this.#storage.get(MAX_BOUND_KEY);\n constraint =\n this.#partitionKey &&\n Object.fromEntries(\n this.#partitionKey.map(key => [key, row[key]] as const),\n );\n }\n\n return {takeState, takeStateKey, maxBound, constraint} as\n | {\n takeState: undefined;\n takeStateKey: string;\n maxBound: undefined;\n constraint: undefined;\n }\n | {\n takeState: TakeState;\n takeStateKey: string;\n maxBound: Row | undefined;\n constraint: Constraint | undefined;\n };\n }\n\n push(change: Change): void {\n if (change.type === 'edit') {\n this.#pushEditChange(change);\n return;\n }\n\n const {takeState, takeStateKey, maxBound, constraint} =\n this.#getStateAndConstraint(change.node.row);\n if (!takeState) {\n return;\n }\n\n const {compareRows} = this.getSchema();\n\n if (change.type === 'add') {\n if (takeState.size < this.#limit) {\n this.#setTakeState(\n takeStateKey,\n takeState.size + 1,\n takeState.bound === undefined ||\n compareRows(takeState.bound, change.node.row) < 0\n ? change.node.row\n : takeState.bound,\n maxBound,\n );\n this.#output.push(change, this);\n return;\n }\n // size === limit\n if (\n takeState.bound === undefined ||\n compareRows(change.node.row, takeState.bound) >= 0\n ) {\n return;\n }\n // added row < bound\n let beforeBoundNode: Node | undefined;\n let boundNode: Node;\n if (this.#limit === 1) {\n boundNode = must(\n first(\n skipYields(\n this.#input.fetch({\n start: {\n row: takeState.bound,\n basis: 'at',\n },\n constraint,\n }),\n ),\n ),\n );\n } else {\n [boundNode, beforeBoundNode] = take(\n skipYields(\n this.#input.fetch({\n start: {\n row: takeState.bound,\n basis: 'at',\n },\n constraint,\n reverse: true,\n }),\n ),\n 2,\n );\n }\n const removeChange: RemoveChange = {\n type: 'remove',\n node: boundNode,\n };\n // Remove before add to maintain invariant that\n // output size <= limit.\n this.#setTakeState(\n takeStateKey,\n takeState.size,\n beforeBoundNode === undefined ||\n compareRows(change.node.row, beforeBoundNode.row) > 0\n ? change.node.row\n : beforeBoundNode.row,\n maxBound,\n );\n this.#withRowHiddenFromFetch(change.node.row, () => {\n this.#output.push(removeChange, this);\n });\n this.#output.push(change, this);\n } else if (change.type === 'remove') {\n if (takeState.bound === undefined) {\n // change is after bound\n return;\n }\n const compToBound = compareRows(change.node.row, takeState.bound);\n if (compToBound > 0) {\n // change is after bound\n return;\n }\n const [beforeBoundNode] = take(\n skipYields(\n this.#input.fetch({\n start: {\n row: takeState.bound,\n basis: 'after',\n },\n constraint,\n reverse: true,\n }),\n ),\n 1,\n );\n\n let newBound: {node: Node; push: boolean} | undefined;\n if (beforeBoundNode) {\n const push = compareRows(beforeBoundNode.row, takeState.bound) > 0;\n newBound = {\n node: beforeBoundNode,\n push,\n };\n }\n if (!newBound?.push) {\n for (const node of skipYields(\n this.#input.fetch({\n start: {\n row: takeState.bound,\n basis: 'at',\n },\n constraint,\n }),\n )) {\n const push = compareRows(node.row, takeState.bound) > 0;\n newBound = {\n node,\n push,\n };\n if (push) {\n break;\n }\n }\n }\n\n if (newBound?.push) {\n this.#output.push(change, this);\n this.#setTakeState(\n takeStateKey,\n takeState.size,\n newBound.node.row,\n maxBound,\n );\n this.#output.push(\n {\n type: 'add',\n node: newBound.node,\n },\n this,\n );\n return;\n }\n this.#setTakeState(\n takeStateKey,\n takeState.size - 1,\n newBound?.node.row,\n maxBound,\n );\n this.#output.push(change, this);\n } else if (change.type === 'child') {\n // A 'child' change should be pushed to output if its row\n // is <= bound.\n if (\n takeState.bound &&\n compareRows(change.node.row, takeState.bound) <= 0\n ) {\n this.#output.push(change, this);\n }\n }\n }\n\n #pushEditChange(change: EditChange): void {\n assert(\n !this.#partitionKeyComparator ||\n this.#partitionKeyComparator(change.oldNode.row, change.node.row) === 0,\n 'Unexpected change of partition key',\n );\n\n const {takeState, takeStateKey, maxBound, constraint} =\n this.#getStateAndConstraint(change.oldNode.row);\n if (!takeState) {\n return;\n }\n\n assert(takeState.bound, 'Bound should be set');\n const {compareRows} = this.getSchema();\n const oldCmp = compareRows(change.oldNode.row, takeState.bound);\n const newCmp = compareRows(change.node.row, takeState.bound);\n\n const replaceBoundAndForwardChange = () => {\n this.#setTakeState(\n takeStateKey,\n takeState.size,\n change.node.row,\n maxBound,\n );\n this.#output.push(change, this);\n };\n\n // The bounds row was changed.\n if (oldCmp === 0) {\n // The new row is the new bound.\n if (newCmp === 0) {\n // no need to update the state since we are keeping the bounds\n this.#output.push(change, this);\n return;\n }\n\n if (newCmp < 0) {\n if (this.#limit === 1) {\n replaceBoundAndForwardChange();\n return;\n }\n\n // New row will be in the result but it might not be the bounds any\n // more. We need to find the row before the bounds to determine the new\n // bounds.\n\n const beforeBoundNode = must(\n first(\n skipYields(\n this.#input.fetch({\n start: {\n row: takeState.bound,\n basis: 'after',\n },\n constraint,\n reverse: true,\n }),\n ),\n ),\n );\n\n this.#setTakeState(\n takeStateKey,\n takeState.size,\n beforeBoundNode.row,\n maxBound,\n );\n this.#output.push(change, this);\n return;\n }\n\n assert(newCmp > 0, 'New comparison must be greater than 0');\n // Find the first item at the old bounds. This will be the new bounds.\n const newBoundNode = must(\n first(\n skipYields(\n this.#input.fetch({\n start: {\n row: takeState.bound,\n basis: 'at',\n },\n constraint,\n }),\n ),\n ),\n );\n\n // The next row is the new row. We can replace the bounds and keep the\n // edit change.\n if (compareRows(newBoundNode.row, change.node.row) === 0) {\n replaceBoundAndForwardChange();\n return;\n }\n\n // The new row is now outside the bounds, so we need to remove the old\n // row and add the new bounds row.\n this.#setTakeState(\n takeStateKey,\n takeState.size,\n newBoundNode.row,\n maxBound,\n );\n this.#withRowHiddenFromFetch(newBoundNode.row, () => {\n this.#output.push(\n {\n type: 'remove',\n node: change.oldNode,\n },\n this,\n );\n });\n this.#output.push(\n {\n type: 'add',\n node: newBoundNode,\n },\n this,\n );\n return;\n }\n\n if (oldCmp > 0) {\n assert(newCmp !== 0, 'Invalid state. Row has duplicate primary key');\n\n // Both old and new outside of bounds\n if (newCmp > 0) {\n return;\n }\n\n // old was outside, new is inside. Pushing out the old bounds\n assert(newCmp < 0, 'New comparison must be less than 0');\n\n const [oldBoundNode, newBoundNode] = take(\n skipYields(\n this.#input.fetch({\n start: {\n row: takeState.bound,\n basis: 'at',\n },\n constraint,\n reverse: true,\n }),\n ),\n 2,\n );\n // Remove before add to maintain invariant that\n // output size <= limit.\n this.#setTakeState(\n takeStateKey,\n takeState.size,\n newBoundNode.row,\n maxBound,\n );\n this.#withRowHiddenFromFetch(change.node.row, () => {\n this.#output.push(\n {\n type: 'remove',\n node: oldBoundNode,\n },\n this,\n );\n });\n this.#output.push(\n {\n type: 'add',\n node: change.node,\n },\n this,\n );\n\n return;\n }\n\n if (oldCmp < 0) {\n assert(newCmp !== 0, 'Invalid state. Row has duplicate primary key');\n\n // Both old and new inside of bounds\n if (newCmp < 0) {\n this.#output.push(change, this);\n return;\n }\n\n // old was inside, new is larger than old bound\n\n assert(newCmp > 0, 'New comparison must be greater than 0');\n\n // at this point we need to find the row after the bound and use that or\n // the newRow as the new bound.\n const afterBoundNode = must(\n first(\n skipYields(\n this.#input.fetch({\n start: {\n row: takeState.bound,\n basis: 'after',\n },\n constraint,\n }),\n ),\n ),\n );\n\n // The new row is the new bound. Use an edit change.\n if (compareRows(afterBoundNode.row, change.node.row) === 0) {\n replaceBoundAndForwardChange();\n return;\n }\n\n this.#output.push(\n {\n type: 'remove',\n node: change.oldNode,\n },\n this,\n );\n this.#setTakeState(\n takeStateKey,\n takeState.size,\n afterBoundNode.row,\n maxBound,\n );\n this.#output.push(\n {\n type: 'add',\n node: afterBoundNode,\n },\n this,\n );\n return;\n }\n\n unreachable();\n }\n\n #withRowHiddenFromFetch(row: Row, fn: () => void) {\n this.#rowHiddenFromFetch = row;\n try {\n fn();\n } finally {\n this.#rowHiddenFromFetch = undefined;\n }\n }\n\n #setTakeState(\n takeStateKey: string,\n size: number,\n bound: Row | undefined,\n maxBound: Row | undefined,\n ) {\n this.#storage.set(takeStateKey, {\n size,\n bound,\n });\n if (\n bound !== undefined &&\n (maxBound === undefined ||\n this.getSchema().compareRows(bound, maxBound) > 0)\n ) {\n this.#storage.set(MAX_BOUND_KEY, bound);\n }\n }\n\n destroy(): void {\n this.#input.destroy();\n }\n}\n\nfunction getTakeStateKey(\n partitionKey: PartitionKey | undefined,\n rowOrConstraint: Row | Constraint | undefined,\n): string {\n // The order must be consistent. We always use the order as defined by the\n // partition key.\n const partitionValues: Value[] = [];\n\n if (partitionKey && rowOrConstraint) {\n for (const key of partitionKey) {\n partitionValues.push(rowOrConstraint[key]);\n }\n }\n\n return JSON.stringify(['take', ...partitionValues]);\n}\n\nfunction constraintMatchesPartitionKey(\n constraint: Constraint | undefined,\n partitionKey: PartitionKey | undefined,\n): boolean {\n if (constraint === undefined || partitionKey === undefined) {\n return constraint === partitionKey;\n }\n if (partitionKey.length !== Object.keys(constraint).length) {\n return false;\n }\n for (const key of partitionKey) {\n if (!hasOwn(constraint, key)) {\n return false;\n }\n }\n return true;\n}\n\nfunction makePartitionKeyComparator(partitionKey: PartitionKey): Comparator {\n return (a, b) => {\n for (const key of partitionKey) {\n const cmp = compareValues(a[key], b[key]);\n if (cmp !== 0) {\n return cmp;\n }\n }\n return 0;\n };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -7,7 +7,6 @@ import type { UnionFanOut } from './union-fan-out.ts';
|
|
|
7
7
|
export declare class UnionFanIn implements Operator {
|
|
8
8
|
#private;
|
|
9
9
|
constructor(fanOut: UnionFanOut, inputs: Input[]);
|
|
10
|
-
cleanup(_req: FetchRequest): Stream<Node>;
|
|
11
10
|
destroy(): void;
|
|
12
11
|
fetch(req: FetchRequest): Stream<Node | 'yield'>;
|
|
13
12
|
getSchema(): SourceSchema;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"union-fan-in.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/union-fan-in.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AAExC,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AACpC,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,MAAM,EACZ,MAAM,eAAe,CAAC;AAMvB,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAQ,KAAK,MAAM,EAAC,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,oBAAoB,CAAC;AAEpD,qBAAa,UAAW,YAAW,QAAQ;;gBAO7B,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE;IAgEhD,OAAO,
|
|
1
|
+
{"version":3,"file":"union-fan-in.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/union-fan-in.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AAExC,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AACpC,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,MAAM,EACZ,MAAM,eAAe,CAAC;AAMvB,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAQ,KAAK,MAAM,EAAC,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,oBAAoB,CAAC;AAEpD,qBAAa,UAAW,YAAW,QAAQ;;gBAO7B,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE;IAgEhD,OAAO,IAAI,IAAI;IAMf,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC;IAOhD,SAAS,IAAI,YAAY;IAIzB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,IAAI;IAgE7C,oBAAoB;IAKpB,iBAAiB,CAAC,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC;IAuBlD,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;CAGhC;AAED,wBAAiB,YAAY,CAC3B,OAAO,EAAE,QAAQ,CAAC,IAAI,GAAG,OAAO,CAAC,EAAE,EACnC,UAAU,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,KAAK,MAAM,GACvC,gBAAgB,CAAC,IAAI,GAAG,OAAO,CAAC,CAuElC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"union-fan-in.js","sources":["../../../../../zql/src/ivm/union-fan-in.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport type {Writable} from '../../../shared/src/writable.ts';\nimport type {Change} from './change.ts';\nimport type {Constraint} from './constraint.ts';\nimport type {Node} from './data.ts';\nimport {\n throwOutput,\n type FetchRequest,\n type Input,\n type InputBase,\n type Operator,\n type Output,\n} from './operator.ts';\nimport {\n makeAddEmptyRelationships,\n mergeRelationships,\n pushAccumulatedChanges,\n} from './push-accumulated.ts';\nimport type {SourceSchema} from './schema.ts';\nimport {first, type Stream} from './stream.ts';\nimport type {UnionFanOut} from './union-fan-out.ts';\n\nexport class UnionFanIn implements Operator {\n readonly #inputs: readonly Input[];\n readonly #schema: SourceSchema;\n #fanOutPushStarted: boolean = false;\n #output: Output = throwOutput;\n #accumulatedPushes: Change[] = [];\n\n constructor(fanOut: UnionFanOut, inputs: Input[]) {\n this.#inputs = inputs;\n const fanOutSchema = fanOut.getSchema();\n fanOut.setFanIn(this);\n\n const schema: Writable<SourceSchema> = {\n tableName: fanOutSchema.tableName,\n columns: fanOutSchema.columns,\n primaryKey: fanOutSchema.primaryKey,\n relationships: {\n ...fanOutSchema.relationships,\n },\n isHidden: fanOutSchema.isHidden,\n system: fanOutSchema.system,\n compareRows: fanOutSchema.compareRows,\n sort: fanOutSchema.sort,\n };\n\n // now go through inputs and merge relationships\n const relationshipsFromBranches: Set<string> = new Set();\n for (const input of inputs) {\n const inputSchema = input.getSchema();\n assert(\n schema.tableName === inputSchema.tableName,\n `Table name mismatch in union fan-in: ${schema.tableName} !== ${inputSchema.tableName}`,\n );\n assert(\n schema.primaryKey === inputSchema.primaryKey,\n `Primary key mismatch in union fan-in`,\n );\n assert(\n schema.system === inputSchema.system,\n `System mismatch in union fan-in: ${schema.system} !== ${inputSchema.system}`,\n );\n assert(\n schema.compareRows === inputSchema.compareRows,\n `compareRows mismatch in union fan-in`,\n );\n assert(schema.sort === inputSchema.sort, `Sort mismatch in union fan-in`);\n\n for (const [relName, relSchema] of Object.entries(\n inputSchema.relationships,\n )) {\n if (relName in fanOutSchema.relationships) {\n continue;\n }\n\n // All branches will have unique relationship names except for relationships\n // that come in from `fanOut`.\n assert(\n !relationshipsFromBranches.has(relName),\n `Relationship ${relName} exists in multiple upstream inputs to union fan-in`,\n );\n schema.relationships[relName] = relSchema;\n relationshipsFromBranches.add(relName);\n }\n\n input.setOutput(this);\n }\n\n this.#schema = schema;\n this.#inputs = inputs;\n }\n\n cleanup(_req: FetchRequest): Stream<Node> {\n // Cleanup is going away. Not implemented.\n return [];\n }\n\n destroy(): void {\n for (const input of this.#inputs) {\n input.destroy();\n }\n }\n\n fetch(req: FetchRequest): Stream<Node | 'yield'> {\n const iterables = this.#inputs.map(input => input.fetch(req));\n return mergeFetches(iterables, (l, r) =>\n this.#schema.compareRows(l.row, r.row),\n );\n }\n\n getSchema(): SourceSchema {\n return this.#schema;\n }\n\n push(change: Change, pusher: InputBase): void {\n if (!this.#fanOutPushStarted) {\n this.#pushInternalChange(change, pusher);\n } else {\n this.#accumulatedPushes.push(change);\n }\n }\n\n /**\n * An internal change means that a change was received inside the fan-out/fan-in sub-graph.\n *\n * These changes always come from children of a flip-join as no other push generating operators\n * currently exist between union-fan-in and union-fan-out. All other pushes\n * enter into union-fan-out before reaching union-fan-in.\n *\n * - normal joins for `exists` come before `union-fan-out`\n * - joins for `related` come after `union-fan-out`\n * - take comes after `union-fan-out`\n *\n * The algorithm for deciding whether or not to forward a push that came from inside the ufo/ufi sub-graph:\n * 1. If the change is a `child` change we can forward it. This is because all child branches in the ufo/ufi sub-graph are unique.\n * 2. If the change is `add` we can forward it iff no `fetches` for the row return any results.\n * If another branch has it, the add was already emitted in the past.\n * 3. If the change is `remove` we can forward it iff no `fetches` for the row return any results.\n * If no other branches have the change, the remove can be sent as the value is no longer present.\n * If other branches have it, the last branch the processes the remove will send the remove.\n * 4. Edits will always come through as child changes as flip join will flip them into children.\n * An edit that would result in a remove or add will have been split into an add/remove pair rather than being an edit.\n */\n #pushInternalChange(change: Change, pusher: InputBase): void {\n if (change.type === 'child') {\n this.#output.push(change, this);\n return;\n }\n\n assert(change.type === 'add' || change.type === 'remove');\n\n let hadMatch = false;\n for (const input of this.#inputs) {\n if (input === pusher) {\n hadMatch = true;\n continue;\n }\n\n const constraint: Writable<Constraint> = {};\n for (const key of this.#schema.primaryKey) {\n constraint[key] = change.node.row[key];\n }\n const fetchResult = input.fetch({\n constraint,\n });\n\n if (first(fetchResult) !== undefined) {\n // Another branch has the row, so the add/remove is not needed.\n return;\n }\n }\n\n assert(hadMatch, 'Pusher was not one of the inputs to union-fan-in!');\n\n // No other branches have the row, so we can push the change.\n this.#output.push(change, this);\n }\n\n fanOutStartedPushing() {\n assert(this.#fanOutPushStarted === false);\n this.#fanOutPushStarted = true;\n }\n\n fanOutDonePushing(fanOutChangeType: Change['type']) {\n assert(this.#fanOutPushStarted);\n this.#fanOutPushStarted = false;\n if (this.#inputs.length === 0) {\n return;\n }\n\n if (this.#accumulatedPushes.length === 0) {\n // It is possible for no forks to pass along the push.\n // E.g., if no filters match in any fork.\n return;\n }\n\n pushAccumulatedChanges(\n this.#accumulatedPushes,\n this.#output,\n this,\n fanOutChangeType,\n mergeRelationships,\n makeAddEmptyRelationships(this.#schema),\n );\n }\n\n setOutput(output: Output): void {\n this.#output = output;\n }\n}\n\nexport function* mergeFetches(\n fetches: Iterable<Node | 'yield'>[],\n comparator: (l: Node, r: Node) => number,\n): IterableIterator<Node | 'yield'> {\n const iterators = fetches.map(i => i[Symbol.iterator]());\n let threw = false;\n try {\n const current: (Node | null)[] = [];\n let lastNodeYielded: Node | undefined;\n for (let i = 0; i < iterators.length; i++) {\n const iter = iterators[i];\n let result = iter.next();\n // yield yields when initializing\n while (!result.done && result.value === 'yield') {\n yield result.value;\n result = iter.next();\n }\n current[i] = result.done ? null : (result.value as Node);\n }\n while (current.some(c => c !== null)) {\n const min = current.reduce(\n (acc: [Node, number] | undefined, c, i): [Node, number] | undefined => {\n if (c === null) {\n return acc;\n }\n if (acc === undefined || comparator(c, acc[0]) < 0) {\n return [c, i];\n }\n return acc;\n },\n undefined,\n );\n\n assert(min !== undefined, 'min is undefined');\n const [minNode, minIndex] = min;\n const iter = iterators[minIndex];\n let result = iter.next();\n while (!result.done && result.value === 'yield') {\n yield result.value;\n result = iter.next();\n }\n current[minIndex] = result.done ? null : (result.value as Node);\n if (\n lastNodeYielded !== undefined &&\n comparator(lastNodeYielded, minNode) === 0\n ) {\n continue;\n }\n lastNodeYielded = minNode;\n yield minNode;\n }\n } catch (e) {\n threw = true;\n for (const iter of iterators) {\n try {\n iter.throw?.(e);\n } catch (_cleanupError) {\n // error in the iter.throw cleanup,\n // catch so other iterators are cleaned up\n }\n }\n throw e;\n } finally {\n if (!threw) {\n for (const iter of iterators) {\n try {\n iter.return?.();\n } catch (_cleanupError) {\n // error in the iter.return cleanup,\n // catch so other iterators are cleaned up\n }\n }\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"union-fan-in.js","sources":["../../../../../zql/src/ivm/union-fan-in.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport type {Writable} from '../../../shared/src/writable.ts';\nimport type {Change} from './change.ts';\nimport type {Constraint} from './constraint.ts';\nimport type {Node} from './data.ts';\nimport {\n throwOutput,\n type FetchRequest,\n type Input,\n type InputBase,\n type Operator,\n type Output,\n} from './operator.ts';\nimport {\n makeAddEmptyRelationships,\n mergeRelationships,\n pushAccumulatedChanges,\n} from './push-accumulated.ts';\nimport type {SourceSchema} from './schema.ts';\nimport {first, type Stream} from './stream.ts';\nimport type {UnionFanOut} from './union-fan-out.ts';\n\nexport class UnionFanIn implements Operator {\n readonly #inputs: readonly Input[];\n readonly #schema: SourceSchema;\n #fanOutPushStarted: boolean = false;\n #output: Output = throwOutput;\n #accumulatedPushes: Change[] = [];\n\n constructor(fanOut: UnionFanOut, inputs: Input[]) {\n this.#inputs = inputs;\n const fanOutSchema = fanOut.getSchema();\n fanOut.setFanIn(this);\n\n const schema: Writable<SourceSchema> = {\n tableName: fanOutSchema.tableName,\n columns: fanOutSchema.columns,\n primaryKey: fanOutSchema.primaryKey,\n relationships: {\n ...fanOutSchema.relationships,\n },\n isHidden: fanOutSchema.isHidden,\n system: fanOutSchema.system,\n compareRows: fanOutSchema.compareRows,\n sort: fanOutSchema.sort,\n };\n\n // now go through inputs and merge relationships\n const relationshipsFromBranches: Set<string> = new Set();\n for (const input of inputs) {\n const inputSchema = input.getSchema();\n assert(\n schema.tableName === inputSchema.tableName,\n `Table name mismatch in union fan-in: ${schema.tableName} !== ${inputSchema.tableName}`,\n );\n assert(\n schema.primaryKey === inputSchema.primaryKey,\n `Primary key mismatch in union fan-in`,\n );\n assert(\n schema.system === inputSchema.system,\n `System mismatch in union fan-in: ${schema.system} !== ${inputSchema.system}`,\n );\n assert(\n schema.compareRows === inputSchema.compareRows,\n `compareRows mismatch in union fan-in`,\n );\n assert(schema.sort === inputSchema.sort, `Sort mismatch in union fan-in`);\n\n for (const [relName, relSchema] of Object.entries(\n inputSchema.relationships,\n )) {\n if (relName in fanOutSchema.relationships) {\n continue;\n }\n\n // All branches will have unique relationship names except for relationships\n // that come in from `fanOut`.\n assert(\n !relationshipsFromBranches.has(relName),\n `Relationship ${relName} exists in multiple upstream inputs to union fan-in`,\n );\n schema.relationships[relName] = relSchema;\n relationshipsFromBranches.add(relName);\n }\n\n input.setOutput(this);\n }\n\n this.#schema = schema;\n this.#inputs = inputs;\n }\n\n destroy(): void {\n for (const input of this.#inputs) {\n input.destroy();\n }\n }\n\n fetch(req: FetchRequest): Stream<Node | 'yield'> {\n const iterables = this.#inputs.map(input => input.fetch(req));\n return mergeFetches(iterables, (l, r) =>\n this.#schema.compareRows(l.row, r.row),\n );\n }\n\n getSchema(): SourceSchema {\n return this.#schema;\n }\n\n push(change: Change, pusher: InputBase): void {\n if (!this.#fanOutPushStarted) {\n this.#pushInternalChange(change, pusher);\n } else {\n this.#accumulatedPushes.push(change);\n }\n }\n\n /**\n * An internal change means that a change was received inside the fan-out/fan-in sub-graph.\n *\n * These changes always come from children of a flip-join as no other push generating operators\n * currently exist between union-fan-in and union-fan-out. All other pushes\n * enter into union-fan-out before reaching union-fan-in.\n *\n * - normal joins for `exists` come before `union-fan-out`\n * - joins for `related` come after `union-fan-out`\n * - take comes after `union-fan-out`\n *\n * The algorithm for deciding whether or not to forward a push that came from inside the ufo/ufi sub-graph:\n * 1. If the change is a `child` change we can forward it. This is because all child branches in the ufo/ufi sub-graph are unique.\n * 2. If the change is `add` we can forward it iff no `fetches` for the row return any results.\n * If another branch has it, the add was already emitted in the past.\n * 3. If the change is `remove` we can forward it iff no `fetches` for the row return any results.\n * If no other branches have the change, the remove can be sent as the value is no longer present.\n * If other branches have it, the last branch the processes the remove will send the remove.\n * 4. Edits will always come through as child changes as flip join will flip them into children.\n * An edit that would result in a remove or add will have been split into an add/remove pair rather than being an edit.\n */\n #pushInternalChange(change: Change, pusher: InputBase): void {\n if (change.type === 'child') {\n this.#output.push(change, this);\n return;\n }\n\n assert(change.type === 'add' || change.type === 'remove');\n\n let hadMatch = false;\n for (const input of this.#inputs) {\n if (input === pusher) {\n hadMatch = true;\n continue;\n }\n\n const constraint: Writable<Constraint> = {};\n for (const key of this.#schema.primaryKey) {\n constraint[key] = change.node.row[key];\n }\n const fetchResult = input.fetch({\n constraint,\n });\n\n if (first(fetchResult) !== undefined) {\n // Another branch has the row, so the add/remove is not needed.\n return;\n }\n }\n\n assert(hadMatch, 'Pusher was not one of the inputs to union-fan-in!');\n\n // No other branches have the row, so we can push the change.\n this.#output.push(change, this);\n }\n\n fanOutStartedPushing() {\n assert(this.#fanOutPushStarted === false);\n this.#fanOutPushStarted = true;\n }\n\n fanOutDonePushing(fanOutChangeType: Change['type']) {\n assert(this.#fanOutPushStarted);\n this.#fanOutPushStarted = false;\n if (this.#inputs.length === 0) {\n return;\n }\n\n if (this.#accumulatedPushes.length === 0) {\n // It is possible for no forks to pass along the push.\n // E.g., if no filters match in any fork.\n return;\n }\n\n pushAccumulatedChanges(\n this.#accumulatedPushes,\n this.#output,\n this,\n fanOutChangeType,\n mergeRelationships,\n makeAddEmptyRelationships(this.#schema),\n );\n }\n\n setOutput(output: Output): void {\n this.#output = output;\n }\n}\n\nexport function* mergeFetches(\n fetches: Iterable<Node | 'yield'>[],\n comparator: (l: Node, r: Node) => number,\n): IterableIterator<Node | 'yield'> {\n const iterators = fetches.map(i => i[Symbol.iterator]());\n let threw = false;\n try {\n const current: (Node | null)[] = [];\n let lastNodeYielded: Node | undefined;\n for (let i = 0; i < iterators.length; i++) {\n const iter = iterators[i];\n let result = iter.next();\n // yield yields when initializing\n while (!result.done && result.value === 'yield') {\n yield result.value;\n result = iter.next();\n }\n current[i] = result.done ? null : (result.value as Node);\n }\n while (current.some(c => c !== null)) {\n const min = current.reduce(\n (acc: [Node, number] | undefined, c, i): [Node, number] | undefined => {\n if (c === null) {\n return acc;\n }\n if (acc === undefined || comparator(c, acc[0]) < 0) {\n return [c, i];\n }\n return acc;\n },\n undefined,\n );\n\n assert(min !== undefined, 'min is undefined');\n const [minNode, minIndex] = min;\n const iter = iterators[minIndex];\n let result = iter.next();\n while (!result.done && result.value === 'yield') {\n yield result.value;\n result = iter.next();\n }\n current[minIndex] = result.done ? null : (result.value as Node);\n if (\n lastNodeYielded !== undefined &&\n comparator(lastNodeYielded, minNode) === 0\n ) {\n continue;\n }\n lastNodeYielded = minNode;\n yield minNode;\n }\n } catch (e) {\n threw = true;\n for (const iter of iterators) {\n try {\n iter.throw?.(e);\n } catch (_cleanupError) {\n // error in the iter.throw cleanup,\n // catch so other iterators are cleaned up\n }\n }\n throw e;\n } finally {\n if (!threw) {\n for (const iter of iterators) {\n try {\n iter.return?.();\n } catch (_cleanupError) {\n // error in the iter.return cleanup,\n // catch so other iterators are cleaned up\n }\n }\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -12,7 +12,6 @@ export declare class UnionFanOut implements Operator {
|
|
|
12
12
|
setOutput(output: Output): void;
|
|
13
13
|
getSchema(): SourceSchema;
|
|
14
14
|
fetch(req: FetchRequest): Stream<Node | 'yield'>;
|
|
15
|
-
cleanup(_req: FetchRequest): Stream<Node>;
|
|
16
15
|
destroy(): void;
|
|
17
16
|
}
|
|
18
17
|
//# sourceMappingURL=union-fan-out.d.ts.map
|