From 916c112949f3ded52fecbac314b4417ca9cd80c9 Mon Sep 17 00:00:00 2001 From: Amp Date: Mon, 2 Nov 2026 04:46:40 +0000 Subject: [PATCH 1/3] zero-swift: sync aggregates, distinct and groupBy from zero-cache Named queries read the aggregate rows zero-cache sends under the a/ key prefix instead of dropping them. Relationship aggregates and grouped counts move optimistically with local mutations (crud-impl's deltas), and a mutator's tx.run reads synced rows for an answered query. Pending mutations are rebased once a synced aggregate's query first materializes after launch, since Swift replays them before any query registers. Client scenarios in packages/zero-conformance compute the server's rows with JS's pipeline (server-rows.ts), and a new E2E test runs the same queries against zero-cache. Co-authored-by: tmm Amp-Thread-ID: https://ampcode.com/threads/T-01a19a37-5aa9-7256-bff5-cdc47c01a1fe --- .changeset/swift-synced-aggregates.md | 5 + packages/zero-conformance/src/client/app.ts | 55 +++ .../zero-conformance/src/client/scenarios.ts | 2 + .../src/client/scenarios/aggregates.ts | 367 ++++++++++++++++++ .../src/client/server-rows.ts | 143 +++++++ packages/zero-conformance/src/e2e/app.ts | 21 + packages/zero-conformance/vectors/client.json | 13 + swift/Sources/Zero/Builder/Builder.swift | 210 +++++++++- swift/Sources/Zero/Client/Engine.swift | 23 +- swift/Sources/Zero/Client/IVMBranch.swift | 201 +++++++++- swift/Sources/Zero/Client/Keys.swift | 46 ++- swift/Sources/Zero/Client/PokeHandler.swift | 19 + swift/Sources/Zero/Client/QueryContext.swift | 37 +- swift/Sources/Zero/Client/Transaction.swift | 174 ++++++++- swift/Sources/Zero/IVM/Aggregate.swift | 2 + swift/Tests/ConformanceTests/ClientApp.swift | 36 ++ swift/Tests/E2ETests/AggregateE2ETests.swift | 98 +++++ 17 files changed, 1416 insertions(+), 36 deletions(-) create mode 100644 .changeset/swift-synced-aggregates.md create mode 100644 packages/zero-conformance/src/client/scenarios/aggregates.ts create mode 100644 packages/zero-conformance/src/client/server-rows.ts create mode 100644 swift/Tests/E2ETests/AggregateE2ETests.swift diff --git a/.changeset/swift-synced-aggregates.md b/.changeset/swift-synced-aggregates.md new file mode 100644 index 0000000000..d9bf653e45 --- /dev/null +++ b/.changeset/swift-synced-aggregates.md @@ -0,0 +1,5 @@ +--- +'zero-swift': patch +--- + +Aggregates, `distinct()` and `groupBy()` sync from zero-cache: a named query's view reads the rows the server computes, stored under `a/`, instead of dropping them from pokes. Until the server answers, a view computes nothing and shows the empty value (`0` for a count). A local mutation moves a synced relationship aggregate or grouped count at once, as the JS client's optimistic deltas do, and the server's rows replace them when it confirms. A mutator's `tx.run` reads the synced rows for a query the server has answered, and computes them otherwise. Pending mutations are rebased when a synced aggregate's query first materializes after launch, so a relaunched client keeps their moves. diff --git a/packages/zero-conformance/src/client/app.ts b/packages/zero-conformance/src/client/app.ts index 9b7bbb53e5..c12253cc22 100644 --- a/packages/zero-conformance/src/client/app.ts +++ b/packages/zero-conformance/src/client/app.ts @@ -9,6 +9,7 @@ import {defineMutators} from '../../../zql/src/mutate/mutator-registry.ts'; import {defineMutator} from '../../../zql/src/mutate/mutator.ts'; import {createBuilder} from '../../../zql/src/query/create-builder.ts'; import { + addContextToQuery, defineQueries, defineQuery, } from '../../../zql/src/query/query-registry.ts'; @@ -60,6 +61,29 @@ export const queries = defineQueries({ users: { all: defineQuery(() => zql.user.orderBy('id', 'asc')), }, + // Aggregates, distinct and groupBy, which the server computes. + aggregates: { + issueCount: defineQuery(() => zql.issue.count()), + openIssueCount: defineQuery(() => zql.issue.where('closed', false).count()), + commentCounts: defineQuery(() => + zql.issue.related('comments', q => q.count()).orderBy('id', 'asc'), + ), + commentTimes: defineQuery(() => + zql.issue + .related('comments', q => + q.where('authorId', '!=', 'u9').avg('createdAt'), + ) + .orderBy('id', 'asc'), + ), + labelCounts: defineQuery(() => + zql.issue.related('labels', q => q.count()).orderBy('id', 'asc'), + ), + owners: defineQuery(() => zql.issue.distinct('ownerId')), + commentsByIssue: defineQuery(() => zql.comment.groupBy('issueId').count()), + timeByAuthor: defineQuery(() => + zql.comment.groupBy('authorId').sum('createdAt'), + ), + }, // A table with a compound primary key. issueLabels: { all: defineQuery(() => @@ -177,9 +201,40 @@ const harden = { }), }; +/** + * Runs `ops` (CRUD operations, as `harden.ops` does), then each of the named + * `queries` through the transaction, and returns what they read: a query the + * server has answered reads its synced aggregates, any other computes them. + */ +const aggregates = { + read: defineMutator(async ({tx, args}: {tx: Tx; args: JSONObject}) => { + for (const o of (args['ops'] ?? []) as CRUDOp[]) { + await tx.mutate[o.table][o.op](o.value); + } + const out: ReadonlyJSONValue[] = []; + for (const {name, args: queryArgs} of (args['queries'] ?? []) as { + name: string; + args?: ReadonlyJSONValue; + }[]) { + let v: unknown = queries; + for (const part of name.split('.')) { + v = (v as Record)[part]; + } + const request = (v as (...a: unknown[]) => unknown)( + ...(queryArgs === undefined ? [] : [queryArgs]), + ); + // oxlint-disable-next-line @typescript-eslint/no-explicit-any + const result = await tx.run(addContextToQuery(request as any, undefined)); + out.push(JSON.parse(JSON.stringify(result ?? null))); + } + return out; + }), +}; + export const mutators = defineMutators({ issue, harden, + aggregates, comment: { add: defineMutator(async ({tx, args}: {tx: Tx; args: JSONObject}) => { await tx.mutate.comment.insert({ diff --git a/packages/zero-conformance/src/client/scenarios.ts b/packages/zero-conformance/src/client/scenarios.ts index 205329866e..eae8e6c526 100644 --- a/packages/zero-conformance/src/client/scenarios.ts +++ b/packages/zero-conformance/src/client/scenarios.ts @@ -1,4 +1,5 @@ import type {Scenario} from './harness.ts'; +import {aggregateScenarios} from './scenarios/aggregates.ts'; import {connectionScenarios} from './scenarios/connection.ts'; import {errorScenarios} from './scenarios/errors.ts'; import {mutationScenarios} from './scenarios/mutations.ts'; @@ -12,6 +13,7 @@ export const scenarios: Scenario[] = [ ...errorScenarios, ...pokeScenarios, ...queryScenarios, + ...aggregateScenarios, ...mutationScenarios, ...persistenceScenarios, ...visibilityScenarios, diff --git a/packages/zero-conformance/src/client/scenarios/aggregates.ts b/packages/zero-conformance/src/client/scenarios/aggregates.ts new file mode 100644 index 0000000000..1da233a0c4 --- /dev/null +++ b/packages/zero-conformance/src/client/scenarios/aggregates.ts @@ -0,0 +1,367 @@ +/** + * Synced aggregates, distinct and groupBy: the value before the server sends + * it, the rows it syncs (computed by JS's pipeline, see `server-rows.ts`), + * the optimistic moves of a local mutation and the rebase that confirms + * them, a restart, and the server dropping the query. + */ +import type {ReadonlyJSONValue} from '../../../../shared/src/json.ts'; +import type {Scenario, Step} from '../harness.ts'; +import {serverRowsPatch, type ServerData} from '../server-rows.ts'; +import { + advance, + comment, + connected, + gotDel, + issue, + mutate, + poke, + queryHash, + start, + syncPoke, +} from './helpers.ts'; + +const data: ServerData = { + issues: [ + issue('i1', {ownerId: 'u1', createdAt: 3}), + issue('i2', {createdAt: 4}), + issue('i3', {ownerId: 'u1', closed: true, createdAt: 5}), + ], + comments: [ + comment('c1', 'i1', {createdAt: 5}), + comment('c2', 'i1', {authorId: 'u2', createdAt: 7}), + comment('c3', 'i2', {createdAt: 2}), + comment('c4', 'i2', {authorId: 'u9', createdAt: 100}), + ], + issueLabel: [ + {issueId: 'i1', labelId: 'l1'}, + {issueId: 'i1', labelId: 'l2'}, + {issueId: 'i3', labelId: 'l1'}, + ], + label: [ + {id: 'l1', name: 'bug'}, + {id: 'l2', name: 'ui'}, + ], +}; + +/** `data` with `rows` added to `table`. */ +function plus(table: string, ...rows: ServerData[string]): ServerData { + return {...data, [table]: [...(data[table] ?? []), ...rows]}; +} + +/** `data` with `table`'s row `id` replaced by `row`, or removed. */ +function replacing( + table: string, + id: string, + row?: ServerData[string][number], +): ServerData { + return { + ...data, + [table]: (data[table] ?? []).flatMap(r => + r['id'] !== id ? [r] : row ? [row] : [], + ), + }; +} + +/** Materializes `query`, connects, and syncs its rows over `data`. */ +function synced(query: string, over: ServerData = data, view = 'v'): Step[] { + return [ + start, + {op: 'materialize', view, query}, + connected, + advance(10), + ...syncPoke( + 'p1', + null, + '01', + [queryHash(query)], + serverRowsPatch(query, undefined, undefined, over), + ), + ]; +} + +/** The server confirms mutation `lmid` and moves `query`'s rows. */ +function confirm( + query: string, + before: ServerData, + after: ServerData, + lmid: number, + pokeID = 'p2', + baseCookie = '01', + cookie = '02', +) { + return poke(pokeID, baseCookie, cookie, { + lastMutationIDChanges: {$clientID: lmid}, + rowsPatch: serverRowsPatch(query, undefined, before, after, cookie), + }); +} + +const addComment = ( + mutation: string, + id: string, + issueId: string, + fields: {authorId?: string; createdAt?: number} = {}, +) => mutate(mutation, 'comment.add', {id, issueId, ...fields}); + +const ops = ( + mutation: string, + o: {op: string; table: string; value: ReadonlyJSONValue}[], + queries: {name: string; args?: ReadonlyJSONValue}[] = [], +) => mutate(mutation, 'aggregates.read', {ops: o, queries}); + +export const aggregateScenarios: Scenario[] = [ + { + name: 'aggregate: a count is 0 until the server sends it, then its synced value', + steps: [ + start, + {op: 'materialize', view: 'v', query: 'aggregates.issueCount'}, + connected, + advance(10), + ...syncPoke( + 'p1', + null, + '01', + [queryHash('aggregates.issueCount')], + serverRowsPatch('aggregates.issueCount', undefined, undefined, data), + ), + advance(10), + ], + }, + { + name: 'aggregate: a top-level count waits for the server after a local mutation', + steps: [ + ...synced('aggregates.openIssueCount'), + mutate('m1', 'issue.close', 'i1'), + advance(10), + ...confirm( + 'aggregates.openIssueCount', + data, + replacing( + 'issues', + 'i1', + issue('i1', {ownerId: 'u1', closed: true, createdAt: 3}), + ), + 1, + ), + advance(10), + ], + }, + { + name: 'aggregate: a relationship count moves with a local mutation, and the server confirms it', + steps: [ + ...synced('aggregates.commentCounts'), + addComment('m1', 'c5', 'i3'), + addComment('m2', 'c6', 'i1'), + advance(10), + ...confirm( + 'aggregates.commentCounts', + data, + plus('comments', comment('c5', 'i3'), comment('c6', 'i1')), + 2, + ), + advance(10), + ], + }, + { + name: 'aggregate: the server confirms one mutation while another is still pending', + steps: [ + ...synced('aggregates.commentCounts'), + addComment('m1', 'c5', 'i3'), + addComment('m2', 'c6', 'i3'), + advance(10), + ...confirm( + 'aggregates.commentCounts', + data, + plus('comments', comment('c5', 'i3')), + 1, + ), + advance(10), + ], + }, + { + name: 'aggregate: a comment moved to another issue moves both counts; one deleted moves one', + steps: [ + ...synced('aggregates.commentCounts'), + ops('m1', [ + {op: 'update', table: 'comment', value: {id: 'c1', issueId: 'i2'}}, + ]), + ops('m2', [{op: 'delete', table: 'comment', value: {id: 'c3'}}]), + advance(10), + ], + }, + { + name: 'aggregate: an average moves only with the comments its where counts', + steps: [ + ...synced('aggregates.commentTimes'), + addComment('m1', 'c5', 'i1', {authorId: 'u9', createdAt: 1000}), + addComment('m2', 'c6', 'i1', {createdAt: 9}), + addComment('m3', 'c7', 'i3', {createdAt: 4}), + ops('m4', [ + {op: 'update', table: 'comment', value: {id: 'c4', authorId: 'u1'}}, + ]), + advance(10), + ...confirm( + 'aggregates.commentTimes', + data, + { + ...data, + comments: [ + ...data.comments.map(c => + c['id'] === 'c4' ? {...c, authorId: 'u1'} : c, + ), + comment('c5', 'i1', {authorId: 'u9', createdAt: 1000}), + comment('c6', 'i1', {createdAt: 9}), + comment('c7', 'i3', {createdAt: 4}), + ], + }, + 4, + ), + advance(10), + ], + }, + { + name: "aggregate: a junction count is the server's until it sends another", + steps: [ + ...synced('aggregates.labelCounts'), + ops('m1', [ + { + op: 'insert', + table: 'issueLabel', + value: {issueId: 'i2', labelId: 'l1'}, + }, + ]), + advance(10), + ...confirm( + 'aggregates.labelCounts', + data, + plus('issueLabel', {issueId: 'i2', labelId: 'l1'}), + 1, + ), + advance(10), + ], + }, + { + name: 'aggregate: a groupBy count adds a group with its first row and drops it with its last', + steps: [ + ...synced('aggregates.commentsByIssue'), + addComment('m1', 'c5', 'i3'), + ops('m2', [ + {op: 'delete', table: 'comment', value: {id: 'c3'}}, + {op: 'delete', table: 'comment', value: {id: 'c4'}}, + ]), + addComment('m3', 'c6', 'i1'), + advance(10), + ...confirm( + 'aggregates.commentsByIssue', + data, + { + ...data, + comments: [ + ...data.comments.filter(c => c['id'] !== 'c3' && c['id'] !== 'c4'), + comment('c5', 'i3'), + comment('c6', 'i1'), + ], + }, + 3, + ), + advance(10), + ], + }, + { + name: "aggregate: a groupBy sum moves and counts its group's rows", + steps: [ + ...synced('aggregates.timeByAuthor'), + addComment('m1', 'c5', 'i1', {authorId: 'u3', createdAt: 6}), + addComment('m2', 'c6', 'i1', {authorId: 'u2', createdAt: 1}), + ops('m3', [{op: 'delete', table: 'comment', value: {id: 'c2'}}]), + advance(10), + ], + }, + { + name: 'aggregate: a distinct adds a value with its first row', + steps: [ + ...synced('aggregates.owners'), + mutate('m1', 'issue.create', {id: 'i4', ownerId: 'u7'}), + mutate('m2', 'issue.create', {id: 'i5', ownerId: 'u1'}), + mutate('m3', 'issue.update', {id: 'i2', ownerId: 'u1'}), + advance(10), + ...confirm( + 'aggregates.owners', + data, + { + ...data, + issues: [ + issue('i1', {ownerId: 'u1', createdAt: 3}), + issue('i2', {ownerId: 'u1', createdAt: 4}), + issue('i3', {ownerId: 'u1', closed: true, createdAt: 5}), + issue('i4', {ownerId: 'u7'}), + issue('i5', {ownerId: 'u1'}), + ], + }, + 3, + ), + advance(10), + ], + }, + { + name: 'aggregate: synced aggregate rows and pending moves survive a restart', + steps: [ + ...synced('aggregates.commentCounts'), + addComment('m1', 'c5', 'i2'), + // Long enough for JS to persist. + advance(2000), + {op: 'restart'}, + {op: 'materialize', view: 'a', query: 'aggregates.commentCounts'}, + {op: 'materialize', view: 'b', query: 'aggregates.issueCount'}, + advance(10), + ], + }, + { + name: 'aggregate: once the server drops the query, a mutation no longer moves its rows', + steps: [ + ...synced('aggregates.commentCounts'), + {op: 'destroy', view: 'v'}, + advance(10), + ...poke('p2', '01', '02', { + gotQueriesPatch: [gotDel(queryHash('aggregates.commentCounts'))], + rowsPatch: serverRowsPatch( + 'aggregates.commentCounts', + undefined, + data, + {}, + ), + }), + addComment('m1', 'c5', 'i1'), + advance(10), + {op: 'materialize', view: 'w', query: 'aggregates.commentCounts'}, + advance(10), + ], + }, + { + name: 'aggregate: a mutator reads a synced aggregate with its own writes, and computes one the server has not sent', + steps: [ + ...synced('aggregates.commentCounts'), + ops( + 'm1', + [ + { + op: 'insert', + table: 'comment', + value: { + id: 'c5', + authorId: 'u1', + issueId: 'i1', + text: '', + createdAt: 1, + }, + }, + ], + [ + {name: 'aggregates.commentCounts'}, + {name: 'aggregates.issueCount'}, + {name: 'aggregates.commentsByIssue'}, + ], + ), + advance(10), + ], + }, +]; diff --git a/packages/zero-conformance/src/client/server-rows.ts b/packages/zero-conformance/src/client/server-rows.ts new file mode 100644 index 0000000000..75a42b896d --- /dev/null +++ b/packages/zero-conformance/src/client/server-rows.ts @@ -0,0 +1,143 @@ +/** + * The rows zero-cache syncs for a named query, computed by JS's own + * pipeline rather than written by hand: the query's AST in server names, + * built in compute mode over server-named tables with the query ID the + * client registers it under, and its output walked as the view-syncer's + * streamer walks it (`streamNodes` in zero-cache's `pipeline-driver.ts`). + * An aggregate's rows go to its synthetic table, stamped with a version. + */ +import type {ReadonlyJSONValue} from '../../../shared/src/json.ts'; +import {mapAST} from '../../../zero-protocol/src/ast.ts'; +import type {Row} from '../../../zero-protocol/src/data.ts'; +import {hashOfNameAndArgs} from '../../../zero-protocol/src/query-hash.ts'; +import {clientToServer} from '../../../zero-schema/src/name-mapper.ts'; +import {buildPipeline} from '../../../zql/src/builder/builder.ts'; +import {TestBuilderDelegate} from '../../../zql/src/builder/test-builder-delegate.ts'; +import type {Node} from '../../../zql/src/ivm/data.ts'; +import {MemorySource} from '../../../zql/src/ivm/memory-source.ts'; +import type {SourceSchema} from '../../../zql/src/ivm/schema.ts'; +import {makeSourceChangeAdd} from '../../../zql/src/ivm/source.ts'; +import {consume} from '../../../zql/src/ivm/stream.ts'; +import {asQueryInternals} from '../../../zql/src/query/query-internals.ts'; +import {addContextToQuery} from '../../../zql/src/query/query-registry.ts'; +import {queries, schema} from './app.ts'; + +type JSONObject = {readonly [key: string]: ReadonlyJSONValue}; + +/** Server-named rows by server table name. */ +export type ServerData = Record; + +type SyncedRow = {table: string; id: JSONObject; value: JSONObject}; + +function lookup(name: string) { + let v: unknown = queries; + for (const part of name.split('.')) { + v = (v as Record)[part]; + } + return v as (...args: unknown[]) => unknown; +} + +/** The rows the server syncs for `query(args)` over `data`, by table and key. */ +function syncedRows( + query: string, + args: ReadonlyJSONValue | undefined, + data: ServerData, + version: string, +): Map { + const argList = args === undefined ? [] : [args]; + const request = lookup(query)(...argList); + // oxlint-disable-next-line @typescript-eslint/no-explicit-any + const q = addContextToQuery(request as any, undefined); + const mapper = clientToServer(schema.tables); + const ast = mapAST(asQueryInternals(q).ast, mapper); + const sources: Record = {}; + for (const [name, table] of Object.entries(schema.tables)) { + const serverName = mapper.tableName(name); + const columns = Object.fromEntries( + Object.entries(table.columns).map(([c, v]) => [ + mapper.columnName(name, c), + v, + ]), + ); + const source = new MemorySource( + serverName, + columns, + table.primaryKey.map(c => mapper.columnName(name, c)) as [ + string, + ...string[], + ], + ); + for (const row of data[serverName] ?? []) { + consume(source.push(makeSourceChangeAdd(row as Row))); + } + sources[serverName] = source; + } + const input = buildPipeline( + ast, + new TestBuilderDelegate(sources), + hashOfNameAndArgs(query, argList), + ); + const rows = new Map(); + const walk = (schema: SourceSchema, nodes: Iterable) => { + if (schema.system === 'permissions') { + return; + } + for (const node of nodes) { + if (node === 'yield') { + continue; + } + const id = Object.fromEntries( + schema.primaryKey.map(c => [c, node.row[c] as ReadonlyJSONValue]), + ); + const value = ( + schema.isAggregate ? {...node.row, _0_version: version} : node.row + ) as JSONObject; + rows.set(JSON.stringify([schema.tableName, id]), { + table: schema.tableName, + id, + value, + }); + for (const [name, stream] of Object.entries(node.relationships)) { + walk(schema.relationships[name], stream()); + } + } + }; + walk(input.getSchema(), input.fetch({})); + input.destroy(); + return rows; +} + +/** + * The `rowsPatch` that takes the client from what the server synced for + * `query(args)` over `before` (nothing when undefined) to what it syncs + * over `after`: a put for each new or changed row, a del for each gone. + */ +export function serverRowsPatch( + query: string, + args: ReadonlyJSONValue | undefined, + before: ServerData | undefined, + after: ServerData, + version = '01', +): ReadonlyJSONValue[] { + const old = before + ? syncedRows(query, args, before, version) + : new Map(); + const next = syncedRows(query, args, after, version); + const patch: ReadonlyJSONValue[] = []; + for (const [key, row] of old) { + if (!next.has(key)) { + patch.push({op: 'del', tableName: row.table, id: row.id}); + } + } + for (const [key, row] of next) { + const prev = old.get(key); + const same = + prev !== undefined && + JSON.stringify({...prev.value, _0_version: null}) === + JSON.stringify({...row.value, _0_version: null}); + if (!same) { + patch.push({op: 'put', tableName: row.table, value: row.value}); + } + } + return patch; +} diff --git a/packages/zero-conformance/src/e2e/app.ts b/packages/zero-conformance/src/e2e/app.ts index 503fbb278f..0d35262c4a 100644 --- a/packages/zero-conformance/src/e2e/app.ts +++ b/packages/zero-conformance/src/e2e/app.ts @@ -30,6 +30,27 @@ export const queries = defineQueries({ zql.issue.where('id', args).related('comments').one(), ), }, + // Aggregates the server computes. The tests create issues but no + // comments, so the comment counts stay the fixture's; the `titled` ones + // see only the issues a test creates with its own title. + aggregates: { + commentCount: defineQuery(() => zql.comment.count()), + commentCounts: defineQuery(() => + zql.issue + .where('id', 'IN', ['i1', 'i2', 'i3', 'i4']) + .related('comments', q => q.count()) + .orderBy('id', 'asc'), + ), + commentsByAuthor: defineQuery(() => + zql.comment.groupBy('authorId').count(), + ), + titled: defineQuery(({args}: {args: string}) => + zql.issue.where('title', args).count(), + ), + titledOwners: defineQuery(({args}: {args: string}) => + zql.issue.where('title', args).groupBy('ownerId').count(), + ), + }, }); type CreateIssue = {id: string; title: string; ownerId?: string | undefined}; diff --git a/packages/zero-conformance/vectors/client.json b/packages/zero-conformance/vectors/client.json index 7f29082f3b..364f99a68c 100644 --- a/packages/zero-conformance/vectors/client.json +++ b/packages/zero-conformance/vectors/client.json @@ -107,6 +107,19 @@ {"name":"run and preload: cached accepts the previous connection, complete waits for this one","steps":[{"op":"materialize","view":"v","query":"issues.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"1y7zr0i1xir4ek"}],"rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":null,"createdAt":1}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"socketClose","code":1006},{"op":"run","run":"cached","query":"issues.all","type":"cached"},{"op":"run","run":"complete","query":"issues.all","type":"complete"},{"op":"preload","preload":"p","query":"issues.all"},{"op":"materialize","view":"w","query":"issues.all"},{"op":"materialize","view":"u","query":"users.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2"}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"complete","notifications":2}}},{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie","01"],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}],"activeClients":["$clientID"]}]}}],"closed":[0],"state":{"name":"connecting"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"complete","notifications":0}}},{"state":{"name":"connecting"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"complete","notifications":0}},"runs":{"cached":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}]}}},{"state":{"name":"connecting"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"complete","notifications":0}},"runs":{"cached":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}]},"complete":"pending"}},{"state":{"name":"connecting"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"complete","notifications":0}},"runs":{"cached":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}]},"complete":"pending"},"preloads":{"p":{"cached":"resolved","complete":"pending"}}},{"state":{"name":"connecting"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"complete","notifications":0},"w":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"cached","notifications":1}},"runs":{"cached":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}]},"complete":"pending"},"preloads":{"p":{"cached":"resolved","complete":"pending"}}},{"state":{"name":"connecting"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"complete","notifications":0},"w":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"cached","notifications":0},"u":{"data":[],"resultType":"unknown","notifications":1}},"runs":{"cached":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}]},"complete":"pending"},"preloads":{"p":{"cached":"resolved","complete":"pending"}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"complete","notifications":0},"w":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"cached","notifications":0},"u":{"data":[],"resultType":"unknown","notifications":0}},"runs":{"cached":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}]},"complete":"pending"},"preloads":{"p":{"cached":"resolved","complete":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"complete","notifications":0},"w":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"cached","notifications":0},"u":{"data":[],"resultType":"unknown","notifications":0}},"runs":{"cached":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}]},"complete":"pending"},"preloads":{"p":{"cached":"resolved","complete":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"complete","notifications":0},"w":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"cached","notifications":0},"u":{"data":[],"resultType":"unknown","notifications":0}},"runs":{"cached":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}]},"complete":"pending"},"preloads":{"p":{"cached":"resolved","complete":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"complete","notifications":0},"w":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"complete","notifications":1},"u":{"data":[],"resultType":"unknown","notifications":0}},"runs":{"cached":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}]},"complete":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1}]}},"preloads":{"p":{"cached":"resolved","complete":"resolved"}}}]}, {"name":"preload: registers with no TTL, resolves when the server has it, and cleans up","steps":[{"op":"advance","ms":0},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"preload","preload":"p","query":"issues.all"},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"1y7zr0i1xir4ek"}],"rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":null,"createdAt":1}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"cleanup","preload":"p"},{"op":"advance","ms":10},{"op":"preload","preload":"q","query":"users.all","ttl":"1m"},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connected"}},{"state":{"name":"connected"},"preloads":{"p":{"cached":"pending","complete":"pending"}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":0}]}]],"state":{"name":"connected"},"preloads":{"p":{"cached":"pending","complete":"pending"}}},{"state":{"name":"connected"},"preloads":{"p":{"cached":"pending","complete":"pending"}}},{"state":{"name":"connected"},"preloads":{"p":{"cached":"pending","complete":"pending"}}},{"state":{"name":"connected"},"preloads":{"p":{"cached":"resolved","complete":"resolved"}}},{"state":{"name":"connected"},"preloads":{"p":{"cached":"resolved","complete":"resolved"}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"del","hash":"1y7zr0i1xir4ek"}]}]],"state":{"name":"connected"},"preloads":{"p":{"cached":"resolved","complete":"resolved"}}},{"state":{"name":"connected"},"preloads":{"p":{"cached":"resolved","complete":"resolved"},"q":{"cached":"pending","complete":"pending"}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":60000}]}]],"state":{"name":"connected"},"preloads":{"p":{"cached":"resolved","complete":"resolved"},"q":{"cached":"pending","complete":"pending"}}}]}, {"name":"preload: a transformError rejects both promises","steps":[{"op":"advance","ms":0},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"preload","preload":"p","query":"issues.all"},{"op":"receive","message":["transformError",[{"error":"app","id":"1y7zr0i1xir4ek","name":"issues.all"}]]}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connected"}},{"state":{"name":"connected"},"preloads":{"p":{"cached":"pending","complete":"pending"}}},{"state":{"name":"connected"},"preloads":{"p":{"cached":{"rejected":{"error":"app","id":"1y7zr0i1xir4ek","name":"issues.all"}},"complete":{"rejected":{"error":"app","id":"1y7zr0i1xir4ek","name":"issues.all"}}}}}]}, +{"name":"aggregate: a count is 0 until the server sends it, then its synced value","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v","query":"aggregates.issueCount"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0oql89w09s2pr4"}],"rowsPatch":[{"op":"put","tableName":"aggregate:0oql89w09s2pr4","value":{"_0_key":0,"_0_value":3,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v":{"data":0,"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0oql89w09s2pr4","name":"aggregates.issueCount","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":0,"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0oql89w09s2pr4","name":"aggregates.issueCount","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":0,"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":0,"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":0,"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":3,"resultType":"complete","notifications":2}}},{"state":{"name":"connected"},"views":{"v":{"data":3,"resultType":"complete","notifications":0}}}]}, +{"name":"aggregate: a top-level count waits for the server after a local mutation","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v","query":"aggregates.openIssueCount"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"05ibvpy1q0cbcv"}],"rowsPatch":[{"op":"put","tableName":"aggregate:05ibvpy1q0cbcv","value":{"_0_key":0,"_0_value":2,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"issue.close","args":"i1"},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2","lastMutationIDChanges":{"$clientID":1},"rowsPatch":[{"op":"put","tableName":"aggregate:05ibvpy1q0cbcv","value":{"_0_key":0,"_0_value":1,"_0_version":"02"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v":{"data":0,"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"05ibvpy1q0cbcv","name":"aggregates.openIssueCount","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":0,"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"05ibvpy1q0cbcv","name":"aggregates.openIssueCount","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":0,"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":0,"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":0,"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":2,"resultType":"complete","notifications":2}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"issue.close","args":["i1"]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":2,"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":2,"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":2,"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":2,"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":1,"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":{"type":"success"}}}},{"state":{"name":"connected"},"views":{"v":{"data":1,"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":{"type":"success"}}}}]}, +{"name":"aggregate: a relationship count moves with a local mutation, and the server confirms it","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v","query":"aggregates.commentCounts"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr"}],"rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i1","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i2","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i3","_0_value":0,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"comment.add","args":{"id":"c5","issueId":"i3"}},{"op":"mutate","mutation":"m2","mutator":"comment.add","args":{"id":"c6","issueId":"i1"}},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2","lastMutationIDChanges":{"$clientID":2},"rowsPatch":[{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i1","_0_value":3,"_0_version":"02"}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i3","_0_value":1,"_0_version":"02"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":2}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"comment.add","args":[{"id":"c5","issueId":"i3"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":1}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":2,"clientID":"$clientID","name":"comment.add","args":[{"id":"c6","issueId":"i1"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":1}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":1}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":1}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":1}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":1}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":{"type":"success"}},"m2":{"client":{"type":"success"},"server":{"type":"success"}}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":1}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":{"type":"success"}},"m2":{"client":{"type":"success"},"server":{"type":"success"}}}}]}, +{"name":"aggregate: the server confirms one mutation while another is still pending","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v","query":"aggregates.commentCounts"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr"}],"rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i1","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i2","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i3","_0_value":0,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"comment.add","args":{"id":"c5","issueId":"i3"}},{"op":"mutate","mutation":"m2","mutator":"comment.add","args":{"id":"c6","issueId":"i3"}},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2","lastMutationIDChanges":{"$clientID":1},"rowsPatch":[{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i3","_0_value":1,"_0_version":"02"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":2}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"comment.add","args":[{"id":"c5","issueId":"i3"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":1}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":2,"clientID":"$clientID","name":"comment.add","args":[{"id":"c6","issueId":"i3"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":2}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":2}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":2}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":2}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":2}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":{"type":"success"}},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":2}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":{"type":"success"}},"m2":{"client":{"type":"success"},"server":"pending"}}}]}, +{"name":"aggregate: a comment moved to another issue moves both counts; one deleted moves one","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v","query":"aggregates.commentCounts"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr"}],"rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i1","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i2","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i3","_0_value":0,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"aggregates.read","args":{"ops":[{"op":"update","table":"comment","value":{"id":"c1","issueId":"i2"}}],"queries":[]}},{"op":"mutate","mutation":"m2","mutator":"aggregates.read","args":{"ops":[{"op":"delete","table":"comment","value":{"id":"c3"}}],"queries":[]}},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":2}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"update","table":"comment","value":{"id":"c1","issueId":"i2"}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":2,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"delete","table":"comment","value":{"id":"c3"}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"}}}]}, +{"name":"aggregate: an average moves only with the comments its where counts","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v","query":"aggregates.commentTimes"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0puwc8m0bnu56k"}],"rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:0puwc8m0bnu56k:comments","value":{"issue_id":"i1","_0_value":6,"_0_sum":12,"_0_count":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"aggregate:0puwc8m0bnu56k:comments","value":{"issue_id":"i2","_0_value":2,"_0_sum":2,"_0_count":1,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"aggregate:0puwc8m0bnu56k:comments","value":{"issue_id":"i3","_0_value":null,"_0_sum":0,"_0_count":0,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"comment.add","args":{"id":"c5","issueId":"i1","authorId":"u9","createdAt":1000}},{"op":"mutate","mutation":"m2","mutator":"comment.add","args":{"id":"c6","issueId":"i1","createdAt":9}},{"op":"mutate","mutation":"m3","mutator":"comment.add","args":{"id":"c7","issueId":"i3","createdAt":4}},{"op":"mutate","mutation":"m4","mutator":"aggregates.read","args":{"ops":[{"op":"update","table":"comment","value":{"id":"c4","authorId":"u1"}}],"queries":[]}},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2","lastMutationIDChanges":{"$clientID":4},"rowsPatch":[{"op":"put","tableName":"aggregate:0puwc8m0bnu56k:comments","value":{"issue_id":"i1","_0_value":7,"_0_sum":21,"_0_count":3,"_0_version":"02"}},{"op":"put","tableName":"aggregate:0puwc8m0bnu56k:comments","value":{"issue_id":"i2","_0_value":51,"_0_sum":102,"_0_count":2,"_0_version":"02"}},{"op":"put","tableName":"aggregate:0puwc8m0bnu56k:comments","value":{"issue_id":"i3","_0_value":4,"_0_sum":4,"_0_count":1,"_0_version":"02"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0puwc8m0bnu56k","name":"aggregates.commentTimes","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0puwc8m0bnu56k","name":"aggregates.commentTimes","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":6},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":null}],"resultType":"complete","notifications":2}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"comment.add","args":[{"id":"c5","issueId":"i1","authorId":"u9","createdAt":1000}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":6},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":null}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":2,"clientID":"$clientID","name":"comment.add","args":[{"id":"c6","issueId":"i1","createdAt":9}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":7},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":null}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":3,"clientID":"$clientID","name":"comment.add","args":[{"id":"c7","issueId":"i3","createdAt":4}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":7},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":4}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":4,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"update","table":"comment","value":{"id":"c4","authorId":"u1"}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":7},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":4}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"},"m4":{"client":{"type":"success","data":[]},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":7},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":4}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"},"m4":{"client":{"type":"success","data":[]},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":7},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":4}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"},"m4":{"client":{"type":"success","data":[]},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":7},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":4}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"},"m4":{"client":{"type":"success","data":[]},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":7},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":51},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":4}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":{"type":"success"}},"m2":{"client":{"type":"success"},"server":{"type":"success"}},"m3":{"client":{"type":"success"},"server":{"type":"success"}},"m4":{"client":{"type":"success","data":[]},"server":{"type":"success"}}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":7},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":51},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":4}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":{"type":"success"}},"m2":{"client":{"type":"success"},"server":{"type":"success"}},"m3":{"client":{"type":"success"},"server":{"type":"success"}},"m4":{"client":{"type":"success","data":[]},"server":{"type":"success"}}}}]}, +{"name":"aggregate: a junction count is the server's until it sends another","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v","query":"aggregates.labelCounts"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0hu6ael0se83ye"}],"rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:0hu6ael0se83ye:labels","value":{"issueId":"i1","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"aggregate:0hu6ael0se83ye:labels","value":{"issueId":"i2","_0_value":0,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"aggregate:0hu6ael0se83ye:labels","value":{"issueId":"i3","_0_value":1,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"aggregates.read","args":{"ops":[{"op":"insert","table":"issueLabel","value":{"issueId":"i2","labelId":"l1"}}],"queries":[]}},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2","lastMutationIDChanges":{"$clientID":1},"rowsPatch":[{"op":"put","tableName":"aggregate:0hu6ael0se83ye:labels","value":{"issueId":"i2","_0_value":1,"_0_version":"02"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0hu6ael0se83ye","name":"aggregates.labelCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0hu6ael0se83ye","name":"aggregates.labelCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"labels":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"labels":0},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"labels":1}],"resultType":"complete","notifications":2}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"insert","table":"issueLabel","value":{"issueId":"i2","labelId":"l1"}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"labels":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"labels":0},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"labels":1}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"labels":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"labels":0},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"labels":1}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"labels":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"labels":0},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"labels":1}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"labels":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"labels":0},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"labels":1}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"labels":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"labels":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"labels":1}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":{"type":"success"}}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"labels":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"labels":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"labels":1}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":{"type":"success"}}}}]}, +{"name":"aggregate: a groupBy count adds a group with its first row and drops it with its last","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v","query":"aggregates.commentsByIssue"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"1sx56i91c6nbxb"}],"rowsPatch":[{"op":"put","tableName":"aggregate:1sx56i91c6nbxb:#group","value":{"issue_id":"i1","_0_key":"si1","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"aggregate:1sx56i91c6nbxb:#group","value":{"issue_id":"i2","_0_key":"si2","_0_value":2,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"comment.add","args":{"id":"c5","issueId":"i3"}},{"op":"mutate","mutation":"m2","mutator":"aggregates.read","args":{"ops":[{"op":"delete","table":"comment","value":{"id":"c3"}},{"op":"delete","table":"comment","value":{"id":"c4"}}],"queries":[]}},{"op":"mutate","mutation":"m3","mutator":"comment.add","args":{"id":"c6","issueId":"i1"}},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2","lastMutationIDChanges":{"$clientID":3},"rowsPatch":[{"op":"del","tableName":"aggregate:1sx56i91c6nbxb:#group","id":{"_0_key":"si2"}},{"op":"put","tableName":"aggregate:1sx56i91c6nbxb:#group","value":{"issue_id":"i1","_0_key":"si1","_0_value":3,"_0_version":"02"}},{"op":"put","tableName":"aggregate:1sx56i91c6nbxb:#group","value":{"issue_id":"i3","_0_key":"si3","_0_value":1,"_0_version":"02"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1sx56i91c6nbxb","name":"aggregates.commentsByIssue","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1sx56i91c6nbxb","name":"aggregates.commentsByIssue","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"issueId":"i1","count":2},{"issueId":"i2","count":2}],"resultType":"complete","notifications":2}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"comment.add","args":[{"id":"c5","issueId":"i3"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"issueId":"i1","count":2},{"issueId":"i2","count":2},{"issueId":"i3","count":1}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":2,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"delete","table":"comment","value":{"id":"c3"}},{"op":"delete","table":"comment","value":{"id":"c4"}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"issueId":"i1","count":2},{"issueId":"i2","count":2},{"issueId":"i3","count":1}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":3,"clientID":"$clientID","name":"comment.add","args":[{"id":"c6","issueId":"i1"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"issueId":"i1","count":3},{"issueId":"i2","count":2},{"issueId":"i3","count":1}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"issueId":"i1","count":3},{"issueId":"i2","count":2},{"issueId":"i3","count":1}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"issueId":"i1","count":3},{"issueId":"i2","count":2},{"issueId":"i3","count":1}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"issueId":"i1","count":3},{"issueId":"i2","count":2},{"issueId":"i3","count":1}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"issueId":"i1","count":3},{"issueId":"i3","count":1}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":{"type":"success"}},"m2":{"client":{"type":"success","data":[]},"server":{"type":"success"}},"m3":{"client":{"type":"success"},"server":{"type":"success"}}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"issueId":"i1","count":3},{"issueId":"i3","count":1}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":{"type":"success"}},"m2":{"client":{"type":"success","data":[]},"server":{"type":"success"}},"m3":{"client":{"type":"success"},"server":{"type":"success"}}}}]}, +{"name":"aggregate: a groupBy sum moves and counts its group's rows","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v","query":"aggregates.timeByAuthor"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0t6mull0l7zix6"}],"rowsPatch":[{"op":"put","tableName":"aggregate:0t6mull0l7zix6:#group","value":{"authorId":"u1","_0_key":"su1","_0_value":7,"_0_sum":7,"_0_count":2,"_0_rows":2,"_0_version":"01"}},{"op":"put","tableName":"aggregate:0t6mull0l7zix6:#group","value":{"authorId":"u2","_0_key":"su2","_0_value":7,"_0_sum":7,"_0_count":1,"_0_rows":1,"_0_version":"01"}},{"op":"put","tableName":"aggregate:0t6mull0l7zix6:#group","value":{"authorId":"u9","_0_key":"su9","_0_value":100,"_0_sum":100,"_0_count":1,"_0_rows":1,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"comment.add","args":{"id":"c5","issueId":"i1","authorId":"u3","createdAt":6}},{"op":"mutate","mutation":"m2","mutator":"comment.add","args":{"id":"c6","issueId":"i1","authorId":"u2","createdAt":1}},{"op":"mutate","mutation":"m3","mutator":"aggregates.read","args":{"ops":[{"op":"delete","table":"comment","value":{"id":"c2"}}],"queries":[]}},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0t6mull0l7zix6","name":"aggregates.timeByAuthor","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0t6mull0l7zix6","name":"aggregates.timeByAuthor","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"authorId":"u1","sum":7},{"authorId":"u2","sum":7},{"authorId":"u9","sum":100}],"resultType":"complete","notifications":2}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"comment.add","args":[{"id":"c5","issueId":"i1","authorId":"u3","createdAt":6}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"authorId":"u1","sum":7},{"authorId":"u2","sum":7},{"authorId":"u3","sum":6},{"authorId":"u9","sum":100}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":2,"clientID":"$clientID","name":"comment.add","args":[{"id":"c6","issueId":"i1","authorId":"u2","createdAt":1}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"authorId":"u1","sum":7},{"authorId":"u2","sum":8},{"authorId":"u3","sum":6},{"authorId":"u9","sum":100}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":3,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"delete","table":"comment","value":{"id":"c2"}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"authorId":"u1","sum":7},{"authorId":"u2","sum":8},{"authorId":"u3","sum":6},{"authorId":"u9","sum":100}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success","data":[]},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"authorId":"u1","sum":7},{"authorId":"u2","sum":8},{"authorId":"u3","sum":6},{"authorId":"u9","sum":100}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success","data":[]},"server":"pending"}}}]}, +{"name":"aggregate: a distinct adds a value with its first row","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v","query":"aggregates.owners"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0xk81rx0bdt9gn"}],"rowsPatch":[{"op":"put","tableName":"aggregate:0xk81rx0bdt9gn:#group","value":{"owner_id":null,"_0_key":"null","_0_value":1,"_0_version":"01"}},{"op":"put","tableName":"aggregate:0xk81rx0bdt9gn:#group","value":{"owner_id":"u1","_0_key":"su1","_0_value":2,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"issue.create","args":{"id":"i4","ownerId":"u7"}},{"op":"mutate","mutation":"m2","mutator":"issue.create","args":{"id":"i5","ownerId":"u1"}},{"op":"mutate","mutation":"m3","mutator":"issue.update","args":{"id":"i2","ownerId":"u1"}},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2","lastMutationIDChanges":{"$clientID":3},"rowsPatch":[{"op":"del","tableName":"aggregate:0xk81rx0bdt9gn:#group","id":{"_0_key":"null"}},{"op":"put","tableName":"aggregate:0xk81rx0bdt9gn:#group","value":{"owner_id":"u1","_0_key":"su1","_0_value":4,"_0_version":"02"}},{"op":"put","tableName":"aggregate:0xk81rx0bdt9gn:#group","value":{"owner_id":"u7","_0_key":"su7","_0_value":1,"_0_version":"02"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0xk81rx0bdt9gn","name":"aggregates.owners","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0xk81rx0bdt9gn","name":"aggregates.owners","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"ownerId":null},{"ownerId":"u1"}],"resultType":"complete","notifications":2}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"issue.create","args":[{"id":"i4","ownerId":"u7"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"ownerId":null},{"ownerId":"u1"},{"ownerId":"u7"}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":2,"clientID":"$clientID","name":"issue.create","args":[{"id":"i5","ownerId":"u1"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"ownerId":null},{"ownerId":"u1"},{"ownerId":"u7"}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":3,"clientID":"$clientID","name":"issue.update","args":[{"id":"i2","ownerId":"u1"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"ownerId":null},{"ownerId":"u1"},{"ownerId":"u7"}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"ownerId":null},{"ownerId":"u1"},{"ownerId":"u7"}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"ownerId":null},{"ownerId":"u1"},{"ownerId":"u7"}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"ownerId":null},{"ownerId":"u1"},{"ownerId":"u7"}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"ownerId":"u1"},{"ownerId":"u7"}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":{"type":"success"}},"m2":{"client":{"type":"success"},"server":{"type":"success"}},"m3":{"client":{"type":"success"},"server":{"type":"success"}}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"ownerId":"u1"},{"ownerId":"u7"}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":{"type":"success"}},"m2":{"client":{"type":"success"},"server":{"type":"success"}},"m3":{"client":{"type":"success"},"server":{"type":"success"}}}}]}, +{"name":"aggregate: synced aggregate rows and pending moves survive a restart","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v","query":"aggregates.commentCounts"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr"}],"rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i1","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i2","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i3","_0_value":0,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"comment.add","args":{"id":"c5","issueId":"i2"}},{"op":"advance","ms":2000},{"op":"restart"},{"op":"materialize","view":"a","query":"aggregates.commentCounts"},{"op":"materialize","view":"b","query":"aggregates.issueCount"},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":2}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"comment.add","args":[{"id":"c5","issueId":"i2"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":3},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":3},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie","01"],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"activeClients":["$clientID"]}]}}],"closed":[0],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"a":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":3},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"cached","notifications":1}}},{"state":{"name":"connecting"},"views":{"a":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":3},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"cached","notifications":0},"b":{"data":0,"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"a":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":3},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"cached","notifications":0},"b":{"data":0,"resultType":"unknown","notifications":0}}}]}, +{"name":"aggregate: once the server drops the query, a mutation no longer moves its rows","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v","query":"aggregates.commentCounts"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr"}],"rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i1","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i2","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i3","_0_value":0,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"destroy","view":"v"},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2","gotQueriesPatch":[{"op":"del","hash":"0u3s9wi0kzvflr"}],"rowsPatch":[{"op":"del","tableName":"issues","id":{"id":"i1"}},{"op":"del","tableName":"aggregate:0u3s9wi0kzvflr:comments","id":{"issue_id":"i1"}},{"op":"del","tableName":"issues","id":{"id":"i2"}},{"op":"del","tableName":"aggregate:0u3s9wi0kzvflr:comments","id":{"issue_id":"i2"}},{"op":"del","tableName":"issues","id":{"id":"i3"}},{"op":"del","tableName":"aggregate:0u3s9wi0kzvflr:comments","id":{"issue_id":"i3"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]},{"op":"mutate","mutation":"m1","mutator":"comment.add","args":{"id":"c5","issueId":"i1"}},{"op":"advance","ms":10},{"op":"materialize","view":"w","query":"aggregates.commentCounts"},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":2}}},{"state":{"name":"connected"}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"del","hash":"0u3s9wi0kzvflr"}]}]],"state":{"name":"connected"}},{"state":{"name":"connected"}},{"state":{"name":"connected"}},{"state":{"name":"connected"}},{"sent":[["push",{"timestamp":1700000000020,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000020,"id":1,"clientID":"$clientID","name":"comment.add","args":[{"id":"c5","issueId":"i1"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"w":{"data":[],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"w":{"data":[],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}}]}, +{"name":"aggregate: a mutator reads a synced aggregate with its own writes, and computes one the server has not sent","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v","query":"aggregates.commentCounts"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr"}],"rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i1","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i2","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i3","_0_value":0,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"aggregates.read","args":{"ops":[{"op":"insert","table":"comment","value":{"id":"c5","authorId":"u1","issueId":"i1","text":"","createdAt":1}}],"queries":[{"name":"aggregates.commentCounts"},{"name":"aggregates.issueCount"},{"name":"aggregates.commentsByIssue"}]}},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":2}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"insert","table":"comment","value":{"id":"c5","authorId":"u1","issueId":"i1","text":"","createdAt":1}}],"queries":[{"name":"aggregates.commentCounts"},{"name":"aggregates.issueCount"},{"name":"aggregates.commentsByIssue"}]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":[[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],3,[{"issueId":"i1","count":1}]]},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":[[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],3,[{"issueId":"i1","count":1}]]},"server":"pending"}}}]}, {"name":"mutate: an optimistic write shows at once and is pushed once","steps":[{"op":"materialize","view":"v","query":"issues.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"mutate","mutation":"m1","mutator":"issue.create","args":{"id":"i1","title":"T","ownerId":"u1"}},{"op":"advance","ms":10},{"op":"mutate","mutation":"m2","mutator":"comment.add","args":{"id":"c1","issueId":"i1"}},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["push",{"timestamp":1700000000000,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000000,"id":1,"clientID":"$clientID","name":"issue.create","args":[{"id":"i1","title":"T","ownerId":"u1"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"T","description":"","closed":false,"ownerId":"u1","createdAt":1}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"T","description":"","closed":false,"ownerId":"u1","createdAt":1}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":2,"clientID":"$clientID","name":"comment.add","args":[{"id":"c1","issueId":"i1"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"T","description":"","closed":false,"ownerId":"u1","createdAt":1}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"T","description":"","closed":false,"ownerId":"u1","createdAt":1}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}}]}, {"name":"mutate: mutations made while connecting are pushed once connected","steps":[{"op":"materialize","view":"v","query":"issues.all"},{"op":"mutate","mutation":"m1","mutator":"issue.create","args":{"id":"i1"}},{"op":"mutate","mutation":"m2","mutator":"issue.create","args":{"id":"i2"}},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v":{"data":[{"id":"i1","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connecting"},"views":{"v":{"data":[{"id":"i1","title":"","description":"","closed":false,"ownerId":null,"createdAt":1},{"id":"i2","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000000,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000000,"id":1,"clientID":"$clientID","name":"issue.create","args":[{"id":"i1"}]}],"pushVersion":1,"requestID":"$requestID"}],["push",{"timestamp":1700000000000,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000000,"id":2,"clientID":"$clientID","name":"issue.create","args":[{"id":"i2"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"","description":"","closed":false,"ownerId":null,"createdAt":1},{"id":"i2","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"","description":"","closed":false,"ownerId":null,"createdAt":1},{"id":"i2","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}}]}, {"name":"mutate: a reconnect pushes pending mutations again and sends lmid","steps":[{"op":"materialize","view":"v","query":"issues.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"mutate","mutation":"m1","mutator":"issue.create","args":{"id":"i1"}},{"op":"mutate","mutation":"m2","mutator":"issue.create","args":{"id":"i2"}},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","lastMutationIDChanges":{"$clientID":1},"gotQueriesPatch":[{"op":"put","hash":"1y7zr0i1xir4ek"}],"rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":null,"createdAt":1}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"socketClose","code":1006},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["push",{"timestamp":1700000000000,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000000,"id":1,"clientID":"$clientID","name":"issue.create","args":[{"id":"i1"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000000,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000000,"id":2,"clientID":"$clientID","name":"issue.create","args":[{"id":"i2"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"","description":"","closed":false,"ownerId":null,"createdAt":1},{"id":"i2","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"","description":"","closed":false,"ownerId":null,"createdAt":1},{"id":"i2","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"","description":"","closed":false,"ownerId":null,"createdAt":1},{"id":"i2","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1},{"id":"i2","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"complete","notifications":2}},"mutations":{"m1":{"client":{"type":"success"},"server":{"type":"success"}},"m2":{"client":{"type":"success"},"server":"pending"}}},{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie","01"],["lmid","1"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}],"activeClients":["$clientID"]}]}}],"closed":[0],"state":{"name":"connecting"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1},{"id":"i2","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":{"type":"success"}},"m2":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000000,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000000,"id":2,"clientID":"$clientID","name":"issue.create","args":[{"id":"i2"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1},{"id":"i2","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":{"type":"success"}},"m2":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1},{"id":"i2","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":{"type":"success"}},"m2":{"client":{"type":"success"},"server":"pending"}}}]}, diff --git a/swift/Sources/Zero/Builder/Builder.swift b/swift/Sources/Zero/Builder/Builder.swift index 7efc3f10c5..21cc477f36 100644 --- a/swift/Sources/Zero/Builder/Builder.swift +++ b/swift/Sources/Zero/Builder/Builder.swift @@ -9,7 +9,21 @@ package protocol BuilderDelegate: AnyObject { /// Do not copy a parent's conditions on correlation columns into its /// subqueries. var disableCorrelatedPredicatePushdown: Bool { get } + /// The synced client's mode: an aggregate or a grouping is read from the + /// synthetic source the server streams its rows to, rather than computed + /// from rows the client doesn't have. + var aggregatesFromSource: Bool { get } func getSource(_ tableName: String) -> (any Source)? + /// The source of a relationship aggregate's or a grouped query's rows, + /// which the name doesn't describe, made with this shape if it's new. + /// `optimistic` lets the client move it when it writes a child row. + func getAggregateSource( + _ name: String, columns: [(String, ColumnSchema)], primaryKey: [String], + optimistic: OptimisticAggregate? + ) -> (any Source)? + /// The names a synced aggregate row has `table`'s `columns` under: the + /// server's, which it computed them with. + func aggregateKeyColumns(_ table: String, _ columns: [String]) -> [String] func decorateInput(_ input: any Input, name: String) -> any Input func addEdge(_ source: any InputBase, _ dest: any InputBase) func decorateFilterInput(_ input: any FilterInput, name: String) -> any FilterInput @@ -21,6 +35,12 @@ extension BuilderDelegate { package var applyFiltersAnyway: Bool { false } package var enableNotExists: Bool { false } package var disableCorrelatedPredicatePushdown: Bool { false } + package var aggregatesFromSource: Bool { false } + func getAggregateSource( + _ name: String, columns: [(String, ColumnSchema)], primaryKey: [String], + optimistic: OptimisticAggregate? + ) -> (any Source)? { getSource(name) } + package func aggregateKeyColumns(_ table: String, _ columns: [String]) -> [String] { columns } package func decorateInput(_ input: any Input, name: String) -> any Input { input } package func addEdge(_ source: any InputBase, _ dest: any InputBase) {} package func decorateFilterInput(_ input: any FilterInput, name: String) -> any FilterInput { @@ -45,6 +65,11 @@ package func buildPipeline( if ast.groupBy != nil && ast.aggregate?.distinct != nil { throw PipelineError("a count of distinct values per group is not supported yet") } + // A synced client reads a top-level aggregate's or a grouping's rows from + // their source: the table isn't synced, and ordering doesn't apply. + if (ast.aggregate != nil || ast.groupBy != nil) && delegate.aggregatesFromSource { + return try buildPipelineInternal(ast, delegate, queryID, "") + } if ast.groupBy != nil || ast.aggregate?.distinct != nil { // A grouping's input is sorted by its columns first, so the rows of a // group are adjacent (see GroupBy). @@ -145,6 +170,20 @@ func buildPipelineInternal( if astIn.groupBy != nil && !name.isEmpty { throw PipelineError("groupBy is only supported at the top level") } + if astIn.aggregate != nil && astIn.groupBy == nil && delegate.aggregatesFromSource { + // The one precomputed row, from `aggregate:`. + let table = topLevelAggregateTableName(queryID) + guard let source = delegate.getSource(table) else { + throw PipelineError("Aggregate source not found: \(table)") + } + let conn = try source.connect( + sort: [AST.OrderPart(AggregateColumns.key, .asc)], filters: nil, splitEditKeys: nil) + return delegate.decorateInput( + delegate.decorateSourceInput(conn, queryID: queryID), name: "\(name):aggregateSource") + } + if astIn.groupBy != nil && delegate.aggregatesFromSource { + return try groupFromSource(astIn, delegate, queryID, name) + } guard let source = delegate.getSource(astIn.table) else { throw PipelineError("Source not found: \(astIn.table)") } @@ -499,6 +538,26 @@ func applyCorrelatedSubQuery( // empty array. if sq.subquery.limit == 0 && fromCondition { return end } guard let alias = sq.subquery.alias else { preconditionFailure("Subquery must have an alias") } + if let aggregate = sq.aggregate, delegate.aggregatesFromSource { + // The precomputed rows, one per parent, keyed by the correlation columns + // under the server's names. + if aggregate.distinct != nil { + throw PipelineError("a count of distinct values is not supported in a relationship yet") + } + let childKey = delegate.aggregateKeyColumns(sq.subquery.table, sq.correlation.childField) + // The server builds its operator with these names and rejects a + // collision; so does the client. + for column in childKey { try assertNotSyntheticColumn(column) } + let child = try aggregateFromSource(sq, aggregate, childKey, delegate, queryID, name) + let join = Join( + parent: end, child: child, parentKey: sq.correlation.parentField, childKey: childKey, + relationshipName: alias, hidden: sq.hidden ?? false, system: sq.system ?? .client, + parentPartitionKey: fromCondition ? nil : parentPartitionKey, boundProvider: boundProvider, + exists: exists) + delegate.addEdge(end, join) + delegate.addEdge(child, join) + return delegate.decorateInput(join, name: "\(name):join(\(alias))") + } var child = try buildPipelineInternal( sq.subquery, delegate, queryID, childPipelineName(name, sq), partitionKey: sq.correlation.childField, isNonFlippedExistsChild: fromCondition) @@ -705,6 +764,25 @@ package func groupTableName(_ queryID: String) -> String { aggregateTablePrefix + queryID + ":#group" } +/// `isAggregateTableName`: a synthetic aggregate table, of any kind. +package func isAggregateTableName(_ name: String) -> Bool { + name.utf8.starts(with: aggregateTablePrefix.utf8) +} + +/// `isTopLevelAggregateTableName`: `aggregate:`, with no further +/// `:`, unlike a relationship aggregate's or a grouped query's. +package func isTopLevelAggregateTableName(_ name: String) -> Bool { + isAggregateTableName(name) + && !name.utf8.dropFirst(aggregateTablePrefix.utf8.count).contains(UInt8(ascii: ":")) +} + +/// `isKeyedAggregateTableName`: a table whose rows `_0_key` alone keys: a +/// top-level aggregate's or a grouped query's. +package func isKeyedAggregateTableName(_ name: String) -> Bool { + isTopLevelAggregateTableName(name) + || (isAggregateTableName(name) && name.utf8.reversed().starts(with: ":#group".utf8.reversed())) +} + /// `reducerOf`: what a grouped query reduces each group to, its aggregate or /// a count. func reducerOf(_ ast: AST) throws(PipelineError) -> Reducer { @@ -713,15 +791,141 @@ func reducerOf(_ ast: AST) throws(PipelineError) -> Reducer { /// `groupViewInput`: the input of a grouped query's view: its rows reduced /// to the group columns and, for a `groupBy()` with an aggregate, the value -/// under the function's name. +/// under the function's name, by the names of the pipeline's AST. package func groupViewInput( _ input: any Input, _ ast: AST, _ delegate: any BuilderDelegate ) throws(PipelineError) -> any Input { - let names = delegate.mapAst(ast).groupBy ?? [] + let viewNames = delegate.mapAst(ast).groupBy ?? [] + let names = + delegate.aggregatesFromSource ? inputNames(ast, delegate, ast.groupBy ?? []) : viewNames return try GroupProjection( - input, columns: names.map { ($0, $0) }, valueName: ast.aggregate?.fn.rawValue) + input, columns: zip(viewNames, names).map { ($0, $1) }, valueName: ast.aggregate?.fn.rawValue) +} + +/// `inputNames`: the names a grouped query's input rows have `columns` +/// under: the query's, or the server's for a synced client. +func inputNames(_ ast: AST, _ delegate: any BuilderDelegate, _ columns: [String]) -> [String] { + delegate.aggregatesFromSource ? delegate.aggregateKeyColumns(ast.table, columns) : columns +} + +/// `renameColumns`: `columns` with each of `from` named as the same +/// position of `to`. +func renameColumns( + _ columns: [String: ColumnSchema], _ from: [String], _ to: [String] +) -> [(String, ColumnSchema)] { + columns.sorted { StringCompare.utf16Less($0.key, $1.key) }.map { name, schema in + (from.firstIndex(of: name).map { to[$0] } ?? name, schema) + } +} + +/// The source mode of an aggregate relationship: reads the rows the server +/// computed from `aggregate::`, provisioned with the +/// child's column types, and registers how a child row's mutation moves +/// them when the row alone can tell. +func aggregateFromSource( + _ sq: AST.CorrelatedSubquery, _ aggregate: AST.Aggregate, _ childKey: [String], + _ delegate: any BuilderDelegate, _ queryID: String, _ name: String +) throws(PipelineError) -> any Input { + let table = aggregateTableName(queryID, sq, parentName: name) + guard let childSource = delegate.getSource(sq.subquery.table) else { + throw PipelineError("Source not found: \(sq.subquery.table)") + } + // A junction aggregate's field is on the destination, one hop past the + // junction rows that hold the key. + var inputColumns = childSource.tableSchema.columns + let isJunction = !(sq.subquery.related ?? []).isEmpty + if isJunction, let dest = sq.subquery.related?.first?.subquery.table { + guard let destSource = delegate.getSource(dest) else { + throw PipelineError("Source not found: \(dest)") + } + inputColumns.merge(destSource.tableSchema.columns) { $1 } + } + let (clientColumns, _) = try aggregateSourceSchema( + inputColumns, groupKey: sq.correlation.childField, aggregate) + let columns = renameColumns(clientColumns, sq.correlation.childField, childKey) + // Optimism only for count, sum and avg of a direct, unbounded relationship + // whose `where` a child row alone decides: otherwise the server's value + // stands until it sends another. + var optimistic: OptimisticAggregate? + if !isJunction && aggregate.fn.isInvertible && sq.subquery.limit == nil + && sq.subquery.start == nil, let predicate = try perRowPredicate(sq.subquery.where) + { + optimistic = OptimisticAggregate( + aggregateTable: table, table: sq.subquery.table, childField: sq.correlation.childField, + keyField: childKey, aggregate: aggregate, predicate: predicate, grouped: false) + } + guard + let source = delegate.getAggregateSource( + table, columns: columns, primaryKey: childKey, optimistic: optimistic) + else { throw PipelineError("Aggregate source not found: \(table)") } + let conn = try source.connect( + sort: childKey.map { AST.OrderPart($0, .asc) }, filters: nil, splitEditKeys: nil) + return delegate.decorateInput( + delegate.decorateSourceInput(conn, queryID: queryID), + name: "\(name):aggregateSource(\(sq.subquery.alias ?? ""))") +} + +/// A `where` compiled to a predicate on a row alone: `.some(nil)` when there +/// is none, nil when it has a subquery, which a row alone can't judge. +func perRowPredicate(_ condition: AST.Condition?) throws(PipelineError) -> RowPredicate?? { + guard let condition else { return .some(nil) } + let transformed = transformFilters(condition) + guard !transformed.conditionsRemoved, let filters = transformed.filters else { return nil } + return .some(try createPredicate(filters)) +} + +/// `groupFromSource`: a synced client reads a grouped query's rows from the +/// source the server streams them to. +func groupFromSource( + _ ast: AST, _ delegate: any BuilderDelegate, _ queryID: String, _ name: String +) throws(PipelineError) -> any Input { + guard let tableSource = delegate.getSource(ast.table) else { + throw PipelineError("Source not found: \(ast.table)") + } + let reducer = try reducerOf(ast) + // The group columns and the aggregated field, under the server's names. + var columns = ast.groupBy ?? [] + if let field = reducer.aggregate.field, !columns.contains(field) { columns.append(field) } + let names = inputNames(ast, delegate, columns) + func inputName(_ column: String) -> String { names[columns.firstIndex(of: column)!] } + var inputColumns: [String: ColumnSchema] = [:] + for column in columns { + inputColumns[inputName(column)] = tableSource.tableSchema.columns[column] + } + var serverAggregate = reducer.aggregate + serverAggregate.field = serverAggregate.field.map(inputName) + let ordering = groupOrdering(ast).map { AST.OrderPart(inputName($0.field), $0.direction) } + let (sourceColumns, primaryKey, sort) = try groupSourceSchema( + inputColumns, ordering, serverAggregate) + let table = groupTableName(queryID) + guard + let source = delegate.getAggregateSource( + table, columns: sourceColumns.sorted { StringCompare.utf16Less($0.key, $1.key) }.map { $0 }, + primaryKey: primaryKey, + optimistic: try groupOptimisticDelta(ast, reducer, table, inputName)) + else { throw PipelineError("Group source not found: \(table)") } + let conn = try source.connect(sort: sort, filters: nil, splitEditKeys: nil) + return delegate.decorateInput( + delegate.decorateSourceInput(conn, queryID: queryID), name: "\(name):groupSource") +} + +/// `groupOptimisticDelta`: how a mutation of the table's rows moves a +/// grouped query's rows, for count, sum and avg when the `where` can be +/// judged from a row alone. +func groupOptimisticDelta( + _ ast: AST, _ reducer: Reducer, _ table: String, _ inputName: (String) -> String +) throws(PipelineError) -> OptimisticAggregate? { + guard reducer.fn.isInvertible, let predicate = try perRowPredicate(ast.where) else { + return nil + } + // In the group's order, which the server's GroupBy keys a row by. + let columns = groupOrdering(ast).map(\.field) + return OptimisticAggregate( + aggregateTable: table, table: ast.table, childField: columns, + keyField: columns.map(inputName), aggregate: reducer.aggregate, predicate: predicate, + grouped: true) } /// JS's `encodeURIComponent`: every UTF-8 byte but the letters, digits and diff --git a/swift/Sources/Zero/Client/Engine.swift b/swift/Sources/Zero/Client/Engine.swift index 3695c82e61..968c04646b 100644 --- a/swift/Sources/Zero/Client/Engine.swift +++ b/swift/Sources/Zero/Client/Engine.swift @@ -258,6 +258,7 @@ final class Engine { guard case .closed(let reason) = self?.connectionManager.state else { return nil } return reason }) + context.rebasePending = { [weak self] in try self?.rebasePending() } _ = connectionManager.subscribe { [weak self] state in self?.onConnectionStateChange(state) } onConnectionStateChange(connectionManager.state) queryManager = QueryManager( @@ -1573,6 +1574,26 @@ final class Engine { } } + /// Runs the pending mutations again over the server snapshot, as a poke + /// that changes nothing would, so they move the synced aggregates a query + /// registered since they last ran. Not while a mutator runs: the next + /// rebase replays them then. + private func rebasePending() throws { + guard !writeLocked, !store.pending.isEmpty else { return } + try withWriteLock { + let snapshot = store.snapshot + let touched = store.pendingWrites + let branch = ivmMain.fork() + branch.apply(KVDiff.between(store.main, snapshot.map, keys: touched)) + let rebased = replay(store.pending, over: snapshot.map, branch: branch) + let diff = store.advance( + to: snapshot, main: rebased.main, pending: rebased.replayed, + touched: touched.union(rebased.touched)) + try context.processChanges(diff) + fireWatchers(diff) + } + } + /// Runs `pending` again, in order, over `map` and on forks of `branch` /// (the rebase of `maybeEndPull`). A mutation that throws stays pending /// without writes. Returns the new main map, the mutations with what they @@ -1637,7 +1658,7 @@ final class Engine { var keyless: [String: [Row]] = [:] for case .update(let key, _, _) in patch { guard let value = write.get(key) else { continue } - let table = IVMBranch.sourceName(key) + let table = Keys.sourceName(key) guard let primaryKey = schema.tables[table]?.primaryKey else { continue } let row = value.objectValue ?? [:] if let rowKey = try? Keys.primaryKeyString(table: table, primaryKey: primaryKey, row: row) { diff --git a/swift/Sources/Zero/Client/IVMBranch.swift b/swift/Sources/Zero/Client/IVMBranch.swift index 41d44f6def..2ae27c56ac 100644 --- a/swift/Sources/Zero/Client/IVMBranch.swift +++ b/swift/Sources/Zero/Client/IVMBranch.swift @@ -8,44 +8,135 @@ final class IVMBranch { /// The layout of each table's rows. Forks share them, so the rows a /// mutator writes in a fork go into this branch's sources as they are. private let layouts: [String: RowLayout] + /// The synced aggregates a child row's mutation moves, shared with the + /// forks: it is query metadata, not row state. + private let optimism: AggregateOptimism + /// Only the main branch registers optimistic aggregates and releases + /// aggregate sources (see `aggregateSource`). + private let isFork: Bool + /// Set when an aggregate's optimism is registered for the first time + /// since it was released, or since launch; see `takeNewRegistration`. + private var newRegistration = false convenience init(schema: ZeroSchema) { - self.init(schema: schema, sources: [:], layouts: schema.tables.mapValues { RowLayout($0) }) + self.init( + schema: schema, sources: [:], layouts: schema.tables.mapValues { RowLayout($0) }, + optimism: AggregateOptimism(), isFork: false) } - private init(schema: ZeroSchema, sources: [String: MemorySource?], layouts: [String: RowLayout]) { + private init( + schema: ZeroSchema, sources: [String: MemorySource?], layouts: [String: RowLayout], + optimism: AggregateOptimism, isFork: Bool + ) { self.schema = schema self.sources = sources self.layouts = layouts + self.optimism = optimism + self.isFork = isFork } func source(_ table: String) -> MemorySource? { if let source = sources[table] { return source } - let source = schema.tables[table].map { MemorySource($0, layout: layouts[table]!) } + let source: MemorySource? + if let tableSchema = schema.tables[table] { + source = MemorySource(tableSchema, layout: layouts[table]!) + } else if isTopLevelAggregateTableName(table) { + // A synced top-level aggregate's source. Its shape is fixed, so it can + // be made from the name alone, also before its query materializes on + // a reload. The payload is typed as `inferAggregateSchema` types it. + source = MemorySource( + TableSchema( + name: table, + columns: [(AggregateColumns.key, ColumnSchema(.number))] + + AggregateColumns.payloadOrder.map { ($0, ColumnSchema(.number, optional: true)) }, + primaryKey: [AggregateColumns.key])) + } else { + source = nil + } sources[table] = .some(source) return source } + /// `getOrCreateAggregateSource`: the source of a relationship aggregate's + /// or a grouped query's rows, whose shape the name doesn't give. The + /// builder gives it when a query materializes; `apply` infers it from a + /// row when stored rows are loaded first. The first caller's shape wins. + func aggregateSource( + _ name: String, columns: [(String, ColumnSchema)], primaryKey: [String], + optimistic: OptimisticAggregate? = nil + ) -> MemorySource { + // A fork's queries are never synced, so only the main branch, which + // releases them, registers. + if let optimistic, !isFork { + if optimism.byTable[optimistic.table]?[name] == nil { newRegistration = true } + optimism.byTable[optimistic.table, default: [:]][name] = optimistic + } + if let existing = sources[name] ?? nil { return existing } + let source = MemorySource(TableSchema(name: name, columns: columns, primaryKey: primaryKey)) + sources[name] = .some(source) + return source + } + + /// Whether an aggregate's optimism was registered for the first time since + /// the last call. Swift only: JS persists a pending mutation's writes, so + /// after a restart its view still has the moves the mutation made. Swift + /// stores the mutation and replays it at launch, before any query + /// registers, so the client rebases the pending mutations once one does. + func takeNewRegistration() -> Bool { + defer { newRegistration = false } + return newRegistration + } + + /// `serverColumnNames`: the server names of `columns` of `table`. + func serverColumnNames(_ table: String, _ columns: [String]) -> [String] { + let tableColumns = schema.tables[table]?.columns + return columns.map { tableColumns?[$0]?.serverName ?? $0 } + } + + /// `getOptimisticAggregates`: the synced aggregates whose child rows live + /// in `table`, by name. + func optimisticAggregates(_ table: String) -> [OptimisticAggregate] { + (optimism.byTable[table] ?? [:]).sorted { StringCompare.utf16Less($0.key, $1.key) } + .map(\.value) + } + /// A copy whose sources share rows with these until written. func fork() -> IVMBranch { - IVMBranch(schema: schema, sources: sources.mapValues { $0?.fork() }, layouts: layouts) + IVMBranch( + schema: schema, sources: sources.mapValues { $0?.fork() }, layouts: layouts, + optimism: optimism, isFork: true) } - /// Applies the entity changes of `diff` (`applyDiffs`). A run of adds to - /// one table is pushed together. A row in `rows`, by key, is the one a - /// transaction wrote, which is the value the diff has for it. + /// Applies the row changes of `diff` (`applyDiffs`): the aggregate rows + /// under `a/`, then the table rows under `e/`, which is key order. A run + /// of adds to one source is pushed together. A row in `rows`, by key, is + /// the one a transaction wrote, which is the value the diff has for it. + /// The main branch then releases the aggregate sources nothing uses. func apply(_ diff: KVDiff, rows written: [String: Row] = [:]) { - let prefix = Keys.entitiesPrefix var i = 0 // JS's throw ends `applyDiffs` at the change an operator failed on. while i < diff.count, !PipelineFailure.hasFailed { let op = diff[i] - guard op.key.utf8.starts(with: prefix.utf8) else { + let isAggregate = op.key.utf8.starts(with: Keys.aggregatesPrefix.utf8) + guard isAggregate || op.key.utf8.starts(with: Keys.entitiesPrefix.utf8) else { i += 1 continue } - let name = Self.sourceName(op.key) - guard let source = source(name) else { + let name = Keys.sourceName(op.key) + var source = source(name) + if source == nil, isAggregate { + // A relationship aggregate's or a grouped query's rows replayed + // before its query materializes (a reload): the source takes the + // row's shape, and the builder reuses it. + let row: JSONValue + switch op { + case .del(_, let old): row = old + case .add(_, let new), .change(_, _, let new): row = new + } + let (columns, primaryKey) = Self.inferAggregateSchema(name, row.objectValue ?? [:]) + source = aggregateSource(name, columns: columns, primaryKey: primaryKey) + } + guard let source else { i += 1 continue } @@ -60,10 +151,14 @@ final class IVMBranch { oldRow: Row(old.objectValue ?? [:], layout: source.layout))) i += 1 case .add: - let tablePrefix = prefix + name + "/" + // The source's own prefix: the key up to the slash after its name. + let keyPrefix = isAggregate ? Keys.aggregatesPrefix : Keys.entitiesPrefix + let sourcePrefix = + keyPrefix + + (isAggregate ? String(name.dropFirst(aggregateTablePrefix.count)) : name) + "/" var rows: [Row] = [] while i < diff.count, case .add(let key, let value) = diff[i], - key.utf8.starts(with: tablePrefix.utf8) + key.utf8.starts(with: sourcePrefix.utf8) { rows.append(written[key] ?? Row(value.objectValue ?? [:], layout: source.layout)) i += 1 @@ -71,12 +166,82 @@ final class IVMBranch { source.pushAdds(rows) } } + if !isFork && !PipelineFailure.hasFailed { releaseAggregateSources() } } - /// `sourceNameFromKey`: the table of an `e//` key. - static func sourceName(_ key: String) -> String { - let rest = key.utf8.dropFirst(Keys.entitiesPrefix.utf8.count) - let end = rest.firstIndex(of: UInt8(ascii: "/")) ?? rest.endIndex - return String(rest[rest.startIndex.. (columns: [(String, ColumnSchema)], primaryKey: [String]) { + var columns: [(String, ColumnSchema)] = [] + for (column, value) in row where column != Keys.rowVersionColumn { + columns.append( + ( + column, + AggregateColumns.payload.contains(column) + ? ColumnSchema(.number, optional: true) : ColumnSchema(value.valueType) + )) + } + if !columns.contains(where: { $0.0 == AggregateColumns.value }) { + columns.append((AggregateColumns.value, ColumnSchema(.number, optional: true))) + } + return (columns, Keys.aggregateRowKeyColumns(table: name, columns: row.keys)) + } +} + +/// `OptimisticAggregate`: how a mutation of a child row moves a synced +/// aggregate's row. Registered when a query with a relationship aggregate +/// or a grouping materializes. +package struct OptimisticAggregate { + /// The aggregate's table, `aggregate::` or `…:#group`. + package let aggregateTable: String + /// The child table whose mutations move it. + package let table: String + /// The correlation (or group) columns of a child row, by client name. + package let childField: [String] + /// The same columns as the aggregate rows name them: server names. + package let keyField: [String] + package let aggregate: AST.Aggregate + /// The aggregate's `where` as a row predicate; nil when every child row + /// counts. + package let predicate: RowPredicate? + /// The rows are a grouped query's groups, keyed by `_0_key`: a group is + /// added with its first row and removed with its last. + package let grouped: Bool +} + +/// The registry of optimistic aggregates, by child table and then by +/// aggregate table, shared by a branch and its forks. +final class AggregateOptimism { + var byTable: [String: [String: OptimisticAggregate]] = [:] +} + +extension JSONValue { + /// `valueTypeOf`: the column type of a value. + var valueType: ValueType { + switch self { + case .string: .string + case .number: .number + case .bool: .boolean + case .null: .null + case .array, .object: .json + } } } diff --git a/swift/Sources/Zero/Client/Keys.swift b/swift/Sources/Zero/Client/Keys.swift index 1d0d99b07c..07413cd7fb 100644 --- a/swift/Sources/Zero/Client/Keys.swift +++ b/swift/Sources/Zero/Client/Keys.swift @@ -3,6 +3,12 @@ package enum Keys { package static let desiredQueriesPrefix = "d/" package static let gotQueriesPrefix = "g/" package static let entitiesPrefix = "e/" + /// Synced aggregate rows live outside `e/`, which a client from before + /// them loads into its schema's tables: both can share a database. + package static let aggregatesPrefix = "a/" + /// The row-version column the server stamps on synced rows; not part of + /// an aggregate row's key. + package static let rowVersionColumn = "_0_version" package static let mutationsPrefix = "m/" package struct InvalidPrimaryKeyValue: Error, CustomStringConvertible { @@ -30,8 +36,32 @@ package enum Keys { try primaryKeyString(table: table, primaryKey: primaryKey) { row[$0] } } + /// `aggregateRowKey`: `a/`, the table name without its `aggregate:`, and + /// the row's key, from `aggregateRowKeyColumns`. A `put`'s full row, a + /// `del`'s key and an optimistic delta all give the same key. + package static func aggregateRowKey( + table: String, row: RowRecord + ) throws(InvalidPrimaryKeyValue) -> String { + try primaryKeyString( + prefix: aggregatesPrefix, table: String(table.dropFirst(aggregateTablePrefix.count)), + primaryKey: aggregateRowKeyColumns(table: table, columns: row.keys) + ) { row[$0] } + } + + /// `aggregateRowKeyColumns`: `_0_key` for a top-level aggregate's or a + /// grouped query's row, and otherwise every column but the payload and + /// the row version, sorted. The table name decides, not the row. + package static func aggregateRowKeyColumns( + table: String, columns: some Sequence + ) -> [String] { + if isKeyedAggregateTableName(table) { return [AggregateColumns.key] } + return columns.filter { !AggregateColumns.payload.contains($0) && $0 != rowVersionColumn } + .sorted(by: StringCompare.utf16Less) + } + private static func primaryKeyString( - table: String, primaryKey: [String], value: (String) -> JSONValue? + prefix: String = entitiesPrefix, table: String, primaryKey: [String], + value: (String) -> JSONValue? ) throws(InvalidPrimaryKeyValue) -> String { func scalar(_ column: String) throws(InvalidPrimaryKeyValue) -> JSONValue { let v = value(column) @@ -42,12 +72,12 @@ package enum Keys { } if primaryKey.count == 1 { let v = try scalar(primaryKey[0]) - return entitiesPrefix + table + "/" + jsString(v) + return prefix + table + "/" + jsString(v) } var values: [JSONValue] = [] for column in primaryKey { values.append(try scalar(column)) } let hash = XXHash32.h128(JSONSerializer.stringify(.array(values))) - return entitiesPrefix + table + "/" + String(hash) + return prefix + table + "/" + String(hash) } /// JS `String(v)` for a scalar. @@ -61,6 +91,16 @@ package enum Keys { } } + /// `sourceNameFromKey`: the source of an `e/` or `a/` row key. An `a/` + /// key leaves out the `aggregate:` of the table's name. + package static func sourceName(_ key: String) -> String { + // Both prefixes are two characters long. + let rest = key.utf8.dropFirst(entitiesPrefix.utf8.count) + let end = rest.firstIndex(of: UInt8(ascii: "/")) ?? rest.endIndex + let name = String(rest[rest.startIndex.. String { desiredQueriesPrefix + clientID + "/" + hash } diff --git a/swift/Sources/Zero/Client/PokeHandler.swift b/swift/Sources/Zero/Client/PokeHandler.swift index ff6297fd0c..da65304530 100644 --- a/swift/Sources/Zero/Client/PokeHandler.swift +++ b/swift/Sources/Zero/Client/PokeHandler.swift @@ -283,6 +283,7 @@ final class PokeHandler { } private func rowPatchOp(_ op: RowPatchOp) throws -> KVPatchOp? { + if let aggregate = try Self.aggregateRowPatchOp(op) { return aggregate } switch op { case .clear: return .clear @@ -304,6 +305,24 @@ final class PokeHandler { } } + /// `aggregateRowsPatchOp`: a synced aggregate row goes to its synthetic + /// table's `a/` key. Such tables aren't in the schema, and their columns + /// have no client names, so the row is kept as sent. Nil for another op. + private static func aggregateRowPatchOp(_ op: RowPatchOp) throws -> KVPatchOp? { + switch op { + case .put(let table, let value) where isAggregateTableName(table): + return .put(key: try Keys.aggregateRowKey(table: table, row: value), value: .object(value)) + case .del(let table, let id) where isAggregateTableName(table): + return .del(key: try Keys.aggregateRowKey(table: table, row: id)) + case .update(let table, let id, let merge, let constrain) where isAggregateTableName(table): + return .update( + key: try Keys.aggregateRowKey(table: table, row: id), + merge: merge.map { $0.objectValue ?? [:] }, constrain: constrain) + default: + return nil + } + } + private func key(_ table: String, _ row: RowRecord) throws -> String { try Keys.primaryKeyString(table: table, primaryKey: schema.tables[table]!.primaryKey, row: row) } diff --git a/swift/Sources/Zero/Client/QueryContext.swift b/swift/Sources/Zero/Client/QueryContext.swift index 46efeea463..884457cf49 100644 --- a/swift/Sources/Zero/Client/QueryContext.swift +++ b/swift/Sources/Zero/Client/QueryContext.swift @@ -1,8 +1,23 @@ /// Builds pipelines over the sources of an IVM branch. final class BranchDelegate: BuilderDelegate { let branch: IVMBranch - init(_ branch: IVMBranch) { self.branch = branch } + /// The synced client reads aggregates from the rows the server streams; + /// a mutator's query the server hasn't answered computes them. + let aggregatesFromSource: Bool + init(_ branch: IVMBranch, aggregatesFromSource: Bool = true) { + self.branch = branch + self.aggregatesFromSource = aggregatesFromSource + } func getSource(_ tableName: String) -> (any Source)? { branch.source(tableName) } + func getAggregateSource( + _ name: String, columns: [(String, ColumnSchema)], primaryKey: [String], + optimistic: OptimisticAggregate? + ) -> (any Source)? { + branch.aggregateSource(name, columns: columns, primaryKey: primaryKey, optimistic: optimistic) + } + func aggregateKeyColumns(_ table: String, _ columns: [String]) -> [String] { + branch.serverColumnNames(table, columns) + } } /// Materializes queries over an IVM branch, registers named ones with the @@ -49,10 +64,11 @@ final class QueryContext { batchViewUpdates: @escaping (() -> Void) -> Void, microtask: @escaping (@escaping () -> Void) -> Void, log: Log? = nil, - closedReason: @escaping () -> ConnectionError? = { nil } + closedReason: @escaping () -> ConnectionError? = { nil }, + aggregatesFromSource: Bool = true ) { self.branch = branch - self.delegate = BranchDelegate(branch) + self.delegate = BranchDelegate(branch, aggregatesFromSource: aggregatesFromSource) self.addCustomQuery = addCustomQuery self.updateCustomQuery = updateCustomQuery self.batchViewUpdatesImpl = batchViewUpdates @@ -88,11 +104,12 @@ final class QueryContext { } /// A context for the queries a mutator runs: nothing is registered with - /// the server, and the branch is already populated. - static func local(_ branch: IVMBranch) -> QueryContext { + /// the server, and the branch is already populated. `aggregatesFromSource` + /// reads aggregates from the synced rows rather than computing them. + static func local(_ branch: IVMBranch, aggregatesFromSource: Bool) -> QueryContext { let context = QueryContext( branch: branch, addCustomQuery: { _, _, _, _ in {} }, updateCustomQuery: { _, _ in }, - batchViewUpdates: { $0() }, microtask: { $0() }) + batchViewUpdates: { $0() }, microtask: { $0() }, aggregatesFromSource: aggregatesFromSource) context.markPipelinesReady() return context } @@ -149,6 +166,10 @@ final class QueryContext { /// on, and every later push, `materialize`, and mutation fails with it. private(set) var branchFailure: PipelineError? + /// Rebases the pending mutations over the server snapshot. The engine + /// sets it; see `IVMBranch.takeNewRegistration`. + var rebasePending: () throws -> Void = {} + /// Pushes `diff` into the branch and flushes the views. A push an /// operator fails (where JS throws from it) still flushes what the views /// got, as JS's `finally` does, and then throws. @@ -259,6 +280,10 @@ final class QueryContext { } // A view of a grouped query shows only its columns and value. input = ast.groupBy != nil ? try groupViewInput(pipeline, ast, delegate) : pipeline + // The pending mutations moved no synced aggregate the query now lets + // them move; rebasing them does, before the view hydrates. The new + // pipeline has no output yet, so it drops what the rebase pushes. + if branch.takeNewRegistration() { try rebasePending() } } catch { removeAddedQuery() throw error diff --git a/swift/Sources/Zero/Client/Transaction.swift b/swift/Sources/Zero/Client/Transaction.swift index fac128a160..1452f255b0 100644 --- a/swift/Sources/Zero/Client/Transaction.swift +++ b/swift/Sources/Zero/Client/Transaction.swift @@ -24,7 +24,12 @@ public final class Transaction { /// The rows written, by key, as the branch has them, so the main branch /// can take the same rows rather than a copy of each. private(set) var rows: [String: Row] = [:] - private lazy var context = QueryContext.local(branch) + /// A mutator's query computes its aggregates from the branch's rows, + /// unless the server has answered it: then it reads the synced rows, with + /// this client's pending changes applied, as a view of it does + /// (`MutatorContext` in `custom.ts`). + private lazy var context = QueryContext.local(branch, aggregatesFromSource: false) + private lazy var syncedContext = QueryContext.local(branch, aggregatesFromSource: true) init( clientID: String, mutationID: Int, reason: Reason, token: String?, write: KVWrite, @@ -44,12 +49,16 @@ public final class Transaction { /// The rows `query` returns over this transaction's data. public func run(_ query: Query) throws -> S { - try S(view: context.snapshot(query.any)) + try S(view: run(query.any)) } /// The rows `query` returns over this transaction's data. public func run(_ query: AnyQuery) throws -> ViewValue { - try context.snapshot(query) + let queryID = + query.customQueryID.map { QueryHash.hashOfNameAndArgs($0.name, $0.args) } + ?? QueryHash.hashOfAST(query.ast) + return try (write.has(Keys.gotQueriesKey(hash: queryID)) ? syncedContext : context) + .snapshot(query) } func tableSchema(_ table: String) throws -> TableSchema { @@ -80,6 +89,7 @@ public final class Transaction { write.set(key, JSONValue(row)) rows[key] = row source.push(.add(row)) + try applyOptimisticAggregateDeltas(tableName, old: nil, new: row) } func upsert(_ tableName: String, _ value: Row) throws { @@ -101,8 +111,10 @@ public final class Transaction { write.set(key, .object(next)) let source = source(tableName) let row = Row(next, layout: source.layout) + let oldRow = Row(prev, layout: source.layout) rows[key] = row - source.push(.edit(row, oldRow: Row(prev, layout: source.layout))) + source.push(.edit(row, oldRow: oldRow)) + try applyOptimisticAggregateDeltas(tableName, old: oldRow, new: row) } func delete(_ tableName: String, _ id: Row) throws { @@ -112,7 +124,159 @@ public final class Transaction { write.delete(key) rows[key] = nil let source = source(tableName) - source.push(.remove(Row(prev, layout: source.layout))) + let oldRow = Row(prev, layout: source.layout) + source.push(.remove(oldRow)) + try applyOptimisticAggregateDeltas(tableName, old: oldRow, new: nil) + } + + // MARK: Optimistic aggregates (`crud-impl.ts`) + + /// `applyOptimisticAggregateDeltas`: moves the synced aggregates whose + /// child rows live in `table` by a child row's change, in this + /// transaction, so views and `run` see it at once. The rebase replays it + /// until the server confirms the mutation, whose value then replaces it. + /// An aggregate row not on the client is left alone, except that a + /// grouped query's group is added by its first row. + private func applyOptimisticAggregateDeltas(_ table: String, old: Row?, new: Row?) throws { + for agg in branch.optimisticAggregates(table) { + let oldKey = try old.flatMap { try aggregateKey(agg, $0) } + let newKey = try new.flatMap { try aggregateKey(agg, $0) } + // JS's `===`: by code unit. + let sameKey = + switch (oldKey, newKey) { + case (nil, nil): true + case (let a?, let b?): StringCompare.equal(a, b) + default: false + } + if sameKey { + if let oldKey { applyAggregateDelta(agg, oldKey, old, new) } + } else { + // The child leaves one aggregate and joins another; either may be + // none. + if let oldKey { applyAggregateDelta(agg, oldKey, old, nil) } + if let newKey { applyAggregateDelta(agg, newKey, nil, new) } + } + } + } + + /// `aggregateKeyFor`: the key of the aggregate row `child` counts in; nil + /// when a correlation value is null, which gives the child no parent. A + /// grouped query's group can have null values. + private func aggregateKey(_ agg: OptimisticAggregate, _ child: Row) throws -> String? { + if agg.grouped { + let values = agg.childField.map { child[$0] ?? .null } + return try Keys.aggregateRowKey( + table: agg.aggregateTable, row: [AggregateColumns.key: .string(groupKey(values))]) + } + var keyRow = JSONObject() + for (i, column) in agg.childField.enumerated() { + guard let value = child[column], value != .null else { return nil } + keyRow[agg.keyField[i]] = value + } + return try Keys.aggregateRowKey(table: agg.aggregateTable, row: keyRow) + } + + /// `applyAggregateDelta`: writes the aggregate row at `key` as one child + /// change moves it, if the row is on the client, and pushes it to the + /// branch so a later `run` reads it. A grouped query's row is added by a + /// group's first row and removed with its last. + private func applyAggregateDelta( + _ agg: OptimisticAggregate, _ key: String, _ old: Row?, _ new: Row? + ) { + // The branch holds the row when a view of its query reads it. + let source = branch.source(agg.aggregateTable) + guard let cur = write.get(key)?.objectValue else { + if agg.grouped, let added = newGroupRow(agg, old, new) { + write.set(key, .object(added)) + source?.push(.add(Row(added, layout: source!.layout))) + } + return + } + guard let updated = nextAggregateRow(agg, cur, old, new) else { return } + let curRow = source.map { Row(cur, layout: $0.layout) } + let inBranch = curRow.map { source!.data.contains($0) } ?? false + if agg.grouped, Self.groupRowCount(agg, updated) == 0 { + write.delete(key) + if inBranch { source!.push(.remove(curRow!)) } + return + } + write.set(key, .object(updated)) + if inBranch { source!.push(.edit(Row(updated, layout: source!.layout), oldRow: curRow!)) } + } + + /// `groupRowCount`: the number of rows of a group, nil for a sum or + /// average row stored before the rows carried it. + private static func groupRowCount(_ agg: OptimisticAggregate, _ row: JSONObject) -> JSONValue? { + row[agg.aggregate.fn == .count ? AggregateColumns.value : AggregateColumns.rows] + } + + /// `newGroupRow`: the row of a group not on the client that `new` is the + /// first row of: it passes the `where`, and `old` wasn't counted already. + private func newGroupRow(_ agg: OptimisticAggregate, _ old: Row?, _ new: Row?) -> JSONObject? { + func counted(_ row: Row?) -> Bool { + guard let row else { return false } + return agg.predicate?(row) ?? true + } + guard let new, counted(new), !counted(old) else { return nil } + let values = agg.childField.map { new[$0] ?? .null } + // The group with no rows, which `new` then joins. + var empty = JSONObject() + for (i, column) in agg.keyField.enumerated() { empty[column] = values[i] } + empty[AggregateColumns.key] = .string(groupKey(values)) + if agg.aggregate.fn == .count { + empty[AggregateColumns.value] = 0 + } else { + empty[AggregateColumns.value] = .null + empty[AggregateColumns.sum] = 0 + empty[AggregateColumns.count] = 0 + empty[AggregateColumns.rows] = 0 + } + return nextAggregateRow(agg, empty, nil, new) + } + + /// `nextAggregateRow`: the aggregate row after a child changes from `old` + /// to `new`, nil when it doesn't move. A row the `where` rejects counts + /// as absent, so a row entering or leaving the filtered set moves it too. + private func nextAggregateRow( + _ agg: OptimisticAggregate, _ cur: JSONObject, _ oldIn: Row?, _ newIn: Row? + ) -> JSONObject? { + let old = oldIn.flatMap { agg.predicate?($0) == false ? nil : $0 } + let new = newIn.flatMap { agg.predicate?($0) == false ? nil : $0 } + func number(_ v: JSONValue?) -> Double { v?.numberValue ?? 0 } + func contribution(_ row: Row?) -> JSONValue? { row.map { aggregateValue(agg.aggregate, $0) } } + func contributes(_ row: Row?) -> Bool { contribution(row)?.numberValue != nil } + var next = cur + switch agg.aggregate.fn { + case .count: + let delta = (new != nil ? 1.0 : 0) - (old != nil ? 1.0 : 0) + if delta == 0 { return nil } + next[AggregateColumns.value] = .number(number(cur[AggregateColumns.value]) + delta) + return next + case .sum, .avg: + guard agg.aggregate.field != nil else { return nil } + // The row carries the sum of the non-null values and their count, so + // both move and the value follows: SQL's sum and avg skip nulls and + // are null over none. A group's row also carries its number of rows, + // nulls included, unless it was stored before it did. + let sumDelta = number(contribution(new)) - number(contribution(old)) + let countDelta = (contributes(new) ? 1.0 : 0) - (contributes(old) ? 1.0 : 0) + let hasRows = cur[AggregateColumns.rows] != nil + let rowsDelta = hasRows ? (new != nil ? 1.0 : 0) - (old != nil ? 1.0 : 0) : 0 + if sumDelta == 0 && countDelta == 0 && rowsDelta == 0 { return nil } + let sum = number(cur[AggregateColumns.sum]) + sumDelta + let count = number(cur[AggregateColumns.count]) + countDelta + let result = agg.aggregate.fn == .sum ? sum : sum / count + next[AggregateColumns.value] = count > 0 ? .number(result) : .null + next[AggregateColumns.sum] = .number(sum) + next[AggregateColumns.count] = .number(count) + if hasRows { + next[AggregateColumns.rows] = .number(number(cur[AggregateColumns.rows]) + rowsDelta) + } + return next + case .min, .max: + // Not invertible: the server's next poke moves them. + return nil + } } } diff --git a/swift/Sources/Zero/IVM/Aggregate.swift b/swift/Sources/Zero/IVM/Aggregate.swift index dee6d2bff3..84cebc0f63 100644 --- a/swift/Sources/Zero/IVM/Aggregate.swift +++ b/swift/Sources/Zero/IVM/Aggregate.swift @@ -14,6 +14,8 @@ package enum AggregateColumns { /// The payload columns, which aren't part of a row's key. package static let payload: Set = [value, sum, count, rows] + /// The payload columns in JS's order. + package static let payloadOrder = [value, sum, count, rows] /// `isSyntheticColumn`. package static func isSynthetic(_ column: String) -> Bool { diff --git a/swift/Tests/ConformanceTests/ClientApp.swift b/swift/Tests/ConformanceTests/ClientApp.swift index 8aa02dd43f..110adaacc3 100644 --- a/swift/Tests/ConformanceTests/ClientApp.swift +++ b/swift/Tests/ConformanceTests/ClientApp.swift @@ -31,6 +31,22 @@ enum ClientApp { .orderBy("id", .asc) }, "users.all": { _ in zql("user").orderBy("id", .asc) }, + "aggregates.issueCount": { _ in zql("issue").count() }, + "aggregates.openIssueCount": { _ in zql("issue").where("closed", false).count() }, + "aggregates.commentCounts": { _ in + zql("issue").related("comments") { $0.count() }.orderBy("id", .asc) + }, + "aggregates.commentTimes": { _ in + zql("issue") + .related("comments") { $0.where("authorId", .ne, "u9").avg("createdAt") } + .orderBy("id", .asc) + }, + "aggregates.labelCounts": { _ in + zql("issue").related("labels") { $0.count() }.orderBy("id", .asc) + }, + "aggregates.owners": { _ in zql("issue").distinct("ownerId") }, + "aggregates.commentsByIssue": { _ in zql("comment").groupBy("issueId").count() }, + "aggregates.timeByAuthor": { _ in zql("comment").groupBy("authorId").sum("createdAt") }, "issueLabels.all": { _ in zql("issueLabel").orderBy("issueId", .asc).orderBy("labelId", .asc) }, @@ -154,6 +170,26 @@ enum ClientApp { } return args?["return"] }, + // Runs CRUD operations, then each named query through the transaction, + // and returns what they read (`aggregates.read` in app.ts). + JSONMutator(name: "aggregates.read") { tx, args in + for o in args?["ops"]?.arrayValue ?? [] { + let table = tx.mutate.table(o["table"]?.stringValue ?? "") + let value = Row(o["value"]?.objectValue ?? [:]) + switch o["op"]?.stringValue { + case "insert": try table.insert(value) + case "upsert": try table.upsert(value) + case "update": try table.update(value) + case "delete": try table.delete(value) + default: throw Failure("Unknown op") + } + } + var out: [JSONValue] = [] + for q in args?["queries"]?.arrayValue ?? [] { + out.append(try tx.run(request(q["name"]?.stringValue ?? "", q["args"])).json ?? .null) + } + return .array(out) + }, JSONMutator(name: "comment.add") { tx, args in var row: Row = [ "authorId": field(args, "authorId", "u1"), diff --git a/swift/Tests/E2ETests/AggregateE2ETests.swift b/swift/Tests/E2ETests/AggregateE2ETests.swift new file mode 100644 index 0000000000..7083afba50 --- /dev/null +++ b/swift/Tests/E2ETests/AggregateE2ETests.swift @@ -0,0 +1,98 @@ +import Foundation +import Testing + +@testable import Zero + +/// Synced aggregates against zero-cache, the API server, and Postgres: the +/// rows zero-cache computes and streams (`aggregates` in +/// `packages/zero-conformance/src/e2e/app.ts`), and a grouped count moved +/// optimistically by a mutation and then confirmed. +@Suite(.enabled(if: E2E.url != nil), .timeLimit(.minutes(2))) +@MainActor +struct AggregateE2ETests { + let directory = NSTemporaryDirectory() + "zero-e2e-" + UUID().uuidString + + func makeZero() throws -> Zero { + let origin = E2E.url!.replacingOccurrences(of: "ws://", with: "http://") + let options = ZeroOptions( + cacheURL: origin, storageKey: UUID().uuidString, storage: .sqlite(directory: directory)) + return try Zero( + schema: .test, mutators: [E2EApp.create, E2EApp.close], options: options, + socketFactory: TransportSocketFactory(E2E.transport)) + } + + func eventually( + _ what: String, timeout: Duration = .seconds(30), _ condition: () -> Bool + ) async throws { + let deadline = ContinuousClock.now + timeout + while !condition() { + guard ContinuousClock.now < deadline else { + Issue.record("Timed out waiting for \(what)") + throw CancellationError() + } + try await Task.sleep(for: .milliseconds(20)) + } + } + + func named(_ query: AnyQuery, _ name: String, _ args: JSONValue? = nil) -> AnyQuery { + query.nameAndArgs(name, args.map { [$0] } ?? []) + } + + @Test func syncsAggregatesAndMovesThemOptimistically() async throws { + defer { try? FileManager.default.removeItem(atPath: directory) } + let zero = try makeZero() + defer { zero.close() } + let zql = { (table: String) in AnyQuery(.test, table) } + + let count = try zero.materialize( + named(zql("comment").count(), "aggregates.commentCount")) + let perIssue = try zero.materialize( + named( + zql("issue").where("id", .in, ["i1", "i2", "i3", "i4"]) + .related("comments") { $0.count() }.orderBy("id", .asc), + "aggregates.commentCounts")) + let byAuthor = try zero.materialize( + named(zql("comment").groupBy("authorId").count(), "aggregates.commentsByAuthor")) + // Before the server answers, a count is 0. + #expect(count.data == .value(0)) + try await eventually("the aggregates") { + [count, perIssue, byAuthor].allSatisfy { $0.resultType == .complete } + } + #expect(count.data == .value(3)) + #expect( + perIssue.data.entries.map { $0.relationships["comments"] } + == [.value(2), .value(0), .value(1), .value(0)]) + #expect( + byAuthor.data.json + == [ + ["authorId": "u1", "count": 1], ["authorId": "u2", "count": 1], + ["authorId": "u3", "count": 1], + ]) + + // A grouped count moves with the mutation at once; a top-level one + // when the server confirms it. + let title = "aggregates \(UUID().uuidString)" + let titled = try zero.materialize( + named( + zql("issue").where("title", .string(title)).count(), "aggregates.titled", .string(title))) + let owners = try zero.materialize( + named( + zql("issue").where("title", .string(title)).groupBy("ownerId").count(), + "aggregates.titledOwners", .string(title))) + try await eventually("the titled aggregates") { + titled.resultType == .complete && owners.resultType == .complete + } + #expect(titled.data == .value(0)) + #expect(owners.data == .many([])) + let id = "swift-\(UUID().uuidString)" + let created = zero.mutate(E2EApp.create(.init(id: id, title: title, ownerId: "u2"))) + #expect(owners.data.json == [["ownerId": "u2", "count": 1]]) + #expect(titled.data == .value(0)) + #expect(try await created.server.value == .success(data: nil)) + try await eventually("the server's count") { titled.data == .value(1) } + #expect(owners.data.json == [["ownerId": "u2", "count": 1]]) + // Closed, as the other tests leave theirs, so the fixture's open issues + // stay the ones `WalkingSkeletonTests` expects. + #expect(try await zero.mutate(E2EApp.close(id)).server.value == .success(data: nil)) + } +} From d346eecd35a5416ec5ad59dab5a673580acd2ec8 Mon Sep 17 00:00:00 2001 From: Amp Date: Mon, 2 Nov 2026 16:35:48 +0000 Subject: [PATCH 2/3] zero-swift: port upstream's aggregate client tests, and rebase only for mutations from before a launch Ports zero-client's aggregate-read-your-writes, group-read-your-writes, crud-impl, custom, context, ivm-branch, keys and zero-poke-handler tests of synced aggregates as JS-generated client scenarios (and an `aggregate-row-key` vector), so Swift replays what JS does: read-your-writes in both the optimistic and the rebase run, a distinct's new and removed values, groupBy sum and avg creating a group, an orderBy-reordered group key, an edit inside a group the client lacks, JSON path sums, null correlations, row counts, junction aggregates, and source release. Three scenarios showed Swift moving a synced group JS doesn't: the rebase Swift runs when an aggregate first registers (standing in for the writes JS persists for a pending mutation across a relaunch) also ran for mutations made since launch, after the server dropped the query, or when a mutator's read was the only reader. It now runs only while a mutation replayed at launch is pending. Co-authored-by: tmm Amp-Thread-ID: https://ampcode.com/threads/T-01a19a37-5aa9-7256-bff5-cdc47c01a1fe --- .changeset/swift-synced-aggregates.md | 2 +- packages/zero-conformance/src/client/app.ts | 128 +- .../zero-conformance/src/client/scenarios.ts | 6 +- .../src/client/scenarios/aggregates.ts | 502 +++++ .../src/primitives/keys.test.ts | 68 +- .../vectors/aggregate-row-key.json | 1796 +++++++++++++++++ packages/zero-conformance/vectors/client.json | 19 + swift/Sources/Zero/Client/Engine.swift | 14 +- swift/Sources/Zero/Client/IVMBranch.swift | 3 +- swift/Tests/ConformanceTests/ClientApp.swift | 94 +- .../PrimitiveConformanceTests.swift | 13 + 11 files changed, 2602 insertions(+), 43 deletions(-) create mode 100644 packages/zero-conformance/vectors/aggregate-row-key.json diff --git a/.changeset/swift-synced-aggregates.md b/.changeset/swift-synced-aggregates.md index d9bf653e45..c1340dbb60 100644 --- a/.changeset/swift-synced-aggregates.md +++ b/.changeset/swift-synced-aggregates.md @@ -2,4 +2,4 @@ 'zero-swift': patch --- -Aggregates, `distinct()` and `groupBy()` sync from zero-cache: a named query's view reads the rows the server computes, stored under `a/`, instead of dropping them from pokes. Until the server answers, a view computes nothing and shows the empty value (`0` for a count). A local mutation moves a synced relationship aggregate or grouped count at once, as the JS client's optimistic deltas do, and the server's rows replace them when it confirms. A mutator's `tx.run` reads the synced rows for a query the server has answered, and computes them otherwise. Pending mutations are rebased when a synced aggregate's query first materializes after launch, so a relaunched client keeps their moves. +Aggregates, `distinct()` and `groupBy()` sync from zero-cache: a named query's view reads the rows the server computes, stored under `a/`, instead of dropping them from pokes. Until the server answers, a view computes nothing and shows the empty value (`0` for a count). A local mutation moves a synced relationship aggregate or grouped count at once, as the JS client's optimistic deltas do, and the server's rows replace them when it confirms. A mutator's `tx.run` reads the synced rows for a query the server has answered, and computes them otherwise. While mutations made before a relaunch are pending, they are rebased when a synced aggregate's query first materializes, so the relaunched client keeps their moves. diff --git a/packages/zero-conformance/src/client/app.ts b/packages/zero-conformance/src/client/app.ts index c12253cc22..02ac4179fd 100644 --- a/packages/zero-conformance/src/client/app.ts +++ b/packages/zero-conformance/src/client/app.ts @@ -83,6 +83,66 @@ export const queries = defineQueries({ timeByAuthor: defineQuery(() => zql.comment.groupBy('authorId').sum('createdAt'), ), + // From zero-client's aggregate-read-your-writes, group-read-your-writes, + // context, crud-impl and custom tests. + issueWithCommentCount: defineQuery(({args}: {args: string}) => + zql.issue + .where('id', args) + .related('comments', q => q.count()) + .one(), + ), + openByState: defineQuery(() => + zql.issue.where('closed', false).groupBy('closed').count(), + ), + issueStates: defineQuery(() => zql.issue.distinct('closed')), + issueStateCount: defineQuery(() => zql.issue.distinct('closed').count()), + countByState: defineQuery(() => zql.issue.groupBy('closed').count()), + timeByState: defineQuery(() => + zql.issue.groupBy('closed').sum('createdAt'), + ), + avgTimeByState: defineQuery(() => + zql.issue.groupBy('closed').avg('createdAt'), + ), + issuesByOwner: defineQuery(() => + zql.issue.groupBy('closed', 'ownerId').count().orderBy('ownerId', 'desc'), + ), + latestIssueTime: defineQuery(() => zql.issue.max('createdAt')), + commentAndLabelCounts: defineQuery(() => + zql.issue + .related('comments', q => q.count()) + .related('labels', q => q.count()) + .orderBy('id', 'asc'), + ), + commentTimeSums: defineQuery(() => + zql.issue + .related('comments', q => q.sum('createdAt')) + .orderBy('id', 'asc'), + ), + userIssueCounts: defineQuery(() => + zql.user.related('issues', q => q.count()).orderBy('id', 'asc'), + ), + // `points` isn't in the metadata's declared type, which only the + // builder's types check. + pointsByName: defineQuery(() => + zql.user + .groupBy('name') + // oxlint-disable-next-line @typescript-eslint/no-explicit-any + .sum(({json}) => (json as any)('metadata', 'points')), + ), + avgPointsByName: defineQuery(() => + zql.user + .groupBy('name') + // oxlint-disable-next-line @typescript-eslint/no-explicit-any + .avg(({json}) => (json as any)('metadata', 'points')), + ), + labelMax: defineQuery(() => + zql.issue.related('labels', q => q.max('name')).orderBy('id', 'asc'), + ), + bugLabelCounts: defineQuery(() => + zql.issue + .related('labels', q => q.where('name', 'bug').count()) + .orderBy('id', 'asc'), + ), }, // A table with a compound primary key. issueLabels: { @@ -201,33 +261,59 @@ const harden = { }), }; -/** - * Runs `ops` (CRUD operations, as `harden.ops` does), then each of the named - * `queries` through the transaction, and returns what they read: a query the - * server has answered reads its synced aggregates, any other computes them. - */ +type QueryRef = {name: string; args?: ReadonlyJSONValue}; + +/** What each of `refs` reads through `tx`, as JSON. */ +async function readAll(tx: Tx, refs: QueryRef[]): Promise { + const out: ReadonlyJSONValue[] = []; + for (const {name, args: queryArgs} of refs) { + let v: unknown = queries; + for (const part of name.split('.')) { + v = (v as Record)[part]; + } + const request = (v as (...a: unknown[]) => unknown)( + ...(queryArgs === undefined ? [] : [queryArgs]), + ); + // oxlint-disable-next-line @typescript-eslint/no-explicit-any + const result = await tx.run(addContextToQuery(request as any, undefined)); + out.push(JSON.parse(JSON.stringify(result ?? null))); + } + return out; +} + const aggregates = { + /** + * Runs `ops` (CRUD operations, as `harden.ops` does), then each of the named + * `queries` through the transaction, and returns what they read: a query the + * server has answered reads its synced aggregates, any other computes them. + */ read: defineMutator(async ({tx, args}: {tx: Tx; args: JSONObject}) => { for (const o of (args['ops'] ?? []) as CRUDOp[]) { await tx.mutate[o.table][o.op](o.value); } - const out: ReadonlyJSONValue[] = []; - for (const {name, args: queryArgs} of (args['queries'] ?? []) as { - name: string; - args?: ReadonlyJSONValue; - }[]) { - let v: unknown = queries; - for (const part of name.split('.')) { - v = (v as Record)[part]; - } - const request = (v as (...a: unknown[]) => unknown)( - ...(queryArgs === undefined ? [] : [queryArgs]), - ); - // oxlint-disable-next-line @typescript-eslint/no-explicit-any - const result = await tx.run(addContextToQuery(request as any, undefined)); - out.push(JSON.parse(JSON.stringify(result ?? null))); + return readAll(tx, (args['queries'] ?? []) as QueryRef[]); + }), + /** + * Reads the `queries`, runs `ops`, and reads them again; returns both + * reads. With `record`, it also upserts the user `record` with the + * transaction's reason as its name and the reads as its metadata, so a + * view of the users shows what the latest run, a rebase too, read. + */ + record: defineMutator(async ({tx, args}: {tx: Tx; args: JSONObject}) => { + const refs = (args['queries'] ?? []) as QueryRef[]; + const before = await readAll(tx, refs); + for (const o of (args['ops'] ?? []) as CRUDOp[]) { + await tx.mutate[o.table][o.op](o.value); + } + const after = await readAll(tx, refs); + if (typeof args['record'] === 'string') { + await tx.mutate.user.upsert({ + id: args['record'], + name: tx.reason, + metadata: {before, after}, + }); } - return out; + return {before, after}; }), }; diff --git a/packages/zero-conformance/src/client/scenarios.ts b/packages/zero-conformance/src/client/scenarios.ts index eae8e6c526..7f0dea44c6 100644 --- a/packages/zero-conformance/src/client/scenarios.ts +++ b/packages/zero-conformance/src/client/scenarios.ts @@ -1,5 +1,8 @@ import type {Scenario} from './harness.ts'; -import {aggregateScenarios} from './scenarios/aggregates.ts'; +import { + aggregateScenarios, + upstreamAggregateScenarios, +} from './scenarios/aggregates.ts'; import {connectionScenarios} from './scenarios/connection.ts'; import {errorScenarios} from './scenarios/errors.ts'; import {mutationScenarios} from './scenarios/mutations.ts'; @@ -14,6 +17,7 @@ export const scenarios: Scenario[] = [ ...pokeScenarios, ...queryScenarios, ...aggregateScenarios, + ...upstreamAggregateScenarios, ...mutationScenarios, ...persistenceScenarios, ...visibilityScenarios, diff --git a/packages/zero-conformance/src/client/scenarios/aggregates.ts b/packages/zero-conformance/src/client/scenarios/aggregates.ts index 1da233a0c4..377288bb07 100644 --- a/packages/zero-conformance/src/client/scenarios/aggregates.ts +++ b/packages/zero-conformance/src/client/scenarios/aggregates.ts @@ -11,13 +11,16 @@ import { advance, comment, connected, + del, gotDel, issue, mutate, poke, + put, queryHash, start, syncPoke, + user, } from './helpers.ts'; const data: ServerData = { @@ -365,3 +368,502 @@ export const aggregateScenarios: Scenario[] = [ ], }, ]; + +type QueryRef = {name: string; args?: ReadonlyJSONValue}; + +/** + * Materializes `refs` as views `v0`, `v1`, ..., and the users as `users` + * (where `aggregates.record` writes what each run read), connects, and + * syncs the queries' rows over `over` in one poke, with `extra` rows. + */ +function syncedViews( + refs: QueryRef[], + over: ServerData, + extra: ReadonlyJSONValue[] = [], +): Step[] { + return [ + start, + ...refs.map((r, i): Step => ({ + op: 'materialize', + view: `v${i}`, + query: r.name, + ...(r.args === undefined ? {} : {args: r.args}), + })), + {op: 'materialize', view: 'users', query: 'users.all'}, + connected, + advance(10), + ...syncPoke( + 'p1', + null, + '01', + refs.map(r => queryHash(r.name, r.args)), + [ + ...refs.flatMap(r => serverRowsPatch(r.name, r.args, undefined, over)), + ...extra, + ], + ), + ]; +} + +/** The rows the server moves for `refs` from `before` to `after`. */ +const moved = ( + refs: QueryRef[], + before: ServerData, + after: ServerData, + version: string, +) => refs.flatMap(r => serverRowsPatch(r.name, r.args, before, after, version)); + +/** + * `aggregates.record`: reads `refs`, runs `o`, reads them again, and records + * both reads, and the reason of the run, in the user `record`. + */ +const record = ( + mutation: string, + refs: QueryRef[], + o: {op: string; table: string; value: ReadonlyJSONValue}[], + rec = mutation, +) => + mutate(mutation, 'aggregates.record', { + queries: refs, + ops: o, + record: rec, + }); + +const insertIssue = ( + id: string, + fields: {closed?: boolean; ownerId?: string | null; createdAt?: number}, +) => ({ + op: 'insert', + table: 'issue', + value: { + id, + title: id, + description: '', + closed: fields.closed ?? false, + ownerId: fields.ownerId ?? null, + createdAt: fields.createdAt ?? 1, + }, +}); + +const users: ServerData = { + users: [user('u1', 'Alice'), user('u2', 'Bob')], + issues: [ + issue('i1', {ownerId: 'u1'}), + issue('i2'), + issue('i3', {ownerId: 'u1', closed: true}), + ], +}; + +const points: ServerData = { + users: [ + user('u1', 'A', {points: 5}), + // A string leaf, another key, and no metadata contribute nothing. + user('u2', 'A', {points: '7'}), + user('u3', 'B', {other: 1}), + user('u4', 'C', null), + ], +}; + +const commentCount: QueryRef = { + name: 'aggregates.issueWithCommentCount', + args: 'i1', +}; +const openByState: QueryRef = {name: 'aggregates.openByState'}; +const issueStates: QueryRef = {name: 'aggregates.issueStates'}; +const timeByState: QueryRef = {name: 'aggregates.timeByState'}; +const avgTimeByState: QueryRef = {name: 'aggregates.avgTimeByState'}; + +/** + * Ports of zero-client's tests of synced aggregates + * (aggregate-read-your-writes, group-read-your-writes, crud-impl, custom, + * context, zero-poke-handler): each names the test it comes from. + */ +export const upstreamAggregateScenarios: Scenario[] = [ + ...(['optimistic', 'rebase'] as const).map((reason): Scenario => ({ + // aggregate-read-your-writes: 'a custom mutator reads its optimistic + // aggregate write during %s'. + name: `aggregate: a mutator reads its optimistic relationship count during ${reason}`, + steps: [ + // Only the count is synced, not the comments it counts. + ...syncedViews([commentCount], data), + record( + 'm1', + [commentCount], + [ + { + op: 'insert', + table: 'comment', + value: { + id: 'c9', + authorId: 'u1', + issueId: 'i1', + text: '', + createdAt: 1, + }, + }, + ], + ), + advance(10), + ...(reason === 'rebase' + ? // The server counts more comments without the pending one: the + // mutation is replayed over the new count. + poke('p2', '01', '02', { + rowsPatch: moved( + [commentCount], + data, + plus( + 'comments', + comment('c5', 'i1'), + comment('c6', 'i1'), + comment('c7', 'i1'), + ), + '02', + ), + }) + : []), + advance(10), + ], + })), + ...(['optimistic', 'rebase'] as const).map((reason): Scenario => ({ + // group-read-your-writes: 'a mutator reads its own writes in a synced + // groupBy during %s'. + name: `aggregate: a mutator reads its own writes in a synced groupBy during ${reason}`, + steps: [ + // Only the groups are synced, not the issues they count. + ...syncedViews([openByState], data), + // Only the open issues are counted, so a closed one moves nothing. + record( + 'm1', + [openByState], + [insertIssue('i9', {}), insertIssue('i10', {closed: true})], + ), + advance(10), + ...(reason === 'rebase' + ? poke('p2', '01', '02', { + rowsPatch: moved( + [openByState], + data, + plus('issues', issue('i4'), issue('i5'), issue('i6')), + '02', + ), + }) + : []), + advance(10), + ], + })), + { + // group-read-your-writes: 'a mutator reads its new and removed values + // in a synced distinct'. + name: 'aggregate: a mutator reads its new and removed values in a synced distinct', + steps: [ + // The open value has one issue, i1, which the client also has. + ...syncedViews([issueStates], {issues: [issue('i1')]}, [ + put('issues', issue('i1')), + ]), + record('m1', [issueStates], [insertIssue('i9', {closed: true})]), + record( + 'm2', + [issueStates], + [{op: 'delete', table: 'issue', value: {id: 'i1'}}], + ), + advance(10), + ], + }, + ...(['sum', 'avg'] as const).map((fn): Scenario => ({ + // group-read-your-writes: 'a mutator reads its own writes in a synced + // groupBy().%s()'. + name: `aggregate: a mutator reads its own writes in a synced groupBy().${fn}()`, + steps: [ + // Two open issues whose times add up to 3. + ...syncedViews([fn === 'sum' ? timeByState : avgTimeByState], { + issues: [issue('i1', {createdAt: 1}), issue('i2', {createdAt: 2})], + }), + // The first row of the closed group, which isn't synced, adds it. + record( + 'm1', + [fn === 'sum' ? timeByState : avgTimeByState], + [ + insertIssue('i9', {createdAt: 7}), + insertIssue('i10', {closed: true, createdAt: 4}), + ], + ), + advance(10), + ], + })), + { + // group-read-your-writes: 'an optimistic count moves the synced group an + // orderBy reorders'. + name: 'aggregate: an optimistic count moves the synced group an orderBy reorders', + steps: [ + // Ordered by owner first: the server keys a group [owner, closed]. + ...syncedViews([{name: 'aggregates.issuesByOwner'}], { + issues: [issue('i1', {ownerId: 'u1'}), issue('i2', {ownerId: 'u1'})], + }), + mutate('m1', 'issue.create', {id: 'i9', ownerId: 'u1'}), + advance(10), + ], + }, + { + // group-read-your-writes: 'an edit within a group the client lacks adds + // no group'; crud-impl: 'optimistic grouped sum: a group the client + // lacks only comes with a new row'. + name: 'aggregate: an edit within a group the client lacks adds no group, a new row does', + steps: [ + start, + {op: 'materialize', view: 'states', query: 'aggregates.issueStates'}, + {op: 'materialize', view: 'times', query: 'aggregates.timeByState'}, + connected, + advance(10), + // i1 is synced, by another query, before the server answers these, so + // its group isn't on the client. + ...poke('p1', null, '01', {rowsPatch: [put('issues', issue('i1'))]}), + advance(10), + mutate('m1', 'issue.update', {id: 'i1', title: 'renamed'}), + mutate('m2', 'issue.update', {id: 'i1', createdAt: 7}), + advance(10), + mutate('m3', 'issue.create', {id: 'i9', closed: true, createdAt: 4}), + advance(10), + ], + }, + { + // crud-impl: 'optimistic grouped sum: a row stored without its row count + // is never removed'. The closed group comes from an older server, without + // `_0_rows`. + name: 'aggregate: a grouped sum stored without its row count keeps its group when emptied', + steps: [ + ...syncedViews([], data, [ + ...serverRowsPatch(timeByState.name, undefined, undefined, data).map( + r => { + const row = r as {value: Record}; + const {['_0_rows']: _, ...value} = row.value; + return {...row, value} as ReadonlyJSONValue; + }, + ), + ...(data.issues ?? []).map(r => put('issues', r)), + ]), + {op: 'materialize', view: 'times', query: timeByState.name}, + ...poke('p2', '01', '02', { + gotQueriesPatch: [{op: 'put', hash: queryHash(timeByState.name)}], + }), + advance(10), + mutate('m1', 'issue.delete', 'i3'), + advance(10), + ], + }, + { + // crud-impl: 'optimistic count: no row for the parent', 'a child with a + // null correlation value has no parent', 'the aggregate row is keyed by + // its server column names' (owner_id). + name: 'aggregate: a child with no parent row, or a null correlation, moves no count', + steps: [ + ...syncedViews([{name: 'aggregates.userIssueCounts'}], users), + mutate('m1', 'issue.create', {id: 'i8', ownerId: null}), + mutate('m2', 'issue.create', {id: 'i9', ownerId: 'u2'}), + mutate('m3', 'issue.update', {id: 'i9', ownerId: null}), + mutate('m4', 'issue.create', {id: 'i10', ownerId: 'u7'}), + advance(10), + // The user the count had no row for arrives. + mutate('m5', 'aggregates.read', { + ops: [{op: 'insert', table: 'user', value: {id: 'u7', name: 'Gus'}}], + queries: [], + }), + advance(10), + ], + }, + ...(['pointsByName', 'avgPointsByName'] as const).map((name): Scenario => ({ + // crud-impl: 'optimistic sum over a JSON path: only the number leaf + // moves the sum', 'optimistic sum: null fields contribute 0', 'null + // over no contributors, 0 over a 0', 'optimistic avg: a null field + // contributes nothing', 'deleting the last contributor → null', + // 'optimistic grouped sum: a group comes with its first row and goes + // with its last'. + name: `aggregate: a grouped ${name === 'pointsByName' ? 'sum' : 'average'} of a JSON path moves only with number leaves`, + steps: [ + // The users are synced too, so editing and deleting them applies. + ...syncedViews( + [{name: `aggregates.${name}`}], + points, + (points.users ?? []).map(u => put('users', u)), + ), + ...( + [ + ['update', {id: 'u1', metadata: {points: 5, note: 'x'}}], + ['update', {id: 'u2', metadata: {points: 6}}], + ['insert', {id: 'u5', name: 'A', metadata: {points: 0}}], + ['delete', {id: 'u1'}], + ['insert', {id: 'u6', name: 'B', metadata: {points: 0}}], + ['delete', {id: 'u6'}], + ['delete', {id: 'u4'}], + ['insert', {id: 'u7', name: 'D', metadata: {points: 3}}], + ['insert', {id: 'u8', name: 'D', metadata: null}], + ] as const + ).map(([op, value], i) => + mutate(`m${i + 1}`, 'aggregates.read', { + ops: [{op, table: 'user', value}], + queries: [], + }), + ), + advance(10), + ], + })), + { + // context: 'synced junction (many-to-many) aggregate (sum) reads the + // server value', 'synced junction (many-to-many) count with a where + // reads the server value'. A junction's aggregate is the server's. + name: "aggregate: a junction max and a junction count with a where are the server's", + steps: [ + ...syncedViews( + [{name: 'aggregates.labelMax'}, {name: 'aggregates.bugLabelCounts'}], + data, + ), + ops('m1', [ + { + op: 'insert', + table: 'issueLabel', + value: {issueId: 'i2', labelId: 'l1'}, + }, + ]), + advance(10), + ...poke('p2', '01', '02', { + lastMutationIDChanges: {$clientID: 1}, + rowsPatch: moved( + [{name: 'aggregates.labelMax'}, {name: 'aggregates.bugLabelCounts'}], + data, + plus('issueLabel', {issueId: 'i2', labelId: 'l1'}), + '02', + ), + }), + advance(10), + ], + }, + { + // custom: 'custom mutators compute aggregates from the rows they can + // read': a top-level aggregate, a distinct, a groupBy and a distinct + // reading the mutator's own writes, a relationship aggregate. + name: 'aggregate: a mutator computes aggregates the server has not sent from its own writes', + steps: [ + start, + connected, + advance(10), + mutate('m1', 'aggregates.record', { + queries: [ + 'issueCount', + 'latestIssueTime', + 'openIssueCount', + 'issueStates', + 'issueStateCount', + 'countByState', + 'timeByState', + 'commentAndLabelCounts', + 'commentTimeSums', + ].map(n => ({name: `aggregates.${n}`})), + ops: [ + insertIssue('1', {}), + insertIssue('2', {closed: true, createdAt: 5}), + insertIssue('3', {createdAt: 2}), + ...[ + ['c1', 2], + ['c2', 3], + ].map(([id, createdAt]) => ({ + op: 'insert', + table: 'comment', + value: {id, authorId: 'u1', issueId: '1', text: '', createdAt}, + })), + {op: 'insert', table: 'label', value: {id: 'l1', name: 'bug'}}, + { + op: 'insert', + table: 'issueLabel', + value: {issueId: '1', labelId: 'l1'}, + }, + // An edge to a label that isn't there doesn't count. + { + op: 'insert', + table: 'issueLabel', + value: {issueId: '2', labelId: 'l2'}, + }, + ], + }), + advance(10), + ], + }, + { + // ivm-branch: 'advance releases an aggregate source the server empties + // once no view reads it'. A grouped query's registration, left behind, + // would make a new row add a group nothing synced. + name: 'aggregate: once the server drops a groupBy, a new row adds no group', + steps: [ + ...syncedViews([{name: 'aggregates.countByState'}], data), + {op: 'destroy', view: 'v0'}, + advance(10), + ...poke('p2', '01', '02', { + gotQueriesPatch: [gotDel(queryHash('aggregates.countByState'))], + rowsPatch: serverRowsPatch( + 'aggregates.countByState', + undefined, + data, + {}, + ), + }), + mutate('m1', 'issue.create', {id: 'i9', closed: true}), + advance(10), + {op: 'materialize', view: 'w', query: 'aggregates.countByState'}, + advance(10), + ], + }, + { + // ivm-branch: 'only the main branch registers optimistic aggregates'. A + // mutator reads a synced groupBy that no view reads and that has no + // rows, so its source exists only in the mutator's fork. + name: "aggregate: a mutator's read of a synced groupBy registers nothing", + steps: [ + ...syncedViews([{name: 'aggregates.countByState'}], {}), + {op: 'destroy', view: 'v0'}, + advance(10), + ops('m1', [], [{name: 'aggregates.countByState'}]), + mutate('m2', 'issue.create', {id: 'i9', closed: true}), + advance(10), + {op: 'materialize', view: 'w', query: 'aggregates.countByState'}, + advance(10), + ], + }, + { + // A mutation made after a restart, before any view of the synced + // groupBy registers it, moves nothing until the next rebase. + name: 'aggregate: after a restart, a mutation made before the view moves its group at the next rebase', + steps: [ + ...syncedViews([{name: 'aggregates.countByState'}], data), + advance(2000), + {op: 'restart'}, + mutate('m1', 'issue.create', {id: 'i9', closed: true}), + advance(10), + {op: 'materialize', view: 'w', query: 'aggregates.countByState'}, + start, + connected, + // A poke that confirms nothing replays the pending mutation. + ...poke('p2', '01', '02', {rowsPatch: [put('issues', issue('i8'))]}), + advance(10), + ], + }, + { + // zero-poke-handler: 'mergePokes routes synced top-level aggregate rows + // (not dropped)', 'mergePokes routes synced relationship aggregate rows'. + name: 'aggregate: pokes put and delete aggregate rows, and drop a table not in the schema', + steps: [ + ...syncedViews( + [{name: 'aggregates.issueCount'}, {name: 'aggregates.commentCounts'}], + data, + [put('notInSchema', {id: 'x'})], + ), + advance(10), + ...poke('p2', '01', '02', { + rowsPatch: [ + del(`aggregate:${queryHash('aggregates.issueCount')}`, {_0_key: 0}), + del(`aggregate:${queryHash('aggregates.commentCounts')}:comments`, { + ['issue_id']: 'i1', + }), + ], + }), + advance(10), + ], + }, +]; diff --git a/packages/zero-conformance/src/primitives/keys.test.ts b/packages/zero-conformance/src/primitives/keys.test.ts index 0d636f7499..19db6bdd68 100644 --- a/packages/zero-conformance/src/primitives/keys.test.ts +++ b/packages/zero-conformance/src/primitives/keys.test.ts @@ -1,5 +1,9 @@ import {test} from 'vitest'; -import {toPrimaryKeyString} from '../../../zero-client/src/client/keys.ts'; +import { + aggregateRowKey, + aggregateRowKeyColumns, + toPrimaryKeyString, +} from '../../../zero-client/src/client/keys.ts'; import type {CompoundKey} from '../../../zero-protocol/src/ast.ts'; import type {Row} from '../../../zero-protocol/src/data.ts'; import {interestingStrings, Random} from '../random.ts'; @@ -47,3 +51,65 @@ test('primary-key-string', () => { })), ); }); + +test('aggregate-row-key', () => { + const r = new Random(0x616767); + const values = [...interestingStrings, 0, -0, 1, 1.5, 2 ** 53, true, false]; + const payload = () => + r.pick([ + {_0_value: r.pick([0, 3, null])}, + {_0_value: 1.5, _0_sum: 3, _0_count: 2, _0_rows: 2}, + {_0_value: null, _0_sum: 0, _0_count: 0}, + ]); + const cases: {table: string; row: Row}[] = []; + for (let i = 0; i < 60; i++) { + // A top-level aggregate's and a grouped query's rows, keyed by `_0_key` + // whatever else they carry. + cases.push({ + table: r.pick(['aggregate:q1', 'aggregate:q1:#group', 'aggregate:#']), + row: { + _0_key: r.pick(values), + ...(r.pick([true, false]) ? {closed: r.pick(values)} : {}), + ...(r.pick([true, false]) ? {_0_version: '01'} : {}), + ...payload(), + }, + }); + // A relationship aggregate's, keyed by its correlation columns, sorted, + // even one named like the synthetic key; never by the row version. + cases.push({ + table: r.pick(['aggregate:q1:comments', 'aggregate:q2:labels']), + row: { + ...(r.pick([true, false]) + ? {issueId: r.pick(values)} + : {b: r.pick(values), a: r.pick(values)}), + ...(r.pick([true, false]) ? {_0_key: r.pick(values)} : {}), + ...(r.pick([true, false]) ? {_0_version: '02'} : {}), + ...payload(), + }, + }); + } + // A key value that isn't a string, number or boolean. + cases.push({table: 'aggregate:q1', row: {_0_key: null, _0_value: 1}}); + cases.push({ + table: 'aggregate:q1:comments', + row: {issueId: null, _0_value: 1}, + }); + emitVectors( + 'aggregate-row-key', + 'aggregate-row-key', + 'aggregateRowKeyColumns(table, row) and aggregateRowKey(table, row): the `a/` storage key of a synced aggregate row; `throws` when a key value is invalid.', + cases.map(c => { + let key: string | undefined; + try { + key = aggregateRowKey(c.table, c.row); + } catch { + key = undefined; + } + return { + ...c, + columns: aggregateRowKeyColumns(c.table, c.row), + ...(key === undefined ? {throws: true} : {key}), + }; + }), + ); +}); diff --git a/packages/zero-conformance/vectors/aggregate-row-key.json b/packages/zero-conformance/vectors/aggregate-row-key.json new file mode 100644 index 0000000000..926bb9c7ca --- /dev/null +++ b/packages/zero-conformance/vectors/aggregate-row-key.json @@ -0,0 +1,1796 @@ +{ + "formatVersion": 1, + "kind": "aggregate-row-key", + "description": "aggregateRowKeyColumns(table, row) and aggregateRowKey(table, row): the `a/` storage key of a synced aggregate row; `throws` when a key value is invalid.", + "cases": [ + { + "table": "aggregate:q1", + "row": { + "_0_key": true, + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/true" + }, + { + "table": "aggregate:q2:labels", + "row": { + "b": "😀", + "a": " ", + "_0_key": "ı", + "_0_version": "02", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key", + "a", + "b" + ], + "key": "a/q2:labels/156631047782885871426998179746928191943" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": "abc", + "closed": "𝒜", + "_0_version": "01", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/abc" + }, + { + "table": "aggregate:q1:comments", + "row": { + "issueId": "中文", + "_0_key": "😀", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key", + "issueId" + ], + "key": "a/q1:comments/101718917366446299477895636544490698238" + }, + { + "table": "aggregate:#", + "row": { + "_0_key": "Ω", + "closed": "𝒜", + "_0_version": "01", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key" + ], + "key": "a/#/Ω" + }, + { + "table": "aggregate:q1:comments", + "row": { + "b": "\u001f", + "a": "A", + "_0_version": "02", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "a", + "b" + ], + "key": "a/q1:comments/253494598612829295466353012358671237038" + }, + { + "table": "aggregate:q1:#group", + "row": { + "_0_key": " ", + "_0_value": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1:#group/ " + }, + { + "table": "aggregate:q2:labels", + "row": { + "issueId": "\\", + "_0_key": "z", + "_0_version": "02", + "_0_value": 3 + }, + "columns": [ + "_0_key", + "issueId" + ], + "key": "a/q2:labels/275359418673279422273815927308651637405" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": "ω", + "closed": "ı", + "_0_value": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/ω" + }, + { + "table": "aggregate:q2:labels", + "row": { + "b": "ı", + "a": "\"", + "_0_key": "ω", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key", + "a", + "b" + ], + "key": "a/q2:labels/259082913063992690510303315935456243085" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": "b", + "closed": 0, + "_0_value": 3 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/b" + }, + { + "table": "aggregate:q2:labels", + "row": { + "b": "𝒜", + "a": "a", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "a", + "b" + ], + "key": "a/q2:labels/107325452672446167370544837745691598846" + }, + { + "table": "aggregate:q1:#group", + "row": { + "_0_key": "�", + "closed": "ß", + "_0_version": "01", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1:#group/�" + }, + { + "table": "aggregate:q1:comments", + "row": { + "b": "中文", + "a": "\\", + "_0_version": "02", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "a", + "b" + ], + "key": "a/q1:comments/330497054020412877977965114737753886598" + }, + { + "table": "aggregate:q1:#group", + "row": { + "_0_key": "9", + "_0_version": "01", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1:#group/9" + }, + { + "table": "aggregate:q1:comments", + "row": { + "issueId": "é", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "issueId" + ], + "key": "a/q1:comments/é" + }, + { + "table": "aggregate:#", + "row": { + "_0_key": 1.5, + "closed": "�", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key" + ], + "key": "a/#/1.5" + }, + { + "table": "aggregate:q2:labels", + "row": { + "issueId": "Ω", + "_0_value": null + }, + "columns": [ + "issueId" + ], + "key": "a/q2:labels/Ω" + }, + { + "table": "aggregate:#", + "row": { + "_0_key": "ab", + "closed": 0, + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key" + ], + "key": "a/#/ab" + }, + { + "table": "aggregate:q2:labels", + "row": { + "issueId": 1, + "_0_key": "b", + "_0_version": "02", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key", + "issueId" + ], + "key": "a/q2:labels/131287170940107068189833748638085139399" + }, + { + "table": "aggregate:#", + "row": { + "_0_key": "é", + "closed": "�", + "_0_version": "01", + "_0_value": null + }, + "columns": [ + "_0_key" + ], + "key": "a/#/é" + }, + { + "table": "aggregate:q2:labels", + "row": { + "issueId": "Ω", + "_0_key": "￿", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key", + "issueId" + ], + "key": "a/q2:labels/241057040618309218168109349550314558222" + }, + { + "table": "aggregate:#", + "row": { + "_0_key": "😀a", + "_0_version": "01", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/#/😀a" + }, + { + "table": "aggregate:q1:comments", + "row": { + "issueId": "ß", + "_0_key": " ", + "_0_version": "02", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key", + "issueId" + ], + "key": "a/q1:comments/311087864027331280325584174532034131791" + }, + { + "table": "aggregate:#", + "row": { + "_0_key": "ff", + "_0_version": "01", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/#/ff" + }, + { + "table": "aggregate:q1:comments", + "row": { + "b": "ω", + "a": "\n", + "_0_key": "é", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key", + "a", + "b" + ], + "key": "a/q1:comments/170852574939168841201845766629266513274" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": "é", + "closed": 0, + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/é" + }, + { + "table": "aggregate:q2:labels", + "row": { + "issueId": " ", + "_0_key": "\\", + "_0_version": "02", + "_0_value": 3 + }, + "columns": [ + "_0_key", + "issueId" + ], + "key": "a/q2:labels/217952664778456665839337002188719679975" + }, + { + "table": "aggregate:#", + "row": { + "_0_key": "\u0000", + "_0_value": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/#/\u0000" + }, + { + "table": "aggregate:q2:labels", + "row": { + "issueId": "�", + "_0_key": "ß", + "_0_version": "02", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key", + "issueId" + ], + "key": "a/q2:labels/211464393569957171780078204392551827881" + }, + { + "table": "aggregate:q1:#group", + "row": { + "_0_key": "￿", + "closed": "😀", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1:#group/￿" + }, + { + "table": "aggregate:q1:comments", + "row": { + "issueId": "😀", + "_0_version": "02", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "issueId" + ], + "key": "a/q1:comments/😀" + }, + { + "table": "aggregate:#", + "row": { + "_0_key": "a😀", + "closed": 0, + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/#/a😀" + }, + { + "table": "aggregate:q2:labels", + "row": { + "b": "0", + "a": "A", + "_0_key": "b", + "_0_version": "02", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key", + "a", + "b" + ], + "key": "a/q2:labels/297949515111589737440908332210213489346" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": "Z", + "closed": 1.5, + "_0_version": "01", + "_0_value": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/Z" + }, + { + "table": "aggregate:q2:labels", + "row": { + "b": "0", + "a": 0, + "_0_key": "😀a", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key", + "a", + "b" + ], + "key": "a/q2:labels/193428358300156941902051175876813588225" + }, + { + "table": "aggregate:#", + "row": { + "_0_key": true, + "_0_version": "01", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/#/true" + }, + { + "table": "aggregate:q1:comments", + "row": { + "b": false, + "a": "�", + "_0_key": "z", + "_0_value": null + }, + "columns": [ + "_0_key", + "a", + "b" + ], + "key": "a/q1:comments/74336746898964573246397375360765557933" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": "Ω", + "closed": "\u001f", + "_0_value": null + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/Ω" + }, + { + "table": "aggregate:q2:labels", + "row": { + "issueId": "a", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "issueId" + ], + "key": "a/q2:labels/a" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": false, + "closed": true, + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/false" + }, + { + "table": "aggregate:q1:comments", + "row": { + "b": "ff", + "a": "\u001f", + "_0_key": true, + "_0_value": 3 + }, + "columns": [ + "_0_key", + "a", + "b" + ], + "key": "a/q1:comments/12342883190522700845073940521368606531" + }, + { + "table": "aggregate:#", + "row": { + "_0_key": "\"", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key" + ], + "key": "a/#/\"" + }, + { + "table": "aggregate:q1:comments", + "row": { + "issueId": "ff", + "_0_version": "02", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "issueId" + ], + "key": "a/q1:comments/ff" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": "ı", + "closed": "\"", + "_0_value": 3 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/ı" + }, + { + "table": "aggregate:q1:comments", + "row": { + "b": "a", + "a": "�", + "_0_version": "02", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "a", + "b" + ], + "key": "a/q1:comments/187447120347154819913647007327752975575" + }, + { + "table": "aggregate:#", + "row": { + "_0_key": "b", + "_0_version": "01", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/#/b" + }, + { + "table": "aggregate:q1:comments", + "row": { + "issueId": false, + "_0_key": "𝒜", + "_0_version": "02", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key", + "issueId" + ], + "key": "a/q1:comments/40975003784943063047585115121857130899" + }, + { + "table": "aggregate:#", + "row": { + "_0_key": "\u001f", + "closed": 1, + "_0_version": "01", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key" + ], + "key": "a/#/\u001f" + }, + { + "table": "aggregate:q1:comments", + "row": { + "issueId": 9007199254740992, + "_0_key": "a", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key", + "issueId" + ], + "key": "a/q1:comments/192798114354683292779073701397039243429" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": 1.5, + "closed": "😀", + "_0_version": "01", + "_0_value": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/1.5" + }, + { + "table": "aggregate:q2:labels", + "row": { + "b": "Z", + "a": "😀", + "_0_version": "02", + "_0_value": null + }, + "columns": [ + "a", + "b" + ], + "key": "a/q2:labels/162326200827063407909572723087875217268" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": "Ω", + "_0_value": null + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/Ω" + }, + { + "table": "aggregate:q2:labels", + "row": { + "b": "z", + "a": "A", + "_0_key": true, + "_0_version": "02", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key", + "a", + "b" + ], + "key": "a/q2:labels/139171651594264903868812938453589582903" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": "\u001f", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/\u001f" + }, + { + "table": "aggregate:q2:labels", + "row": { + "issueId": "􏿿", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "issueId" + ], + "key": "a/q2:labels/􏿿" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": "ab", + "_0_version": "01", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/ab" + }, + { + "table": "aggregate:q2:labels", + "row": { + "b": "a😀", + "a": "￿", + "_0_key": 0, + "_0_version": "02", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key", + "a", + "b" + ], + "key": "a/q2:labels/50876109455147000903841395024858976167" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": "é", + "_0_value": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/é" + }, + { + "table": "aggregate:q1:comments", + "row": { + "issueId": "b", + "_0_key": "Ω", + "_0_version": "02", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key", + "issueId" + ], + "key": "a/q1:comments/149324162463867099562130838562677612239" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": "ω", + "closed": "", + "_0_version": "01", + "_0_value": 3 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/ω" + }, + { + "table": "aggregate:q2:labels", + "row": { + "issueId": "é", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "issueId" + ], + "key": "a/q2:labels/é" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": "😀", + "closed": "ı", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/😀" + }, + { + "table": "aggregate:q2:labels", + "row": { + "issueId": "z", + "_0_key": "􏿿", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key", + "issueId" + ], + "key": "a/q2:labels/93491842394695852304698550219164132360" + }, + { + "table": "aggregate:q1:#group", + "row": { + "_0_key": "é", + "closed": "9", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1:#group/é" + }, + { + "table": "aggregate:q2:labels", + "row": { + "b": "ff", + "a": "Ω", + "_0_value": 0 + }, + "columns": [ + "a", + "b" + ], + "key": "a/q2:labels/36520884848527769869584295979815071932" + }, + { + "table": "aggregate:#", + "row": { + "_0_key": "Ω", + "closed": "z", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/#/Ω" + }, + { + "table": "aggregate:q2:labels", + "row": { + "b": "", + "a": "é", + "_0_key": "\u001f", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key", + "a", + "b" + ], + "key": "a/q2:labels/24800932752331141705543058892556376152" + }, + { + "table": "aggregate:#", + "row": { + "_0_key": "abc", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/#/abc" + }, + { + "table": "aggregate:q2:labels", + "row": { + "b": "😀a", + "a": "ω", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "a", + "b" + ], + "key": "a/q2:labels/84759063139452653896005669827304217644" + }, + { + "table": "aggregate:q1:#group", + "row": { + "_0_key": "9", + "closed": 0, + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1:#group/9" + }, + { + "table": "aggregate:q1:comments", + "row": { + "b": "\u0000", + "a": "a", + "_0_key": "9", + "_0_version": "02", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key", + "a", + "b" + ], + "key": "a/q1:comments/62550142395451932666061351421927599877" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": "A", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/A" + }, + { + "table": "aggregate:q1:comments", + "row": { + "issueId": "ß", + "_0_version": "02", + "_0_value": 3 + }, + "columns": [ + "issueId" + ], + "key": "a/q1:comments/ß" + }, + { + "table": "aggregate:#", + "row": { + "_0_key": 0, + "closed": "Z", + "_0_version": "01", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key" + ], + "key": "a/#/0" + }, + { + "table": "aggregate:q1:comments", + "row": { + "issueId": "😀", + "_0_version": "02", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "issueId" + ], + "key": "a/q1:comments/😀" + }, + { + "table": "aggregate:q1:#group", + "row": { + "_0_key": "z", + "closed": "\u0000", + "_0_version": "01", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1:#group/z" + }, + { + "table": "aggregate:q1:comments", + "row": { + "issueId": "􏿿", + "_0_key": "", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key", + "issueId" + ], + "key": "a/q1:comments/117548740108254688086540036149019764094" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": 1, + "closed": 9007199254740992, + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/1" + }, + { + "table": "aggregate:q2:labels", + "row": { + "b": "é", + "a": "Z", + "_0_value": 0 + }, + "columns": [ + "a", + "b" + ], + "key": "a/q2:labels/325466968069441688793335171179812968308" + }, + { + "table": "aggregate:q1:#group", + "row": { + "_0_key": "é", + "closed": "𝒜", + "_0_version": "01", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1:#group/é" + }, + { + "table": "aggregate:q1:comments", + "row": { + "issueId": "abc", + "_0_key": "😀a", + "_0_version": "02", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key", + "issueId" + ], + "key": "a/q1:comments/245677117039437240313871861748431845039" + }, + { + "table": "aggregate:#", + "row": { + "_0_key": "😀", + "closed": "z", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/#/😀" + }, + { + "table": "aggregate:q1:comments", + "row": { + "issueId": "😀a", + "_0_key": " ", + "_0_version": "02", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key", + "issueId" + ], + "key": "a/q1:comments/327083438832788622566427568356887504744" + }, + { + "table": "aggregate:#", + "row": { + "_0_key": "ß", + "_0_version": "01", + "_0_value": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/#/ß" + }, + { + "table": "aggregate:q2:labels", + "row": { + "issueId": "İ", + "_0_key": "0", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key", + "issueId" + ], + "key": "a/q2:labels/223171369741914826854501957862931939589" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": "9", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/9" + }, + { + "table": "aggregate:q1:comments", + "row": { + "issueId": "9", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "issueId" + ], + "key": "a/q1:comments/9" + }, + { + "table": "aggregate:#", + "row": { + "_0_key": "中文", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/#/中文" + }, + { + "table": "aggregate:q2:labels", + "row": { + "b": "􏿿", + "a": "\n", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "a", + "b" + ], + "key": "a/q2:labels/287413044363108328751638218724697824358" + }, + { + "table": "aggregate:q1:#group", + "row": { + "_0_key": "abc", + "closed": "z", + "_0_value": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1:#group/abc" + }, + { + "table": "aggregate:q1:comments", + "row": { + "issueId": 1, + "_0_version": "02", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "issueId" + ], + "key": "a/q1:comments/1" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": "Ω", + "closed": "𝒜", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/Ω" + }, + { + "table": "aggregate:q2:labels", + "row": { + "issueId": "中文", + "_0_key": "", + "_0_value": null + }, + "columns": [ + "_0_key", + "issueId" + ], + "key": "a/q2:labels/208855635852580089004030315336708308440" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": "￿", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/￿" + }, + { + "table": "aggregate:q2:labels", + "row": { + "issueId": "\u001f", + "_0_key": "A", + "_0_version": "02", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key", + "issueId" + ], + "key": "a/q2:labels/253494598612829295466353012358671237038" + }, + { + "table": "aggregate:#", + "row": { + "_0_key": "é", + "closed": " ", + "_0_version": "01", + "_0_value": null + }, + "columns": [ + "_0_key" + ], + "key": "a/#/é" + }, + { + "table": "aggregate:q2:labels", + "row": { + "b": "�", + "a": " ", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "a", + "b" + ], + "key": "a/q2:labels/17327414818598726598999821881078743270" + }, + { + "table": "aggregate:q1:#group", + "row": { + "_0_key": 0, + "closed": "0", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1:#group/0" + }, + { + "table": "aggregate:q2:labels", + "row": { + "issueId": "ab", + "_0_key": "é", + "_0_version": "02", + "_0_value": 0 + }, + "columns": [ + "_0_key", + "issueId" + ], + "key": "a/q2:labels/10452058293472187974925376530387777406" + }, + { + "table": "aggregate:q1:#group", + "row": { + "_0_key": "a", + "_0_version": "01", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1:#group/a" + }, + { + "table": "aggregate:q1:comments", + "row": { + "b": " ", + "a": 1, + "_0_key": "ω", + "_0_version": "02", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key", + "a", + "b" + ], + "key": "a/q1:comments/327840771041439189072094833307203068931" + }, + { + "table": "aggregate:q1:#group", + "row": { + "_0_key": 9007199254740992, + "_0_version": "01", + "_0_value": null + }, + "columns": [ + "_0_key" + ], + "key": "a/q1:#group/9007199254740992" + }, + { + "table": "aggregate:q1:comments", + "row": { + "b": 9007199254740992, + "a": "z", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "a", + "b" + ], + "key": "a/q1:comments/2500749764263746202473845560558549756" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": "é", + "closed": 9007199254740992, + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/é" + }, + { + "table": "aggregate:q1:comments", + "row": { + "b": "\n", + "a": "�", + "_0_key": "0", + "_0_version": "02", + "_0_value": null + }, + "columns": [ + "_0_key", + "a", + "b" + ], + "key": "a/q1:comments/140044415761150807955647765974736326780" + }, + { + "table": "aggregate:q1:#group", + "row": { + "_0_key": false, + "closed": "𝒜", + "_0_version": "01", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1:#group/false" + }, + { + "table": "aggregate:q1:comments", + "row": { + "b": 9007199254740992, + "a": "ab", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "a", + "b" + ], + "key": "a/q1:comments/217781012334280161020417414279952942549" + }, + { + "table": "aggregate:q1:#group", + "row": { + "_0_key": "ß", + "closed": 0, + "_0_version": "01", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1:#group/ß" + }, + { + "table": "aggregate:q2:labels", + "row": { + "b": "é", + "a": "9", + "_0_version": "02", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "a", + "b" + ], + "key": "a/q2:labels/7065857705056541004346072310487412216" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": "abc", + "_0_version": "01", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1/abc" + }, + { + "table": "aggregate:q1:comments", + "row": { + "issueId": "😀a", + "_0_key": "😀", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key", + "issueId" + ], + "key": "a/q1:comments/138237440500213278766544576420175538153" + }, + { + "table": "aggregate:#", + "row": { + "_0_key": "ı", + "closed": 0, + "_0_value": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/#/ı" + }, + { + "table": "aggregate:q2:labels", + "row": { + "b": "é", + "a": "中文", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "a", + "b" + ], + "key": "a/q2:labels/46942451689340533355549146697318881875" + }, + { + "table": "aggregate:q1:#group", + "row": { + "_0_key": "Ω", + "closed": "a", + "_0_version": "01", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1:#group/Ω" + }, + { + "table": "aggregate:q2:labels", + "row": { + "b": "😀a", + "a": "z", + "_0_key": "0", + "_0_value": 1.5, + "_0_sum": 3, + "_0_count": 2, + "_0_rows": 2 + }, + "columns": [ + "_0_key", + "a", + "b" + ], + "key": "a/q2:labels/281378494539073334830367030762091931482" + }, + { + "table": "aggregate:q1:#group", + "row": { + "_0_key": "中文", + "closed": "", + "_0_version": "01", + "_0_value": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/q1:#group/中文" + }, + { + "table": "aggregate:q1:comments", + "row": { + "issueId": "\"", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "issueId" + ], + "key": "a/q1:comments/\"" + }, + { + "table": "aggregate:#", + "row": { + "_0_key": "A", + "closed": "A", + "_0_version": "01", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key" + ], + "key": "a/#/A" + }, + { + "table": "aggregate:q1:comments", + "row": { + "b": "9", + "a": "a", + "_0_key": "b", + "_0_value": null, + "_0_sum": 0, + "_0_count": 0 + }, + "columns": [ + "_0_key", + "a", + "b" + ], + "key": "a/q1:comments/157500501030969852608456868797404635372" + }, + { + "table": "aggregate:q1", + "row": { + "_0_key": null, + "_0_value": 1 + }, + "columns": [ + "_0_key" + ], + "throws": true + }, + { + "table": "aggregate:q1:comments", + "row": { + "issueId": null, + "_0_value": 1 + }, + "columns": [ + "issueId" + ], + "throws": true + } + ] +} diff --git a/packages/zero-conformance/vectors/client.json b/packages/zero-conformance/vectors/client.json index 364f99a68c..4b9df08e2d 100644 --- a/packages/zero-conformance/vectors/client.json +++ b/packages/zero-conformance/vectors/client.json @@ -120,6 +120,25 @@ {"name":"aggregate: synced aggregate rows and pending moves survive a restart","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v","query":"aggregates.commentCounts"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr"}],"rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i1","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i2","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i3","_0_value":0,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"comment.add","args":{"id":"c5","issueId":"i2"}},{"op":"advance","ms":2000},{"op":"restart"},{"op":"materialize","view":"a","query":"aggregates.commentCounts"},{"op":"materialize","view":"b","query":"aggregates.issueCount"},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":2}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"comment.add","args":[{"id":"c5","issueId":"i2"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":3},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":3},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie","01"],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"activeClients":["$clientID"]}]}}],"closed":[0],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"a":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":3},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"cached","notifications":1}}},{"state":{"name":"connecting"},"views":{"a":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":3},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"cached","notifications":0},"b":{"data":0,"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"a":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":3},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"cached","notifications":0},"b":{"data":0,"resultType":"unknown","notifications":0}}}]}, {"name":"aggregate: once the server drops the query, a mutation no longer moves its rows","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v","query":"aggregates.commentCounts"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr"}],"rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i1","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i2","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i3","_0_value":0,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"destroy","view":"v"},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2","gotQueriesPatch":[{"op":"del","hash":"0u3s9wi0kzvflr"}],"rowsPatch":[{"op":"del","tableName":"issues","id":{"id":"i1"}},{"op":"del","tableName":"aggregate:0u3s9wi0kzvflr:comments","id":{"issue_id":"i1"}},{"op":"del","tableName":"issues","id":{"id":"i2"}},{"op":"del","tableName":"aggregate:0u3s9wi0kzvflr:comments","id":{"issue_id":"i2"}},{"op":"del","tableName":"issues","id":{"id":"i3"}},{"op":"del","tableName":"aggregate:0u3s9wi0kzvflr:comments","id":{"issue_id":"i3"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]},{"op":"mutate","mutation":"m1","mutator":"comment.add","args":{"id":"c5","issueId":"i1"}},{"op":"advance","ms":10},{"op":"materialize","view":"w","query":"aggregates.commentCounts"},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":2}}},{"state":{"name":"connected"}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"del","hash":"0u3s9wi0kzvflr"}]}]],"state":{"name":"connected"}},{"state":{"name":"connected"}},{"state":{"name":"connected"}},{"state":{"name":"connected"}},{"sent":[["push",{"timestamp":1700000000020,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000020,"id":1,"clientID":"$clientID","name":"comment.add","args":[{"id":"c5","issueId":"i1"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"w":{"data":[],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"w":{"data":[],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}}]}, {"name":"aggregate: a mutator reads a synced aggregate with its own writes, and computes one the server has not sent","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v","query":"aggregates.commentCounts"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr"}],"rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i1","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i2","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i3","_0_value":0,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"aggregates.read","args":{"ops":[{"op":"insert","table":"comment","value":{"id":"c5","authorId":"u1","issueId":"i1","text":"","createdAt":1}}],"queries":[{"name":"aggregates.commentCounts"},{"name":"aggregates.issueCount"},{"name":"aggregates.commentsByIssue"}]}},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":2}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"insert","table":"comment","value":{"id":"c5","authorId":"u1","issueId":"i1","text":"","createdAt":1}}],"queries":[{"name":"aggregates.commentCounts"},{"name":"aggregates.issueCount"},{"name":"aggregates.commentsByIssue"}]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":[[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],3,[{"issueId":"i1","count":1}]]},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":[[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],3,[{"issueId":"i1","count":1}]]},"server":"pending"}}}]}, +{"name":"aggregate: a mutator reads its optimistic relationship count during optimistic","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.issueWithCommentCount","args":"i1"},{"op":"materialize","view":"users","query":"users.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"1martcw10qb56j"}],"rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:1martcw10qb56j:comments","value":{"issue_id":"i1","_0_value":2,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"aggregates.record","args":{"queries":[{"name":"aggregates.issueWithCommentCount","args":"i1"}],"ops":[{"op":"insert","table":"comment","value":{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":1}}],"record":"m1"}},{"op":"advance","ms":10},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":null,"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":null,"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1martcw10qb56j","name":"aggregates.issueWithCommentCount","args":["i1"],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":null,"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1martcw10qb56j","name":"aggregates.issueWithCommentCount","args":["i1"],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":null,"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":null,"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":null,"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},"resultType":"complete","notifications":2},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"aggregates.record","args":[{"queries":[{"name":"aggregates.issueWithCommentCount","args":"i1"}],"ops":[{"op":"insert","table":"comment","value":{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":1}}],"record":"m1"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},"resultType":"complete","notifications":1},"users":{"data":[{"id":"m1","name":"optimistic","metadata":{"before":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2}],"after":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3}]}}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2}],"after":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3}]}},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},"resultType":"complete","notifications":0},"users":{"data":[{"id":"m1","name":"optimistic","metadata":{"before":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2}],"after":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3}]}}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2}],"after":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3}]}},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},"resultType":"complete","notifications":0},"users":{"data":[{"id":"m1","name":"optimistic","metadata":{"before":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2}],"after":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3}]}}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2}],"after":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3}]}},"server":"pending"}}}]}, +{"name":"aggregate: a mutator reads its optimistic relationship count during rebase","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.issueWithCommentCount","args":"i1"},{"op":"materialize","view":"users","query":"users.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"1martcw10qb56j"}],"rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:1martcw10qb56j:comments","value":{"issue_id":"i1","_0_value":2,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"aggregates.record","args":{"queries":[{"name":"aggregates.issueWithCommentCount","args":"i1"}],"ops":[{"op":"insert","table":"comment","value":{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":1}}],"record":"m1"}},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2","rowsPatch":[{"op":"put","tableName":"aggregate:1martcw10qb56j:comments","value":{"issue_id":"i1","_0_value":5,"_0_version":"02"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":null,"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":null,"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1martcw10qb56j","name":"aggregates.issueWithCommentCount","args":["i1"],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":null,"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1martcw10qb56j","name":"aggregates.issueWithCommentCount","args":["i1"],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":null,"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":null,"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":null,"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},"resultType":"complete","notifications":2},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"aggregates.record","args":[{"queries":[{"name":"aggregates.issueWithCommentCount","args":"i1"}],"ops":[{"op":"insert","table":"comment","value":{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":1}}],"record":"m1"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},"resultType":"complete","notifications":1},"users":{"data":[{"id":"m1","name":"optimistic","metadata":{"before":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2}],"after":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3}]}}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2}],"after":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3}]}},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},"resultType":"complete","notifications":0},"users":{"data":[{"id":"m1","name":"optimistic","metadata":{"before":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2}],"after":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3}]}}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2}],"after":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3}]}},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},"resultType":"complete","notifications":0},"users":{"data":[{"id":"m1","name":"optimistic","metadata":{"before":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2}],"after":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3}]}}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2}],"after":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3}]}},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},"resultType":"complete","notifications":0},"users":{"data":[{"id":"m1","name":"optimistic","metadata":{"before":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2}],"after":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3}]}}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2}],"after":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3}]}},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":6},"resultType":"complete","notifications":1},"users":{"data":[{"id":"m1","name":"rebase","metadata":{"before":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":5}],"after":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":6}]}}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2}],"after":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3}]}},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":6},"resultType":"complete","notifications":0},"users":{"data":[{"id":"m1","name":"rebase","metadata":{"before":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":5}],"after":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":6}]}}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2}],"after":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3}]}},"server":"pending"}}}]}, +{"name":"aggregate: a mutator reads its own writes in a synced groupBy during optimistic","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.openByState"},{"op":"materialize","view":"users","query":"users.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"19nbwzq10acko1"}],"rowsPatch":[{"op":"put","tableName":"aggregate:19nbwzq10acko1:#group","value":{"closed":false,"_0_key":"false","_0_value":2,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"aggregates.record","args":{"queries":[{"name":"aggregates.openByState"}],"ops":[{"op":"insert","table":"issue","value":{"id":"i9","title":"i9","description":"","closed":false,"ownerId":null,"createdAt":1}},{"op":"insert","table":"issue","value":{"id":"i10","title":"i10","description":"","closed":true,"ownerId":null,"createdAt":1}}],"record":"m1"}},{"op":"advance","ms":10},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"19nbwzq10acko1","name":"aggregates.openByState","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"19nbwzq10acko1","name":"aggregates.openByState","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"count":2}],"resultType":"complete","notifications":2},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"aggregates.record","args":[{"queries":[{"name":"aggregates.openByState"}],"ops":[{"op":"insert","table":"issue","value":{"id":"i9","title":"i9","description":"","closed":false,"ownerId":null,"createdAt":1}},{"op":"insert","table":"issue","value":{"id":"i10","title":"i10","description":"","closed":true,"ownerId":null,"createdAt":1}}],"record":"m1"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"count":3}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"m1","name":"optimistic","metadata":{"before":[[{"closed":false,"count":2}]],"after":[[{"closed":false,"count":3}]]}}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[[{"closed":false,"count":2}]],"after":[[{"closed":false,"count":3}]]}},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"count":3}],"resultType":"complete","notifications":0},"users":{"data":[{"id":"m1","name":"optimistic","metadata":{"before":[[{"closed":false,"count":2}]],"after":[[{"closed":false,"count":3}]]}}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[[{"closed":false,"count":2}]],"after":[[{"closed":false,"count":3}]]}},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"count":3}],"resultType":"complete","notifications":0},"users":{"data":[{"id":"m1","name":"optimistic","metadata":{"before":[[{"closed":false,"count":2}]],"after":[[{"closed":false,"count":3}]]}}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[[{"closed":false,"count":2}]],"after":[[{"closed":false,"count":3}]]}},"server":"pending"}}}]}, +{"name":"aggregate: a mutator reads its own writes in a synced groupBy during rebase","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.openByState"},{"op":"materialize","view":"users","query":"users.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"19nbwzq10acko1"}],"rowsPatch":[{"op":"put","tableName":"aggregate:19nbwzq10acko1:#group","value":{"closed":false,"_0_key":"false","_0_value":2,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"aggregates.record","args":{"queries":[{"name":"aggregates.openByState"}],"ops":[{"op":"insert","table":"issue","value":{"id":"i9","title":"i9","description":"","closed":false,"ownerId":null,"createdAt":1}},{"op":"insert","table":"issue","value":{"id":"i10","title":"i10","description":"","closed":true,"ownerId":null,"createdAt":1}}],"record":"m1"}},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2","rowsPatch":[{"op":"put","tableName":"aggregate:19nbwzq10acko1:#group","value":{"closed":false,"_0_key":"false","_0_value":5,"_0_version":"02"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"19nbwzq10acko1","name":"aggregates.openByState","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"19nbwzq10acko1","name":"aggregates.openByState","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"count":2}],"resultType":"complete","notifications":2},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"aggregates.record","args":[{"queries":[{"name":"aggregates.openByState"}],"ops":[{"op":"insert","table":"issue","value":{"id":"i9","title":"i9","description":"","closed":false,"ownerId":null,"createdAt":1}},{"op":"insert","table":"issue","value":{"id":"i10","title":"i10","description":"","closed":true,"ownerId":null,"createdAt":1}}],"record":"m1"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"count":3}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"m1","name":"optimistic","metadata":{"before":[[{"closed":false,"count":2}]],"after":[[{"closed":false,"count":3}]]}}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[[{"closed":false,"count":2}]],"after":[[{"closed":false,"count":3}]]}},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"count":3}],"resultType":"complete","notifications":0},"users":{"data":[{"id":"m1","name":"optimistic","metadata":{"before":[[{"closed":false,"count":2}]],"after":[[{"closed":false,"count":3}]]}}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[[{"closed":false,"count":2}]],"after":[[{"closed":false,"count":3}]]}},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"count":3}],"resultType":"complete","notifications":0},"users":{"data":[{"id":"m1","name":"optimistic","metadata":{"before":[[{"closed":false,"count":2}]],"after":[[{"closed":false,"count":3}]]}}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[[{"closed":false,"count":2}]],"after":[[{"closed":false,"count":3}]]}},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"count":3}],"resultType":"complete","notifications":0},"users":{"data":[{"id":"m1","name":"optimistic","metadata":{"before":[[{"closed":false,"count":2}]],"after":[[{"closed":false,"count":3}]]}}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[[{"closed":false,"count":2}]],"after":[[{"closed":false,"count":3}]]}},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"count":6}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"m1","name":"rebase","metadata":{"before":[[{"closed":false,"count":5}]],"after":[[{"closed":false,"count":6}]]}}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[[{"closed":false,"count":2}]],"after":[[{"closed":false,"count":3}]]}},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"count":6}],"resultType":"complete","notifications":0},"users":{"data":[{"id":"m1","name":"rebase","metadata":{"before":[[{"closed":false,"count":5}]],"after":[[{"closed":false,"count":6}]]}}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[[{"closed":false,"count":2}]],"after":[[{"closed":false,"count":3}]]}},"server":"pending"}}}]}, +{"name":"aggregate: a mutator reads its new and removed values in a synced distinct","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.issueStates"},{"op":"materialize","view":"users","query":"users.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"1yd1we10at424n"}],"rowsPatch":[{"op":"put","tableName":"aggregate:1yd1we10at424n:#group","value":{"closed":false,"_0_key":"false","_0_value":1,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":null,"createdAt":1}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"aggregates.record","args":{"queries":[{"name":"aggregates.issueStates"}],"ops":[{"op":"insert","table":"issue","value":{"id":"i9","title":"i9","description":"","closed":true,"ownerId":null,"createdAt":1}}],"record":"m1"}},{"op":"mutate","mutation":"m2","mutator":"aggregates.record","args":{"queries":[{"name":"aggregates.issueStates"}],"ops":[{"op":"delete","table":"issue","value":{"id":"i1"}}],"record":"m2"}},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1yd1we10at424n","name":"aggregates.issueStates","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1yd1we10at424n","name":"aggregates.issueStates","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false}],"resultType":"complete","notifications":2},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"aggregates.record","args":[{"queries":[{"name":"aggregates.issueStates"}],"ops":[{"op":"insert","table":"issue","value":{"id":"i9","title":"i9","description":"","closed":true,"ownerId":null,"createdAt":1}}],"record":"m1"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false},{"closed":true}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"m1","name":"optimistic","metadata":{"before":[[{"closed":false}]],"after":[[{"closed":false},{"closed":true}]]}}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[[{"closed":false}]],"after":[[{"closed":false},{"closed":true}]]}},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":2,"clientID":"$clientID","name":"aggregates.record","args":[{"queries":[{"name":"aggregates.issueStates"}],"ops":[{"op":"delete","table":"issue","value":{"id":"i1"}}],"record":"m2"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":true}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"m1","name":"optimistic","metadata":{"before":[[{"closed":false}]],"after":[[{"closed":false},{"closed":true}]]}},{"id":"m2","name":"optimistic","metadata":{"before":[[{"closed":false},{"closed":true}]],"after":[[{"closed":true}]]}}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[[{"closed":false}]],"after":[[{"closed":false},{"closed":true}]]}},"server":"pending"},"m2":{"client":{"type":"success","data":{"before":[[{"closed":false},{"closed":true}]],"after":[[{"closed":true}]]}},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":true}],"resultType":"complete","notifications":0},"users":{"data":[{"id":"m1","name":"optimistic","metadata":{"before":[[{"closed":false}]],"after":[[{"closed":false},{"closed":true}]]}},{"id":"m2","name":"optimistic","metadata":{"before":[[{"closed":false},{"closed":true}]],"after":[[{"closed":true}]]}}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[[{"closed":false}]],"after":[[{"closed":false},{"closed":true}]]}},"server":"pending"},"m2":{"client":{"type":"success","data":{"before":[[{"closed":false},{"closed":true}]],"after":[[{"closed":true}]]}},"server":"pending"}}}]}, +{"name":"aggregate: a mutator reads its own writes in a synced groupBy().sum()","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.timeByState"},{"op":"materialize","view":"users","query":"users.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"1qnqg810hetfbd"}],"rowsPatch":[{"op":"put","tableName":"aggregate:1qnqg810hetfbd:#group","value":{"closed":false,"_0_key":"false","_0_value":3,"_0_sum":3,"_0_count":2,"_0_rows":2,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"aggregates.record","args":{"queries":[{"name":"aggregates.timeByState"}],"ops":[{"op":"insert","table":"issue","value":{"id":"i9","title":"i9","description":"","closed":false,"ownerId":null,"createdAt":7}},{"op":"insert","table":"issue","value":{"id":"i10","title":"i10","description":"","closed":true,"ownerId":null,"createdAt":4}}],"record":"m1"}},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1qnqg810hetfbd","name":"aggregates.timeByState","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1qnqg810hetfbd","name":"aggregates.timeByState","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"sum":3}],"resultType":"complete","notifications":2},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"aggregates.record","args":[{"queries":[{"name":"aggregates.timeByState"}],"ops":[{"op":"insert","table":"issue","value":{"id":"i9","title":"i9","description":"","closed":false,"ownerId":null,"createdAt":7}},{"op":"insert","table":"issue","value":{"id":"i10","title":"i10","description":"","closed":true,"ownerId":null,"createdAt":4}}],"record":"m1"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"sum":10},{"closed":true,"sum":4}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"m1","name":"optimistic","metadata":{"before":[[{"closed":false,"sum":3}]],"after":[[{"closed":false,"sum":10},{"closed":true,"sum":4}]]}}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[[{"closed":false,"sum":3}]],"after":[[{"closed":false,"sum":10},{"closed":true,"sum":4}]]}},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"sum":10},{"closed":true,"sum":4}],"resultType":"complete","notifications":0},"users":{"data":[{"id":"m1","name":"optimistic","metadata":{"before":[[{"closed":false,"sum":3}]],"after":[[{"closed":false,"sum":10},{"closed":true,"sum":4}]]}}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[[{"closed":false,"sum":3}]],"after":[[{"closed":false,"sum":10},{"closed":true,"sum":4}]]}},"server":"pending"}}}]}, +{"name":"aggregate: a mutator reads its own writes in a synced groupBy().avg()","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.avgTimeByState"},{"op":"materialize","view":"users","query":"users.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"04kf6q80mb4f77"}],"rowsPatch":[{"op":"put","tableName":"aggregate:04kf6q80mb4f77:#group","value":{"closed":false,"_0_key":"false","_0_value":1.5,"_0_sum":3,"_0_count":2,"_0_rows":2,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"aggregates.record","args":{"queries":[{"name":"aggregates.avgTimeByState"}],"ops":[{"op":"insert","table":"issue","value":{"id":"i9","title":"i9","description":"","closed":false,"ownerId":null,"createdAt":7}},{"op":"insert","table":"issue","value":{"id":"i10","title":"i10","description":"","closed":true,"ownerId":null,"createdAt":4}}],"record":"m1"}},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"04kf6q80mb4f77","name":"aggregates.avgTimeByState","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"04kf6q80mb4f77","name":"aggregates.avgTimeByState","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"avg":1.5}],"resultType":"complete","notifications":2},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"aggregates.record","args":[{"queries":[{"name":"aggregates.avgTimeByState"}],"ops":[{"op":"insert","table":"issue","value":{"id":"i9","title":"i9","description":"","closed":false,"ownerId":null,"createdAt":7}},{"op":"insert","table":"issue","value":{"id":"i10","title":"i10","description":"","closed":true,"ownerId":null,"createdAt":4}}],"record":"m1"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"avg":3.3333333333333335},{"closed":true,"avg":4}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"m1","name":"optimistic","metadata":{"before":[[{"closed":false,"avg":1.5}]],"after":[[{"closed":false,"avg":3.3333333333333335},{"closed":true,"avg":4}]]}}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[[{"closed":false,"avg":1.5}]],"after":[[{"closed":false,"avg":3.3333333333333335},{"closed":true,"avg":4}]]}},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"avg":3.3333333333333335},{"closed":true,"avg":4}],"resultType":"complete","notifications":0},"users":{"data":[{"id":"m1","name":"optimistic","metadata":{"before":[[{"closed":false,"avg":1.5}]],"after":[[{"closed":false,"avg":3.3333333333333335},{"closed":true,"avg":4}]]}}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":{"before":[[{"closed":false,"avg":1.5}]],"after":[[{"closed":false,"avg":3.3333333333333335},{"closed":true,"avg":4}]]}},"server":"pending"}}}]}, +{"name":"aggregate: an optimistic count moves the synced group an orderBy reorders","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.issuesByOwner"},{"op":"materialize","view":"users","query":"users.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"1pin8cw178mkdt"}],"rowsPatch":[{"op":"put","tableName":"aggregate:1pin8cw178mkdt:#group","value":{"owner_id":"u1","closed":false,"_0_key":"[\"u1\",false]","_0_value":2,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"issue.create","args":{"id":"i9","ownerId":"u1"}},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1pin8cw178mkdt","name":"aggregates.issuesByOwner","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1pin8cw178mkdt","name":"aggregates.issuesByOwner","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"ownerId":"u1","count":2}],"resultType":"complete","notifications":2},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"issue.create","args":[{"id":"i9","ownerId":"u1"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"ownerId":"u1","count":3}],"resultType":"complete","notifications":1},"users":{"data":[],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"ownerId":"u1","count":3}],"resultType":"complete","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}}]}, +{"name":"aggregate: an edit within a group the client lacks adds no group, a new row does","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"states","query":"aggregates.issueStates"},{"op":"materialize","view":"times","query":"aggregates.timeByState"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":null,"createdAt":1}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"advance","ms":10},{"op":"mutate","mutation":"m1","mutator":"issue.update","args":{"id":"i1","title":"renamed"}},{"op":"mutate","mutation":"m2","mutator":"issue.update","args":{"id":"i1","createdAt":7}},{"op":"advance","ms":10},{"op":"mutate","mutation":"m3","mutator":"issue.create","args":{"id":"i9","closed":true,"createdAt":4}},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"states":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"states":{"data":[],"resultType":"unknown","notifications":0},"times":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1yd1we10at424n","name":"aggregates.issueStates","args":[],"ttl":300000},{"op":"put","hash":"1qnqg810hetfbd","name":"aggregates.timeByState","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"states":{"data":[],"resultType":"unknown","notifications":0},"times":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1yd1we10at424n","name":"aggregates.issueStates","args":[],"ttl":300000},{"op":"put","hash":"1qnqg810hetfbd","name":"aggregates.timeByState","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"states":{"data":[],"resultType":"unknown","notifications":0},"times":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"states":{"data":[],"resultType":"unknown","notifications":0},"times":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"states":{"data":[],"resultType":"unknown","notifications":0},"times":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"states":{"data":[],"resultType":"unknown","notifications":0},"times":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"states":{"data":[],"resultType":"unknown","notifications":0},"times":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["push",{"timestamp":1700000000020,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000020,"id":1,"clientID":"$clientID","name":"issue.update","args":[{"id":"i1","title":"renamed"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"states":{"data":[],"resultType":"unknown","notifications":0},"times":{"data":[],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000020,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000020,"id":2,"clientID":"$clientID","name":"issue.update","args":[{"id":"i1","createdAt":7}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"states":{"data":[],"resultType":"unknown","notifications":0},"times":{"data":[],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"states":{"data":[],"resultType":"unknown","notifications":0},"times":{"data":[],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000030,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000030,"id":3,"clientID":"$clientID","name":"issue.create","args":[{"id":"i9","closed":true,"createdAt":4}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"states":{"data":[{"closed":true}],"resultType":"unknown","notifications":1},"times":{"data":[{"closed":true,"sum":4}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"states":{"data":[{"closed":true}],"resultType":"unknown","notifications":0},"times":{"data":[{"closed":true,"sum":4}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}}]}, +{"name":"aggregate: a grouped sum stored without its row count keeps its group when emptied","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"users","query":"users.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[],"rowsPatch":[{"op":"put","tableName":"aggregate:1qnqg810hetfbd:#group","value":{"closed":false,"_0_key":"false","_0_value":7,"_0_sum":7,"_0_count":2,"_0_version":"01"}},{"op":"put","tableName":"aggregate:1qnqg810hetfbd:#group","value":{"closed":true,"_0_key":"true","_0_value":5,"_0_sum":5,"_0_count":1,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"materialize","view":"times","query":"aggregates.timeByState"},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2","gotQueriesPatch":[{"op":"put","hash":"1qnqg810hetfbd"}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]},{"op":"advance","ms":10},{"op":"mutate","mutation":"m1","mutator":"issue.delete","args":"i3"},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"users":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0},"times":{"data":[{"closed":false,"sum":7},{"closed":true,"sum":5}],"resultType":"unknown","notifications":1}}},{"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0},"times":{"data":[{"closed":false,"sum":7},{"closed":true,"sum":5}],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0},"times":{"data":[{"closed":false,"sum":7},{"closed":true,"sum":5}],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0},"times":{"data":[{"closed":false,"sum":7},{"closed":true,"sum":5}],"resultType":"complete","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1qnqg810hetfbd","name":"aggregates.timeByState","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0},"times":{"data":[{"closed":false,"sum":7},{"closed":true,"sum":5}],"resultType":"complete","notifications":0}}},{"sent":[["push",{"timestamp":1700000000020,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000020,"id":1,"clientID":"$clientID","name":"issue.delete","args":["i3"]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0},"times":{"data":[{"closed":false,"sum":7},{"closed":true,"sum":null}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0},"times":{"data":[{"closed":false,"sum":7},{"closed":true,"sum":null}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}}]}, +{"name":"aggregate: a child with no parent row, or a null correlation, moves no count","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.userIssueCounts"},{"op":"materialize","view":"users","query":"users.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"1ho6ttz1azgab3"}],"rowsPatch":[{"op":"put","tableName":"users","value":{"id":"u1","name":"Alice","metadata":null}},{"op":"put","tableName":"aggregate:1ho6ttz1azgab3:issues","value":{"owner_id":"u1","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"users","value":{"id":"u2","name":"Bob","metadata":null}},{"op":"put","tableName":"aggregate:1ho6ttz1azgab3:issues","value":{"owner_id":"u2","_0_value":0,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"issue.create","args":{"id":"i8","ownerId":null}},{"op":"mutate","mutation":"m2","mutator":"issue.create","args":{"id":"i9","ownerId":"u2"}},{"op":"mutate","mutation":"m3","mutator":"issue.update","args":{"id":"i9","ownerId":null}},{"op":"mutate","mutation":"m4","mutator":"issue.create","args":{"id":"i10","ownerId":"u7"}},{"op":"advance","ms":10},{"op":"mutate","mutation":"m5","mutator":"aggregates.read","args":{"ops":[{"op":"insert","table":"user","value":{"id":"u7","name":"Gus"}}],"queries":[]}},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1ho6ttz1azgab3","name":"aggregates.userIssueCounts","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1ho6ttz1azgab3","name":"aggregates.userIssueCounts","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"u1","name":"Alice","metadata":null,"issues":2},{"id":"u2","name":"Bob","metadata":null,"issues":0}],"resultType":"complete","notifications":2},"users":{"data":[{"id":"u1","name":"Alice","metadata":null},{"id":"u2","name":"Bob","metadata":null}],"resultType":"unknown","notifications":1}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"issue.create","args":[{"id":"i8","ownerId":null}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"u1","name":"Alice","metadata":null,"issues":2},{"id":"u2","name":"Bob","metadata":null,"issues":0}],"resultType":"complete","notifications":0},"users":{"data":[{"id":"u1","name":"Alice","metadata":null},{"id":"u2","name":"Bob","metadata":null}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":2,"clientID":"$clientID","name":"issue.create","args":[{"id":"i9","ownerId":"u2"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"u1","name":"Alice","metadata":null,"issues":2},{"id":"u2","name":"Bob","metadata":null,"issues":1}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"u1","name":"Alice","metadata":null},{"id":"u2","name":"Bob","metadata":null}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":3,"clientID":"$clientID","name":"issue.update","args":[{"id":"i9","ownerId":null}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"u1","name":"Alice","metadata":null,"issues":2},{"id":"u2","name":"Bob","metadata":null,"issues":0}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"u1","name":"Alice","metadata":null},{"id":"u2","name":"Bob","metadata":null}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":4,"clientID":"$clientID","name":"issue.create","args":[{"id":"i10","ownerId":"u7"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"u1","name":"Alice","metadata":null,"issues":2},{"id":"u2","name":"Bob","metadata":null,"issues":0}],"resultType":"complete","notifications":0},"users":{"data":[{"id":"u1","name":"Alice","metadata":null},{"id":"u2","name":"Bob","metadata":null}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"},"m4":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"u1","name":"Alice","metadata":null,"issues":2},{"id":"u2","name":"Bob","metadata":null,"issues":0}],"resultType":"complete","notifications":0},"users":{"data":[{"id":"u1","name":"Alice","metadata":null},{"id":"u2","name":"Bob","metadata":null}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"},"m4":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000020,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000020,"id":5,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"insert","table":"user","value":{"id":"u7","name":"Gus"}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"u1","name":"Alice","metadata":null,"issues":2},{"id":"u2","name":"Bob","metadata":null,"issues":0},{"id":"u7","name":"Gus","metadata":null,"issues":0}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"u1","name":"Alice","metadata":null},{"id":"u2","name":"Bob","metadata":null},{"id":"u7","name":"Gus","metadata":null}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"},"m4":{"client":{"type":"success"},"server":"pending"},"m5":{"client":{"type":"success","data":[]},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"u1","name":"Alice","metadata":null,"issues":2},{"id":"u2","name":"Bob","metadata":null,"issues":0},{"id":"u7","name":"Gus","metadata":null,"issues":0}],"resultType":"complete","notifications":0},"users":{"data":[{"id":"u1","name":"Alice","metadata":null},{"id":"u2","name":"Bob","metadata":null},{"id":"u7","name":"Gus","metadata":null}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"},"m4":{"client":{"type":"success"},"server":"pending"},"m5":{"client":{"type":"success","data":[]},"server":"pending"}}}]}, +{"name":"aggregate: a grouped sum of a JSON path moves only with number leaves","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.pointsByName"},{"op":"materialize","view":"users","query":"users.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0igt7mf0vzeqcu"}],"rowsPatch":[{"op":"put","tableName":"aggregate:0igt7mf0vzeqcu:#group","value":{"name":"A","_0_key":"sA","_0_value":5,"_0_sum":5,"_0_count":1,"_0_rows":2,"_0_version":"01"}},{"op":"put","tableName":"aggregate:0igt7mf0vzeqcu:#group","value":{"name":"B","_0_key":"sB","_0_value":null,"_0_sum":0,"_0_count":0,"_0_rows":1,"_0_version":"01"}},{"op":"put","tableName":"aggregate:0igt7mf0vzeqcu:#group","value":{"name":"C","_0_key":"sC","_0_value":null,"_0_sum":0,"_0_count":0,"_0_rows":1,"_0_version":"01"}},{"op":"put","tableName":"users","value":{"id":"u1","name":"A","metadata":{"points":5}}},{"op":"put","tableName":"users","value":{"id":"u2","name":"A","metadata":{"points":"7"}}},{"op":"put","tableName":"users","value":{"id":"u3","name":"B","metadata":{"other":1}}},{"op":"put","tableName":"users","value":{"id":"u4","name":"C","metadata":null}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"aggregates.read","args":{"ops":[{"op":"update","table":"user","value":{"id":"u1","metadata":{"points":5,"note":"x"}}}],"queries":[]}},{"op":"mutate","mutation":"m2","mutator":"aggregates.read","args":{"ops":[{"op":"update","table":"user","value":{"id":"u2","metadata":{"points":6}}}],"queries":[]}},{"op":"mutate","mutation":"m3","mutator":"aggregates.read","args":{"ops":[{"op":"insert","table":"user","value":{"id":"u5","name":"A","metadata":{"points":0}}}],"queries":[]}},{"op":"mutate","mutation":"m4","mutator":"aggregates.read","args":{"ops":[{"op":"delete","table":"user","value":{"id":"u1"}}],"queries":[]}},{"op":"mutate","mutation":"m5","mutator":"aggregates.read","args":{"ops":[{"op":"insert","table":"user","value":{"id":"u6","name":"B","metadata":{"points":0}}}],"queries":[]}},{"op":"mutate","mutation":"m6","mutator":"aggregates.read","args":{"ops":[{"op":"delete","table":"user","value":{"id":"u6"}}],"queries":[]}},{"op":"mutate","mutation":"m7","mutator":"aggregates.read","args":{"ops":[{"op":"delete","table":"user","value":{"id":"u4"}}],"queries":[]}},{"op":"mutate","mutation":"m8","mutator":"aggregates.read","args":{"ops":[{"op":"insert","table":"user","value":{"id":"u7","name":"D","metadata":{"points":3}}}],"queries":[]}},{"op":"mutate","mutation":"m9","mutator":"aggregates.read","args":{"ops":[{"op":"insert","table":"user","value":{"id":"u8","name":"D","metadata":null}}],"queries":[]}},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0igt7mf0vzeqcu","name":"aggregates.pointsByName","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0igt7mf0vzeqcu","name":"aggregates.pointsByName","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"name":"A","sum":5},{"name":"B","sum":null},{"name":"C","sum":null}],"resultType":"complete","notifications":2},"users":{"data":[{"id":"u1","name":"A","metadata":{"points":5}},{"id":"u2","name":"A","metadata":{"points":"7"}},{"id":"u3","name":"B","metadata":{"other":1}},{"id":"u4","name":"C","metadata":null}],"resultType":"unknown","notifications":1}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"update","table":"user","value":{"id":"u1","metadata":{"points":5,"note":"x"}}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"name":"A","sum":5},{"name":"B","sum":null},{"name":"C","sum":null}],"resultType":"complete","notifications":0},"users":{"data":[{"id":"u1","name":"A","metadata":{"points":5,"note":"x"}},{"id":"u2","name":"A","metadata":{"points":"7"}},{"id":"u3","name":"B","metadata":{"other":1}},{"id":"u4","name":"C","metadata":null}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":2,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"update","table":"user","value":{"id":"u2","metadata":{"points":6}}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"name":"A","sum":11},{"name":"B","sum":null},{"name":"C","sum":null}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"u1","name":"A","metadata":{"points":5,"note":"x"}},{"id":"u2","name":"A","metadata":{"points":6}},{"id":"u3","name":"B","metadata":{"other":1}},{"id":"u4","name":"C","metadata":null}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":3,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"insert","table":"user","value":{"id":"u5","name":"A","metadata":{"points":0}}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"name":"A","sum":11},{"name":"B","sum":null},{"name":"C","sum":null}],"resultType":"complete","notifications":0},"users":{"data":[{"id":"u1","name":"A","metadata":{"points":5,"note":"x"}},{"id":"u2","name":"A","metadata":{"points":6}},{"id":"u3","name":"B","metadata":{"other":1}},{"id":"u4","name":"C","metadata":null},{"id":"u5","name":"A","metadata":{"points":0}}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"},"m3":{"client":{"type":"success","data":[]},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":4,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"delete","table":"user","value":{"id":"u1"}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"name":"A","sum":6},{"name":"B","sum":null},{"name":"C","sum":null}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"u2","name":"A","metadata":{"points":6}},{"id":"u3","name":"B","metadata":{"other":1}},{"id":"u4","name":"C","metadata":null},{"id":"u5","name":"A","metadata":{"points":0}}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"},"m3":{"client":{"type":"success","data":[]},"server":"pending"},"m4":{"client":{"type":"success","data":[]},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":5,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"insert","table":"user","value":{"id":"u6","name":"B","metadata":{"points":0}}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"name":"A","sum":6},{"name":"B","sum":0},{"name":"C","sum":null}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"u2","name":"A","metadata":{"points":6}},{"id":"u3","name":"B","metadata":{"other":1}},{"id":"u4","name":"C","metadata":null},{"id":"u5","name":"A","metadata":{"points":0}},{"id":"u6","name":"B","metadata":{"points":0}}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"},"m3":{"client":{"type":"success","data":[]},"server":"pending"},"m4":{"client":{"type":"success","data":[]},"server":"pending"},"m5":{"client":{"type":"success","data":[]},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":6,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"delete","table":"user","value":{"id":"u6"}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"name":"A","sum":6},{"name":"B","sum":null},{"name":"C","sum":null}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"u2","name":"A","metadata":{"points":6}},{"id":"u3","name":"B","metadata":{"other":1}},{"id":"u4","name":"C","metadata":null},{"id":"u5","name":"A","metadata":{"points":0}}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"},"m3":{"client":{"type":"success","data":[]},"server":"pending"},"m4":{"client":{"type":"success","data":[]},"server":"pending"},"m5":{"client":{"type":"success","data":[]},"server":"pending"},"m6":{"client":{"type":"success","data":[]},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":7,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"delete","table":"user","value":{"id":"u4"}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"name":"A","sum":6},{"name":"B","sum":null}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"u2","name":"A","metadata":{"points":6}},{"id":"u3","name":"B","metadata":{"other":1}},{"id":"u5","name":"A","metadata":{"points":0}}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"},"m3":{"client":{"type":"success","data":[]},"server":"pending"},"m4":{"client":{"type":"success","data":[]},"server":"pending"},"m5":{"client":{"type":"success","data":[]},"server":"pending"},"m6":{"client":{"type":"success","data":[]},"server":"pending"},"m7":{"client":{"type":"success","data":[]},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":8,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"insert","table":"user","value":{"id":"u7","name":"D","metadata":{"points":3}}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"name":"A","sum":6},{"name":"B","sum":null},{"name":"D","sum":3}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"u2","name":"A","metadata":{"points":6}},{"id":"u3","name":"B","metadata":{"other":1}},{"id":"u5","name":"A","metadata":{"points":0}},{"id":"u7","name":"D","metadata":{"points":3}}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"},"m3":{"client":{"type":"success","data":[]},"server":"pending"},"m4":{"client":{"type":"success","data":[]},"server":"pending"},"m5":{"client":{"type":"success","data":[]},"server":"pending"},"m6":{"client":{"type":"success","data":[]},"server":"pending"},"m7":{"client":{"type":"success","data":[]},"server":"pending"},"m8":{"client":{"type":"success","data":[]},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":9,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"insert","table":"user","value":{"id":"u8","name":"D","metadata":null}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"name":"A","sum":6},{"name":"B","sum":null},{"name":"D","sum":3}],"resultType":"complete","notifications":0},"users":{"data":[{"id":"u2","name":"A","metadata":{"points":6}},{"id":"u3","name":"B","metadata":{"other":1}},{"id":"u5","name":"A","metadata":{"points":0}},{"id":"u7","name":"D","metadata":{"points":3}},{"id":"u8","name":"D","metadata":null}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"},"m3":{"client":{"type":"success","data":[]},"server":"pending"},"m4":{"client":{"type":"success","data":[]},"server":"pending"},"m5":{"client":{"type":"success","data":[]},"server":"pending"},"m6":{"client":{"type":"success","data":[]},"server":"pending"},"m7":{"client":{"type":"success","data":[]},"server":"pending"},"m8":{"client":{"type":"success","data":[]},"server":"pending"},"m9":{"client":{"type":"success","data":[]},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"name":"A","sum":6},{"name":"B","sum":null},{"name":"D","sum":3}],"resultType":"complete","notifications":0},"users":{"data":[{"id":"u2","name":"A","metadata":{"points":6}},{"id":"u3","name":"B","metadata":{"other":1}},{"id":"u5","name":"A","metadata":{"points":0}},{"id":"u7","name":"D","metadata":{"points":3}},{"id":"u8","name":"D","metadata":null}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"},"m3":{"client":{"type":"success","data":[]},"server":"pending"},"m4":{"client":{"type":"success","data":[]},"server":"pending"},"m5":{"client":{"type":"success","data":[]},"server":"pending"},"m6":{"client":{"type":"success","data":[]},"server":"pending"},"m7":{"client":{"type":"success","data":[]},"server":"pending"},"m8":{"client":{"type":"success","data":[]},"server":"pending"},"m9":{"client":{"type":"success","data":[]},"server":"pending"}}}]}, +{"name":"aggregate: a grouped average of a JSON path moves only with number leaves","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.avgPointsByName"},{"op":"materialize","view":"users","query":"users.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"1d8bkkf05ocqze"}],"rowsPatch":[{"op":"put","tableName":"aggregate:1d8bkkf05ocqze:#group","value":{"name":"A","_0_key":"sA","_0_value":5,"_0_sum":5,"_0_count":1,"_0_rows":2,"_0_version":"01"}},{"op":"put","tableName":"aggregate:1d8bkkf05ocqze:#group","value":{"name":"B","_0_key":"sB","_0_value":null,"_0_sum":0,"_0_count":0,"_0_rows":1,"_0_version":"01"}},{"op":"put","tableName":"aggregate:1d8bkkf05ocqze:#group","value":{"name":"C","_0_key":"sC","_0_value":null,"_0_sum":0,"_0_count":0,"_0_rows":1,"_0_version":"01"}},{"op":"put","tableName":"users","value":{"id":"u1","name":"A","metadata":{"points":5}}},{"op":"put","tableName":"users","value":{"id":"u2","name":"A","metadata":{"points":"7"}}},{"op":"put","tableName":"users","value":{"id":"u3","name":"B","metadata":{"other":1}}},{"op":"put","tableName":"users","value":{"id":"u4","name":"C","metadata":null}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"aggregates.read","args":{"ops":[{"op":"update","table":"user","value":{"id":"u1","metadata":{"points":5,"note":"x"}}}],"queries":[]}},{"op":"mutate","mutation":"m2","mutator":"aggregates.read","args":{"ops":[{"op":"update","table":"user","value":{"id":"u2","metadata":{"points":6}}}],"queries":[]}},{"op":"mutate","mutation":"m3","mutator":"aggregates.read","args":{"ops":[{"op":"insert","table":"user","value":{"id":"u5","name":"A","metadata":{"points":0}}}],"queries":[]}},{"op":"mutate","mutation":"m4","mutator":"aggregates.read","args":{"ops":[{"op":"delete","table":"user","value":{"id":"u1"}}],"queries":[]}},{"op":"mutate","mutation":"m5","mutator":"aggregates.read","args":{"ops":[{"op":"insert","table":"user","value":{"id":"u6","name":"B","metadata":{"points":0}}}],"queries":[]}},{"op":"mutate","mutation":"m6","mutator":"aggregates.read","args":{"ops":[{"op":"delete","table":"user","value":{"id":"u6"}}],"queries":[]}},{"op":"mutate","mutation":"m7","mutator":"aggregates.read","args":{"ops":[{"op":"delete","table":"user","value":{"id":"u4"}}],"queries":[]}},{"op":"mutate","mutation":"m8","mutator":"aggregates.read","args":{"ops":[{"op":"insert","table":"user","value":{"id":"u7","name":"D","metadata":{"points":3}}}],"queries":[]}},{"op":"mutate","mutation":"m9","mutator":"aggregates.read","args":{"ops":[{"op":"insert","table":"user","value":{"id":"u8","name":"D","metadata":null}}],"queries":[]}},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1d8bkkf05ocqze","name":"aggregates.avgPointsByName","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1d8bkkf05ocqze","name":"aggregates.avgPointsByName","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"name":"A","avg":5},{"name":"B","avg":null},{"name":"C","avg":null}],"resultType":"complete","notifications":2},"users":{"data":[{"id":"u1","name":"A","metadata":{"points":5}},{"id":"u2","name":"A","metadata":{"points":"7"}},{"id":"u3","name":"B","metadata":{"other":1}},{"id":"u4","name":"C","metadata":null}],"resultType":"unknown","notifications":1}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"update","table":"user","value":{"id":"u1","metadata":{"points":5,"note":"x"}}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"name":"A","avg":5},{"name":"B","avg":null},{"name":"C","avg":null}],"resultType":"complete","notifications":0},"users":{"data":[{"id":"u1","name":"A","metadata":{"points":5,"note":"x"}},{"id":"u2","name":"A","metadata":{"points":"7"}},{"id":"u3","name":"B","metadata":{"other":1}},{"id":"u4","name":"C","metadata":null}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":2,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"update","table":"user","value":{"id":"u2","metadata":{"points":6}}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"name":"A","avg":5.5},{"name":"B","avg":null},{"name":"C","avg":null}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"u1","name":"A","metadata":{"points":5,"note":"x"}},{"id":"u2","name":"A","metadata":{"points":6}},{"id":"u3","name":"B","metadata":{"other":1}},{"id":"u4","name":"C","metadata":null}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":3,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"insert","table":"user","value":{"id":"u5","name":"A","metadata":{"points":0}}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"name":"A","avg":3.6666666666666665},{"name":"B","avg":null},{"name":"C","avg":null}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"u1","name":"A","metadata":{"points":5,"note":"x"}},{"id":"u2","name":"A","metadata":{"points":6}},{"id":"u3","name":"B","metadata":{"other":1}},{"id":"u4","name":"C","metadata":null},{"id":"u5","name":"A","metadata":{"points":0}}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"},"m3":{"client":{"type":"success","data":[]},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":4,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"delete","table":"user","value":{"id":"u1"}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"name":"A","avg":3},{"name":"B","avg":null},{"name":"C","avg":null}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"u2","name":"A","metadata":{"points":6}},{"id":"u3","name":"B","metadata":{"other":1}},{"id":"u4","name":"C","metadata":null},{"id":"u5","name":"A","metadata":{"points":0}}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"},"m3":{"client":{"type":"success","data":[]},"server":"pending"},"m4":{"client":{"type":"success","data":[]},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":5,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"insert","table":"user","value":{"id":"u6","name":"B","metadata":{"points":0}}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"name":"A","avg":3},{"name":"B","avg":0},{"name":"C","avg":null}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"u2","name":"A","metadata":{"points":6}},{"id":"u3","name":"B","metadata":{"other":1}},{"id":"u4","name":"C","metadata":null},{"id":"u5","name":"A","metadata":{"points":0}},{"id":"u6","name":"B","metadata":{"points":0}}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"},"m3":{"client":{"type":"success","data":[]},"server":"pending"},"m4":{"client":{"type":"success","data":[]},"server":"pending"},"m5":{"client":{"type":"success","data":[]},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":6,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"delete","table":"user","value":{"id":"u6"}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"name":"A","avg":3},{"name":"B","avg":null},{"name":"C","avg":null}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"u2","name":"A","metadata":{"points":6}},{"id":"u3","name":"B","metadata":{"other":1}},{"id":"u4","name":"C","metadata":null},{"id":"u5","name":"A","metadata":{"points":0}}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"},"m3":{"client":{"type":"success","data":[]},"server":"pending"},"m4":{"client":{"type":"success","data":[]},"server":"pending"},"m5":{"client":{"type":"success","data":[]},"server":"pending"},"m6":{"client":{"type":"success","data":[]},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":7,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"delete","table":"user","value":{"id":"u4"}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"name":"A","avg":3},{"name":"B","avg":null}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"u2","name":"A","metadata":{"points":6}},{"id":"u3","name":"B","metadata":{"other":1}},{"id":"u5","name":"A","metadata":{"points":0}}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"},"m3":{"client":{"type":"success","data":[]},"server":"pending"},"m4":{"client":{"type":"success","data":[]},"server":"pending"},"m5":{"client":{"type":"success","data":[]},"server":"pending"},"m6":{"client":{"type":"success","data":[]},"server":"pending"},"m7":{"client":{"type":"success","data":[]},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":8,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"insert","table":"user","value":{"id":"u7","name":"D","metadata":{"points":3}}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"name":"A","avg":3},{"name":"B","avg":null},{"name":"D","avg":3}],"resultType":"complete","notifications":1},"users":{"data":[{"id":"u2","name":"A","metadata":{"points":6}},{"id":"u3","name":"B","metadata":{"other":1}},{"id":"u5","name":"A","metadata":{"points":0}},{"id":"u7","name":"D","metadata":{"points":3}}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"},"m3":{"client":{"type":"success","data":[]},"server":"pending"},"m4":{"client":{"type":"success","data":[]},"server":"pending"},"m5":{"client":{"type":"success","data":[]},"server":"pending"},"m6":{"client":{"type":"success","data":[]},"server":"pending"},"m7":{"client":{"type":"success","data":[]},"server":"pending"},"m8":{"client":{"type":"success","data":[]},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":9,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"insert","table":"user","value":{"id":"u8","name":"D","metadata":null}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"name":"A","avg":3},{"name":"B","avg":null},{"name":"D","avg":3}],"resultType":"complete","notifications":0},"users":{"data":[{"id":"u2","name":"A","metadata":{"points":6}},{"id":"u3","name":"B","metadata":{"other":1}},{"id":"u5","name":"A","metadata":{"points":0}},{"id":"u7","name":"D","metadata":{"points":3}},{"id":"u8","name":"D","metadata":null}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"},"m3":{"client":{"type":"success","data":[]},"server":"pending"},"m4":{"client":{"type":"success","data":[]},"server":"pending"},"m5":{"client":{"type":"success","data":[]},"server":"pending"},"m6":{"client":{"type":"success","data":[]},"server":"pending"},"m7":{"client":{"type":"success","data":[]},"server":"pending"},"m8":{"client":{"type":"success","data":[]},"server":"pending"},"m9":{"client":{"type":"success","data":[]},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"name":"A","avg":3},{"name":"B","avg":null},{"name":"D","avg":3}],"resultType":"complete","notifications":0},"users":{"data":[{"id":"u2","name":"A","metadata":{"points":6}},{"id":"u3","name":"B","metadata":{"other":1}},{"id":"u5","name":"A","metadata":{"points":0}},{"id":"u7","name":"D","metadata":{"points":3}},{"id":"u8","name":"D","metadata":null}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"},"m2":{"client":{"type":"success","data":[]},"server":"pending"},"m3":{"client":{"type":"success","data":[]},"server":"pending"},"m4":{"client":{"type":"success","data":[]},"server":"pending"},"m5":{"client":{"type":"success","data":[]},"server":"pending"},"m6":{"client":{"type":"success","data":[]},"server":"pending"},"m7":{"client":{"type":"success","data":[]},"server":"pending"},"m8":{"client":{"type":"success","data":[]},"server":"pending"},"m9":{"client":{"type":"success","data":[]},"server":"pending"}}}]}, +{"name":"aggregate: a junction max and a junction count with a where are the server's","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.labelMax"},{"op":"materialize","view":"v1","query":"aggregates.bugLabelCounts"},{"op":"materialize","view":"users","query":"users.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"1164v3x06h3d4f"},{"op":"put","hash":"1bd6x3r0guu0ws"}],"rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:1164v3x06h3d4f:labels","value":{"issueId":"i1","_0_value":"ui","_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"aggregate:1164v3x06h3d4f:labels","value":{"issueId":"i2","_0_value":null,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"aggregate:1164v3x06h3d4f:labels","value":{"issueId":"i3","_0_value":"bug","_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:1bd6x3r0guu0ws:labels","value":{"issueId":"i1","_0_value":1,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"aggregate:1bd6x3r0guu0ws:labels","value":{"issueId":"i2","_0_value":0,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"aggregate:1bd6x3r0guu0ws:labels","value":{"issueId":"i3","_0_value":1,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"mutate","mutation":"m1","mutator":"aggregates.read","args":{"ops":[{"op":"insert","table":"issueLabel","value":{"issueId":"i2","labelId":"l1"}}],"queries":[]}},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2","lastMutationIDChanges":{"$clientID":1},"rowsPatch":[{"op":"put","tableName":"aggregate:1164v3x06h3d4f:labels","value":{"issueId":"i2","_0_value":"bug","_0_version":"02"}},{"op":"put","tableName":"aggregate:1bd6x3r0guu0ws:labels","value":{"issueId":"i2","_0_value":1,"_0_version":"02"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1164v3x06h3d4f","name":"aggregates.labelMax","args":[],"ttl":300000},{"op":"put","hash":"1bd6x3r0guu0ws","name":"aggregates.bugLabelCounts","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1164v3x06h3d4f","name":"aggregates.labelMax","args":[],"ttl":300000},{"op":"put","hash":"1bd6x3r0guu0ws","name":"aggregates.bugLabelCounts","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"labels":"ui"},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"labels":null},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"labels":"bug"}],"resultType":"complete","notifications":2},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"labels":1},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"labels":0},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"labels":1}],"resultType":"complete","notifications":2},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[{"op":"insert","table":"issueLabel","value":{"issueId":"i2","labelId":"l1"}}],"queries":[]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"labels":"ui"},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"labels":null},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"labels":"bug"}],"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"labels":1},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"labels":0},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"labels":1}],"resultType":"complete","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"labels":"ui"},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"labels":null},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"labels":"bug"}],"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"labels":1},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"labels":0},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"labels":1}],"resultType":"complete","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"labels":"ui"},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"labels":null},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"labels":"bug"}],"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"labels":1},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"labels":0},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"labels":1}],"resultType":"complete","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"labels":"ui"},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"labels":null},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"labels":"bug"}],"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"labels":1},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"labels":0},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"labels":1}],"resultType":"complete","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"labels":"ui"},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"labels":"bug"},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"labels":"bug"}],"resultType":"complete","notifications":1},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"labels":1},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"labels":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"labels":1}],"resultType":"complete","notifications":1},"users":{"data":[],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":{"type":"success"}}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"labels":"ui"},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"labels":"bug"},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"labels":"bug"}],"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"labels":1},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"labels":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"labels":1}],"resultType":"complete","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":[]},"server":{"type":"success"}}}}]}, +{"name":"aggregate: a mutator computes aggregates the server has not sent from its own writes","steps":[{"op":"advance","ms":0},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"mutate","mutation":"m1","mutator":"aggregates.record","args":{"queries":[{"name":"aggregates.issueCount"},{"name":"aggregates.latestIssueTime"},{"name":"aggregates.openIssueCount"},{"name":"aggregates.issueStates"},{"name":"aggregates.issueStateCount"},{"name":"aggregates.countByState"},{"name":"aggregates.timeByState"},{"name":"aggregates.commentAndLabelCounts"},{"name":"aggregates.commentTimeSums"}],"ops":[{"op":"insert","table":"issue","value":{"id":"1","title":"1","description":"","closed":false,"ownerId":null,"createdAt":1}},{"op":"insert","table":"issue","value":{"id":"2","title":"2","description":"","closed":true,"ownerId":null,"createdAt":5}},{"op":"insert","table":"issue","value":{"id":"3","title":"3","description":"","closed":false,"ownerId":null,"createdAt":2}},{"op":"insert","table":"comment","value":{"id":"c1","authorId":"u1","issueId":"1","text":"","createdAt":2}},{"op":"insert","table":"comment","value":{"id":"c2","authorId":"u1","issueId":"1","text":"","createdAt":3}},{"op":"insert","table":"label","value":{"id":"l1","name":"bug"}},{"op":"insert","table":"issueLabel","value":{"issueId":"1","labelId":"l1"}},{"op":"insert","table":"issueLabel","value":{"issueId":"2","labelId":"l2"}}]}},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connected"}},{"state":{"name":"connected"}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"aggregates.record","args":[{"queries":[{"name":"aggregates.issueCount"},{"name":"aggregates.latestIssueTime"},{"name":"aggregates.openIssueCount"},{"name":"aggregates.issueStates"},{"name":"aggregates.issueStateCount"},{"name":"aggregates.countByState"},{"name":"aggregates.timeByState"},{"name":"aggregates.commentAndLabelCounts"},{"name":"aggregates.commentTimeSums"}],"ops":[{"op":"insert","table":"issue","value":{"id":"1","title":"1","description":"","closed":false,"ownerId":null,"createdAt":1}},{"op":"insert","table":"issue","value":{"id":"2","title":"2","description":"","closed":true,"ownerId":null,"createdAt":5}},{"op":"insert","table":"issue","value":{"id":"3","title":"3","description":"","closed":false,"ownerId":null,"createdAt":2}},{"op":"insert","table":"comment","value":{"id":"c1","authorId":"u1","issueId":"1","text":"","createdAt":2}},{"op":"insert","table":"comment","value":{"id":"c2","authorId":"u1","issueId":"1","text":"","createdAt":3}},{"op":"insert","table":"label","value":{"id":"l1","name":"bug"}},{"op":"insert","table":"issueLabel","value":{"issueId":"1","labelId":"l1"}},{"op":"insert","table":"issueLabel","value":{"issueId":"2","labelId":"l2"}}]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"mutations":{"m1":{"client":{"type":"success","data":{"before":[0,null,0,[],0,[],[],[],[]],"after":[3,5,2,[{"closed":false},{"closed":true}],2,[{"closed":false,"count":2},{"closed":true,"count":1}],[{"closed":false,"sum":3},{"closed":true,"sum":5}],[{"id":"1","title":"1","description":"","closed":false,"ownerId":null,"createdAt":1,"comments":2,"labels":1},{"id":"2","title":"2","description":"","closed":true,"ownerId":null,"createdAt":5,"comments":0,"labels":0},{"id":"3","title":"3","description":"","closed":false,"ownerId":null,"createdAt":2,"comments":0,"labels":0}],[{"id":"1","title":"1","description":"","closed":false,"ownerId":null,"createdAt":1,"comments":5},{"id":"2","title":"2","description":"","closed":true,"ownerId":null,"createdAt":5,"comments":null},{"id":"3","title":"3","description":"","closed":false,"ownerId":null,"createdAt":2,"comments":null}]]}},"server":"pending"}}},{"state":{"name":"connected"},"mutations":{"m1":{"client":{"type":"success","data":{"before":[0,null,0,[],0,[],[],[],[]],"after":[3,5,2,[{"closed":false},{"closed":true}],2,[{"closed":false,"count":2},{"closed":true,"count":1}],[{"closed":false,"sum":3},{"closed":true,"sum":5}],[{"id":"1","title":"1","description":"","closed":false,"ownerId":null,"createdAt":1,"comments":2,"labels":1},{"id":"2","title":"2","description":"","closed":true,"ownerId":null,"createdAt":5,"comments":0,"labels":0},{"id":"3","title":"3","description":"","closed":false,"ownerId":null,"createdAt":2,"comments":0,"labels":0}],[{"id":"1","title":"1","description":"","closed":false,"ownerId":null,"createdAt":1,"comments":5},{"id":"2","title":"2","description":"","closed":true,"ownerId":null,"createdAt":5,"comments":null},{"id":"3","title":"3","description":"","closed":false,"ownerId":null,"createdAt":2,"comments":null}]]}},"server":"pending"}}}]}, +{"name":"aggregate: once the server drops a groupBy, a new row adds no group","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.countByState"},{"op":"materialize","view":"users","query":"users.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0ovq3ue0294kbv"}],"rowsPatch":[{"op":"put","tableName":"aggregate:0ovq3ue0294kbv:#group","value":{"closed":false,"_0_key":"false","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"aggregate:0ovq3ue0294kbv:#group","value":{"closed":true,"_0_key":"true","_0_value":1,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"destroy","view":"v0"},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2","gotQueriesPatch":[{"op":"del","hash":"0ovq3ue0294kbv"}],"rowsPatch":[{"op":"del","tableName":"aggregate:0ovq3ue0294kbv:#group","id":{"_0_key":"false"}},{"op":"del","tableName":"aggregate:0ovq3ue0294kbv:#group","id":{"_0_key":"true"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]},{"op":"mutate","mutation":"m1","mutator":"issue.create","args":{"id":"i9","closed":true}},{"op":"advance","ms":10},{"op":"materialize","view":"w","query":"aggregates.countByState"},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0ovq3ue0294kbv","name":"aggregates.countByState","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0ovq3ue0294kbv","name":"aggregates.countByState","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"count":2},{"closed":true,"count":1}],"resultType":"complete","notifications":2},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"del","hash":"0ovq3ue0294kbv"}]}]],"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["push",{"timestamp":1700000000020,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000020,"id":1,"clientID":"$clientID","name":"issue.create","args":[{"id":"i9","closed":true}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0},"w":{"data":[],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0ovq3ue0294kbv","name":"aggregates.countByState","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0},"w":{"data":[],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}}]}, +{"name":"aggregate: a mutator's read of a synced groupBy registers nothing","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.countByState"},{"op":"materialize","view":"users","query":"users.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0ovq3ue0294kbv"}],"rowsPatch":[]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"destroy","view":"v0"},{"op":"advance","ms":10},{"op":"mutate","mutation":"m1","mutator":"aggregates.read","args":{"ops":[],"queries":[{"name":"aggregates.countByState"}]}},{"op":"mutate","mutation":"m2","mutator":"issue.create","args":{"id":"i9","closed":true}},{"op":"advance","ms":10},{"op":"materialize","view":"w","query":"aggregates.countByState"},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0ovq3ue0294kbv","name":"aggregates.countByState","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0ovq3ue0294kbv","name":"aggregates.countByState","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"complete","notifications":1},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"del","hash":"0ovq3ue0294kbv"}]}]],"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["push",{"timestamp":1700000000020,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000020,"id":1,"clientID":"$clientID","name":"aggregates.read","args":[{"ops":[],"queries":[{"name":"aggregates.countByState"}]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":[[]]},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000020,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000020,"id":2,"clientID":"$clientID","name":"issue.create","args":[{"id":"i9","closed":true}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":[[]]},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":[[]]},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0},"w":{"data":[],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success","data":[[]]},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0ovq3ue0294kbv","name":"aggregates.countByState","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"users":{"data":[],"resultType":"unknown","notifications":0},"w":{"data":[],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success","data":[[]]},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}}]}, +{"name":"aggregate: after a restart, a mutation made before the view moves its group at the next rebase","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.countByState"},{"op":"materialize","view":"users","query":"users.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0ovq3ue0294kbv"}],"rowsPatch":[{"op":"put","tableName":"aggregate:0ovq3ue0294kbv:#group","value":{"closed":false,"_0_key":"false","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"aggregate:0ovq3ue0294kbv:#group","value":{"closed":true,"_0_key":"true","_0_value":1,"_0_version":"01"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"advance","ms":2000},{"op":"restart"},{"op":"mutate","mutation":"m1","mutator":"issue.create","args":{"id":"i9","closed":true}},{"op":"advance","ms":10},{"op":"materialize","view":"w","query":"aggregates.countByState"},{"op":"advance","ms":0},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2","rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i8","title":"I8","description":"","closed":false,"owner_id":null,"createdAt":1}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0ovq3ue0294kbv","name":"aggregates.countByState","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0ovq3ue0294kbv","name":"aggregates.countByState","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"count":2},{"closed":true,"count":1}],"resultType":"complete","notifications":2},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"closed":false,"count":2},{"closed":true,"count":1}],"resultType":"complete","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie","01"],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"activeClients":["$clientID"]}]}}],"closed":[0],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connecting"},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connecting"},"views":{"w":{"data":[{"closed":false,"count":2},{"closed":true,"count":1}],"resultType":"cached","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connecting"},"views":{"w":{"data":[{"closed":false,"count":2},{"closed":true,"count":1}],"resultType":"cached","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0ovq3ue0294kbv","name":"aggregates.countByState","args":[],"ttl":300000}]}],["push",{"timestamp":1700000002020,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000002010,"id":1,"clientID":"$clientID","name":"issue.create","args":[{"id":"i9","closed":true}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"w":{"data":[{"closed":false,"count":2},{"closed":true,"count":1}],"resultType":"cached","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"w":{"data":[{"closed":false,"count":2},{"closed":true,"count":1}],"resultType":"cached","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"w":{"data":[{"closed":false,"count":2},{"closed":true,"count":1}],"resultType":"cached","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"w":{"data":[{"closed":false,"count":2},{"closed":true,"count":2}],"resultType":"complete","notifications":2}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0ovq3ue0294kbv","name":"aggregates.countByState","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"w":{"data":[{"closed":false,"count":2},{"closed":true,"count":2}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}}]}, +{"name":"aggregate: pokes put and delete aggregate rows, and drop a table not in the schema","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.issueCount"},{"op":"materialize","view":"v1","query":"aggregates.commentCounts"},{"op":"materialize","view":"users","query":"users.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0oql89w09s2pr4"},{"op":"put","hash":"0u3s9wi0kzvflr"}],"rowsPatch":[{"op":"put","tableName":"aggregate:0oql89w09s2pr4","value":{"_0_key":0,"_0_value":3,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i1","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i2","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i3","_0_value":0,"_0_version":"01"}},{"op":"put","tableName":"notInSchema","value":{"id":"x"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2","rowsPatch":[{"op":"del","tableName":"aggregate:0oql89w09s2pr4","id":{"_0_key":0}},{"op":"del","tableName":"aggregate:0u3s9wi0kzvflr:comments","id":{"issue_id":"i1"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0oql89w09s2pr4","name":"aggregates.issueCount","args":[],"ttl":300000},{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0oql89w09s2pr4","name":"aggregates.issueCount","args":[],"ttl":300000},{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000},{"op":"put","hash":"1864qec0oaacid","name":"users.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":3,"resultType":"complete","notifications":2},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":2},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":3,"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":3,"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":3,"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"complete","notifications":1},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":0},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":1},"users":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":0},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0},"users":{"data":[],"resultType":"unknown","notifications":0}}}]}, {"name":"mutate: an optimistic write shows at once and is pushed once","steps":[{"op":"materialize","view":"v","query":"issues.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"mutate","mutation":"m1","mutator":"issue.create","args":{"id":"i1","title":"T","ownerId":"u1"}},{"op":"advance","ms":10},{"op":"mutate","mutation":"m2","mutator":"comment.add","args":{"id":"c1","issueId":"i1"}},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["push",{"timestamp":1700000000000,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000000,"id":1,"clientID":"$clientID","name":"issue.create","args":[{"id":"i1","title":"T","ownerId":"u1"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"T","description":"","closed":false,"ownerId":"u1","createdAt":1}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"T","description":"","closed":false,"ownerId":"u1","createdAt":1}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":2,"clientID":"$clientID","name":"comment.add","args":[{"id":"c1","issueId":"i1"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"T","description":"","closed":false,"ownerId":"u1","createdAt":1}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"T","description":"","closed":false,"ownerId":"u1","createdAt":1}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}}]}, {"name":"mutate: mutations made while connecting are pushed once connected","steps":[{"op":"materialize","view":"v","query":"issues.all"},{"op":"mutate","mutation":"m1","mutator":"issue.create","args":{"id":"i1"}},{"op":"mutate","mutation":"m2","mutator":"issue.create","args":{"id":"i2"}},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v":{"data":[{"id":"i1","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connecting"},"views":{"v":{"data":[{"id":"i1","title":"","description":"","closed":false,"ownerId":null,"createdAt":1},{"id":"i2","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000000,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000000,"id":1,"clientID":"$clientID","name":"issue.create","args":[{"id":"i1"}]}],"pushVersion":1,"requestID":"$requestID"}],["push",{"timestamp":1700000000000,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000000,"id":2,"clientID":"$clientID","name":"issue.create","args":[{"id":"i2"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"","description":"","closed":false,"ownerId":null,"createdAt":1},{"id":"i2","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"","description":"","closed":false,"ownerId":null,"createdAt":1},{"id":"i2","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}}]}, {"name":"mutate: a reconnect pushes pending mutations again and sends lmid","steps":[{"op":"materialize","view":"v","query":"issues.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"mutate","mutation":"m1","mutator":"issue.create","args":{"id":"i1"}},{"op":"mutate","mutation":"m2","mutator":"issue.create","args":{"id":"i2"}},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","lastMutationIDChanges":{"$clientID":1},"gotQueriesPatch":[{"op":"put","hash":"1y7zr0i1xir4ek"}],"rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":null,"createdAt":1}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"socketClose","code":1006},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["push",{"timestamp":1700000000000,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000000,"id":1,"clientID":"$clientID","name":"issue.create","args":[{"id":"i1"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000000,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000000,"id":2,"clientID":"$clientID","name":"issue.create","args":[{"id":"i2"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"","description":"","closed":false,"ownerId":null,"createdAt":1},{"id":"i2","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"","description":"","closed":false,"ownerId":null,"createdAt":1},{"id":"i2","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"","description":"","closed":false,"ownerId":null,"createdAt":1},{"id":"i2","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1},{"id":"i2","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"complete","notifications":2}},"mutations":{"m1":{"client":{"type":"success"},"server":{"type":"success"}},"m2":{"client":{"type":"success"},"server":"pending"}}},{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie","01"],["lmid","1"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}],"activeClients":["$clientID"]}]}}],"closed":[0],"state":{"name":"connecting"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1},{"id":"i2","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":{"type":"success"}},"m2":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000000,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000000,"id":2,"clientID":"$clientID","name":"issue.create","args":[{"id":"i2"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1},{"id":"i2","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":{"type":"success"}},"m2":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":null,"createdAt":1},{"id":"i2","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":{"type":"success"}},"m2":{"client":{"type":"success"},"server":"pending"}}}]}, diff --git a/swift/Sources/Zero/Client/Engine.swift b/swift/Sources/Zero/Client/Engine.swift index 968c04646b..2180d74c70 100644 --- a/swift/Sources/Zero/Client/Engine.swift +++ b/swift/Sources/Zero/Client/Engine.swift @@ -124,6 +124,9 @@ final class Engine { private var deletedClients: DeleteClientsBody? private var lastMutationIDReceived: Double = 0 private var lastMutationIDsSent: [String: Double] = [:] + /// The last mutation ID of each client pending at launch: the mutations + /// `rebasePending` stands in for JS's persisted writes of. + private var launchPendingIDs: [String: Double] = [:] private var additionalConnectParams: [(String, String)]? private var currentAttempt: ConnectAttempt? private var connectionReady = ReadyPromise() @@ -286,6 +289,7 @@ final class Engine { // on it. ivmMain.apply(KVDiff.between(KVMap(), store.snapshot.map)) if !store.pending.isEmpty { + for m in store.pending { launchPendingIDs[m.clientID] = m.id } let (main, replayed, touched, _) = replay( store.pending, over: store.snapshot.map, branch: ivmMain.fork()) ivmMain.apply( @@ -1576,10 +1580,14 @@ final class Engine { /// Runs the pending mutations again over the server snapshot, as a poke /// that changes nothing would, so they move the synced aggregates a query - /// registered since they last ran. Not while a mutator runs: the next - /// rebase replays them then. + /// registered since they last ran. Only while a mutation replayed at + /// launch is pending: JS kept the moves it made before the restart, but a + /// mutation made since moved only what was registered then, until the + /// next rebase. Not while a mutator runs: the next rebase replays them then. private func rebasePending() throws { - guard !writeLocked, !store.pending.isEmpty else { return } + guard !writeLocked, + store.pending.contains(where: { $0.id <= launchPendingIDs[$0.clientID] ?? 0 }) + else { return } try withWriteLock { let snapshot = store.snapshot let touched = store.pendingWrites diff --git a/swift/Sources/Zero/Client/IVMBranch.swift b/swift/Sources/Zero/Client/IVMBranch.swift index 2ae27c56ac..c046e103bf 100644 --- a/swift/Sources/Zero/Client/IVMBranch.swift +++ b/swift/Sources/Zero/Client/IVMBranch.swift @@ -81,7 +81,8 @@ final class IVMBranch { /// the last call. Swift only: JS persists a pending mutation's writes, so /// after a restart its view still has the moves the mutation made. Swift /// stores the mutation and replays it at launch, before any query - /// registers, so the client rebases the pending mutations once one does. + /// registers, so the client rebases the pending mutations once one does, + /// while one replayed at launch is pending. func takeNewRegistration() -> Bool { defer { newRegistration = false } return newRegistration diff --git a/swift/Tests/ConformanceTests/ClientApp.swift b/swift/Tests/ConformanceTests/ClientApp.swift index 110adaacc3..158b49044b 100644 --- a/swift/Tests/ConformanceTests/ClientApp.swift +++ b/swift/Tests/ConformanceTests/ClientApp.swift @@ -47,6 +47,47 @@ enum ClientApp { "aggregates.owners": { _ in zql("issue").distinct("ownerId") }, "aggregates.commentsByIssue": { _ in zql("comment").groupBy("issueId").count() }, "aggregates.timeByAuthor": { _ in zql("comment").groupBy("authorId").sum("createdAt") }, + // From zero-client's aggregate-read-your-writes, group-read-your-writes, + // context, crud-impl and custom tests. + "aggregates.issueWithCommentCount": { args in + zql("issue").where("id", args ?? .null).related("comments") { $0.count() }.one() + }, + "aggregates.openByState": { _ in + zql("issue").where("closed", false).groupBy("closed").count() + }, + "aggregates.issueStates": { _ in zql("issue").distinct("closed") }, + "aggregates.issueStateCount": { _ in zql("issue").distinct("closed").count() }, + "aggregates.countByState": { _ in zql("issue").groupBy("closed").count() }, + "aggregates.timeByState": { _ in zql("issue").groupBy("closed").sum("createdAt") }, + "aggregates.avgTimeByState": { _ in zql("issue").groupBy("closed").avg("createdAt") }, + "aggregates.issuesByOwner": { _ in + zql("issue").groupBy("closed", "ownerId").count().orderBy("ownerId", .desc) + }, + "aggregates.latestIssueTime": { _ in zql("issue").max("createdAt") }, + "aggregates.commentAndLabelCounts": { _ in + zql("issue") + .related("comments") { $0.count() } + .related("labels") { $0.count() } + .orderBy("id", .asc) + }, + "aggregates.commentTimeSums": { _ in + zql("issue").related("comments") { $0.sum("createdAt") }.orderBy("id", .asc) + }, + "aggregates.userIssueCounts": { _ in + zql("user").related("issues") { $0.count() }.orderBy("id", .asc) + }, + "aggregates.pointsByName": { _ in + zql("user").groupBy("name").sum(json: "metadata", "points") + }, + "aggregates.avgPointsByName": { _ in + zql("user").groupBy("name").avg(json: "metadata", "points") + }, + "aggregates.labelMax": { _ in + zql("issue").related("labels") { $0.max("name") }.orderBy("id", .asc) + }, + "aggregates.bugLabelCounts": { _ in + zql("issue").related("labels") { $0.where("name", "bug").count() }.orderBy("id", .asc) + }, "issueLabels.all": { _ in zql("issueLabel").orderBy("issueId", .asc).orderBy("labelId", .asc) }, @@ -58,6 +99,28 @@ enum ClientApp { return build(args).nameAndArgs(name, args.map { [$0] } ?? []) } + /// Runs the CRUD operations `ops` through `tx`. + @MainActor static func runOps(_ tx: Transaction, _ ops: JSONValue?) throws { + for o in ops?.arrayValue ?? [] { + let table = tx.mutate.table(o["table"]?.stringValue ?? "") + let value = Row(o["value"]?.objectValue ?? [:]) + switch o["op"]?.stringValue { + case "insert": try table.insert(value) + case "upsert": try table.upsert(value) + case "update": try table.update(value) + case "delete": try table.delete(value) + default: throw Failure("Unknown op") + } + } + } + + /// What each named query in `refs` reads through `tx`. + @MainActor static func readAll(_ tx: Transaction, _ refs: JSONValue?) throws -> [JSONValue] { + try (refs?.arrayValue ?? []).map { + try tx.run(request($0["name"]?.stringValue ?? "", $0["args"])).json ?? .null + } + } + struct Failure: Error, CustomStringConvertible { let description: String init(_ description: String) { self.description = description } @@ -173,22 +236,23 @@ enum ClientApp { // Runs CRUD operations, then each named query through the transaction, // and returns what they read (`aggregates.read` in app.ts). JSONMutator(name: "aggregates.read") { tx, args in - for o in args?["ops"]?.arrayValue ?? [] { - let table = tx.mutate.table(o["table"]?.stringValue ?? "") - let value = Row(o["value"]?.objectValue ?? [:]) - switch o["op"]?.stringValue { - case "insert": try table.insert(value) - case "upsert": try table.upsert(value) - case "update": try table.update(value) - case "delete": try table.delete(value) - default: throw Failure("Unknown op") - } - } - var out: [JSONValue] = [] - for q in args?["queries"]?.arrayValue ?? [] { - out.append(try tx.run(request(q["name"]?.stringValue ?? "", q["args"])).json ?? .null) + try runOps(tx, args?["ops"]) + return .array(try readAll(tx, args?["queries"])) + }, + // Reads the queries, runs the operations, reads them again, and returns + // both reads; with `record`, also upserts that user with the reason of + // the run and the reads (`aggregates.record` in app.ts). + JSONMutator(name: "aggregates.record") { tx, args in + let before = try readAll(tx, args?["queries"]) + try runOps(tx, args?["ops"]) + let after = try readAll(tx, args?["queries"]) + let reads: JSONValue = ["before": .array(before), "after": .array(after)] + if let id = args?["record"]?.stringValue { + try tx.mutate.table("user").upsert([ + "id": .string(id), "name": .string(tx.reason.rawValue), "metadata": reads, + ]) } - return .array(out) + return reads }, JSONMutator(name: "comment.add") { tx, args in var row: Row = [ diff --git a/swift/Tests/ConformanceTests/PrimitiveConformanceTests.swift b/swift/Tests/ConformanceTests/PrimitiveConformanceTests.swift index 7ea098ba9a..de1fbb5975 100644 --- a/swift/Tests/ConformanceTests/PrimitiveConformanceTests.swift +++ b/swift/Tests/ConformanceTests/PrimitiveConformanceTests.swift @@ -68,6 +68,19 @@ struct PrimitiveConformanceTests { } } + @Test func aggregateRowKey() throws { + for c in try Vectors.cases("aggregate-row-key") { + let table = c["table"]!.stringValue! + let row = c["row"]!.objectValue! + #expect( + Keys.aggregateRowKeyColumns(table: table, columns: row.keys) + == c["columns"]!.arrayValue!.map { $0.stringValue! }, "\(table) \(row)") + let key = try? Keys.aggregateRowKey(table: table, row: row) + #expect(key == c["key"]?.stringValue, "\(table) \(row)") + #expect((key == nil) == (c["throws"]?.boolValue ?? false), "\(table) \(row)") + } + } + @Test func like() throws { for c in try Vectors.cases("like") { let pattern = c["pattern"]!.stringValue! From e1ce5c1a84eb33ec1c7dfd7e96b6731eea311733 Mon Sep 17 00:00:00 2001 From: Amp Date: Mon, 2 Nov 2026 21:35:55 +0000 Subject: [PATCH 3/3] fix(zero-swift): persist pending mutations' aggregate writes as JS does After a restart, the rebase Swift ran when a synced aggregate first registered diverged from JS in two ways. A mutation made after launch moved the new aggregate at once. A mutation from before the restart, made while the query wasn't registered, was replayed into it. JS persists each pending mutation's commit about a second after a change (persistDD31), so its a/ rows hold the moves of the aggregates registered at that persist. Swift now stores those a/ writes with each mutation (mutations.aggregate_writes, added with a guarded ALTER), refreshes them on JS's persist schedule, and puts them back when it replays the mutation at launch. The rebase on registration is gone. Adds the bug hunt's client scenarios (bughunt-client) and its seeded client fuzz (seed 1 x 150 by default) to BugHuntTests. Co-authored-by: tmm Amp-Thread-ID: https://ampcode.com/threads/T-01a19a37-5aa9-7256-bff5-cdc47c01a1fe --- .changeset/swift-synced-aggregates.md | 2 +- packages/zero-conformance/src/client/app.ts | 40 ++ .../src/client/bughunt.test.ts | 493 ++++++++++++++++++ .../src/client/scenarios/bughunt.ts | 370 +++++++++++++ .../src/client/server-rows.ts | 4 +- .../vectors/bughunt-client.json | 14 + swift/DESIGN.md | 2 +- swift/Sources/Zero/Client/Engine.swift | 155 ++++-- swift/Sources/Zero/Client/IVMBranch.swift | 15 - swift/Sources/Zero/Client/QueryContext.swift | 8 - .../Zero/Storage/ReplicaDatabase.swift | 64 ++- .../Tests/ConformanceTests/BugHuntTests.swift | 67 ++- swift/Tests/ConformanceTests/ClientApp.swift | 25 + 13 files changed, 1190 insertions(+), 69 deletions(-) create mode 100644 packages/zero-conformance/src/client/bughunt.test.ts create mode 100644 packages/zero-conformance/src/client/scenarios/bughunt.ts create mode 100644 packages/zero-conformance/vectors/bughunt-client.json diff --git a/.changeset/swift-synced-aggregates.md b/.changeset/swift-synced-aggregates.md index c1340dbb60..da6712afe0 100644 --- a/.changeset/swift-synced-aggregates.md +++ b/.changeset/swift-synced-aggregates.md @@ -2,4 +2,4 @@ 'zero-swift': patch --- -Aggregates, `distinct()` and `groupBy()` sync from zero-cache: a named query's view reads the rows the server computes, stored under `a/`, instead of dropping them from pokes. Until the server answers, a view computes nothing and shows the empty value (`0` for a count). A local mutation moves a synced relationship aggregate or grouped count at once, as the JS client's optimistic deltas do, and the server's rows replace them when it confirms. A mutator's `tx.run` reads the synced rows for a query the server has answered, and computes them otherwise. While mutations made before a relaunch are pending, they are rebased when a synced aggregate's query first materializes, so the relaunched client keeps their moves. +Aggregates, `distinct()` and `groupBy()` sync from zero-cache: a named query's view reads the rows the server computes, stored under `a/`, instead of dropping them from pokes. Until the server answers, a view computes nothing and shows the empty value (`0` for a count). A local mutation moves a synced relationship aggregate or grouped count at once, as the JS client's optimistic deltas do, and the server's rows replace them when it confirms. A mutator's `tx.run` reads the synced rows for a query the server has answered, and computes them otherwise. A pending mutation's moves of synced aggregates are stored with it, as JS persists them about a second after a change, for the aggregates registered then, so a relaunched client shows the moves the JS client would. diff --git a/packages/zero-conformance/src/client/app.ts b/packages/zero-conformance/src/client/app.ts index 02ac4179fd..0b6a91ba44 100644 --- a/packages/zero-conformance/src/client/app.ts +++ b/packages/zero-conformance/src/client/app.ts @@ -144,6 +144,46 @@ export const queries = defineQueries({ .orderBy('id', 'asc'), ), }, + // More aggregates, for the aggregate bug hunt (`bughunt.test.ts`). + bughunt: { + allComments: defineQuery(() => zql.comment.orderBy('id', 'asc')), + allLabels: defineQuery(() => zql.label.orderBy('id', 'asc')), + maxCommentText: defineQuery(() => zql.comment.max('text')), + minIssueTitle: defineQuery(() => zql.issue.min('title')), + pointsSum: defineQuery(() => + // oxlint-disable-next-line @typescript-eslint/no-explicit-any + zql.user.sum(({json}) => (json as any)('metadata', 'points')), + ), + ownerIssueCounts: defineQuery(() => + zql.issue + .related('owner', o => o.related('issues', i => i.count())) + .orderBy('id', 'asc'), + ), + commentAvgWhere: defineQuery(() => + zql.issue + .related('comments', q => q.where('createdAt', '>', 3).avg('createdAt')) + .orderBy('id', 'asc'), + ), + commentsByAuthorAndIssue: defineQuery(() => + zql.comment.groupBy('authorId', 'issueId').count(), + ), + avgTimeByIssueWhere: defineQuery(() => + zql.comment + .where('authorId', '!=', 'u3') + .groupBy('issueId') + .avg('createdAt'), + ), + commentCountsLimited: defineQuery(() => + zql.issue + .related('comments', q => q.count()) + .orderBy('createdAt', 'desc') + .limit(3), + ), + ownerCount: defineQuery(() => zql.issue.distinct('ownerId').count()), + sumTimeByOwner: defineQuery(() => + zql.issue.groupBy('ownerId').sum('createdAt'), + ), + }, // A table with a compound primary key. issueLabels: { all: defineQuery(() => diff --git a/packages/zero-conformance/src/client/bughunt.test.ts b/packages/zero-conformance/src/client/bughunt.test.ts new file mode 100644 index 0000000000..4d1af3f292 --- /dev/null +++ b/packages/zero-conformance/src/client/bughunt.test.ts @@ -0,0 +1,493 @@ +/** + * Aggregate bug hunt: seeded random client scenarios over the synced + * aggregate queries of `app.ts`. A scenario syncs a few queries, then mixes + * local mutations (with `tx.run` reads of the aggregates), server + * confirmations of some of them, other clients' writes, dropped and + * re-added queries and restarts. Every server row comes from JS's own + * pipeline (`server-rows.ts`), as zero-cache would stream it. + * + * `AGG_FUZZ_SEED` and `AGG_FUZZ_CASES` widen the search. The corpus goes to + * `generated/client-aggregates-fuzz.json`; `BugHuntTests.swift` replays it. + */ +import {test} from 'vitest'; +import type {ReadonlyJSONValue} from '../../../shared/src/json.ts'; +import {interestingStrings, Random} from '../random.ts'; +import {emitGeneratedVectors, emitVectors} from '../vectors.ts'; +import { + runScenario, + START_TIME, + type Scenario, + type Step, + type StepResult, +} from './harness.ts'; +import {bughuntScenarios} from './scenarios/bughunt.ts'; +import {advance, connected, queryHash, start} from './scenarios/helpers.ts'; +import {syncedRows, type ServerData, type SyncedRow} from './server-rows.ts'; + +type JSONObject = {readonly [key: string]: ReadonlyJSONValue}; +type QueryRef = {name: string; args?: ReadonlyJSONValue}; +type CRUD = { + op: 'insert' | 'upsert' | 'update' | 'delete'; + table: string; + value: JSONObject; +}; + +/** The aggregate queries a scenario syncs some of. */ +export const aggregateRefs: QueryRef[] = [ + ...[ + 'aggregates.issueCount', + 'aggregates.openIssueCount', + 'aggregates.commentCounts', + 'aggregates.commentTimes', + 'aggregates.labelCounts', + 'aggregates.owners', + 'aggregates.commentsByIssue', + 'aggregates.timeByAuthor', + 'aggregates.openByState', + 'aggregates.issueStates', + 'aggregates.issueStateCount', + 'aggregates.countByState', + 'aggregates.timeByState', + 'aggregates.avgTimeByState', + 'aggregates.issuesByOwner', + 'aggregates.latestIssueTime', + 'aggregates.commentAndLabelCounts', + 'aggregates.commentTimeSums', + 'aggregates.userIssueCounts', + 'aggregates.pointsByName', + 'aggregates.avgPointsByName', + 'aggregates.labelMax', + 'aggregates.bugLabelCounts', + 'bughunt.maxCommentText', + 'bughunt.minIssueTitle', + 'bughunt.pointsSum', + 'bughunt.ownerIssueCounts', + 'bughunt.commentAvgWhere', + 'bughunt.commentsByAuthorAndIssue', + 'bughunt.avgTimeByIssueWhere', + 'bughunt.commentCountsLimited', + 'bughunt.ownerCount', + 'bughunt.sumTimeByOwner', + ].map((name): QueryRef => ({name})), + {name: 'aggregates.issueWithCommentCount', args: 'i1'}, + {name: 'aggregates.issueWithCommentCount', args: 'i2'}, +]; + +/** Queries of rows, which give the client rows to edit and delete. */ +const rowRefs: QueryRef[] = [ + {name: 'issues.all'}, + {name: 'users.all'}, + {name: 'bughunt.allComments'}, + {name: 'issueLabels.all'}, + {name: 'bughunt.allLabels'}, +]; + +const issueIDs = ['i1', 'i2', 'i3', 'i4', 'i5']; +const commentIDs = ['c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8']; +const userIDs = ['u1', 'u2', 'u3']; +const labelIDs = ['l1', 'l2', 'l3']; +const numbers = [0, 1, 2, 3, 4, 5, 7, 0.1, 0.2, 0.3, -1, 2.5, 2 ** 53, 1e21]; +const names = ['A', 'B', 'a', '', '\u00e9', 'e\u0301', '\u{1f600}']; +const texts = ['', 'a', 'b', 'B', 'z', ...interestingStrings.slice(14, 30)]; + +function metadata(r: Random): ReadonlyJSONValue { + return r.pick([ + null, + {points: r.pick(numbers)}, + {points: r.pick(numbers)}, + {points: '7'}, + {other: 1}, + {points: null}, + [1], + ]); +} + +/** A full row of `table` in client names. */ +function clientRow(r: Random, table: string, id: string): JSONObject { + switch (table) { + case 'issue': + return { + id, + title: r.pick(texts), + description: '', + closed: r.bool(), + ownerId: r.bool(0.2) ? null : r.pick([...userIDs, 'u9']), + createdAt: r.pick(numbers), + }; + case 'comment': + return { + id, + authorId: r.pick(userIDs), + issueId: r.bool(0.1) ? 'i9' : r.pick(issueIDs), + text: r.pick(texts), + createdAt: r.pick(numbers), + }; + case 'user': + return {id, name: r.pick(names), metadata: metadata(r)}; + case 'label': + return {id, name: r.pick(['bug', 'ui', 'a', 'z'])}; + default: + throw new Error(table); + } +} + +const serverTable: Record = { + issue: 'issues', + comment: 'comments', + user: 'users', + label: 'label', + issueLabel: 'issueLabel', +}; +const serverColumn: Record = { + 'issue.ownerId': 'owner_id', + 'comment.issueId': 'issue_id', +}; +const primaryKey: Record = { + issue: ['id'], + comment: ['id'], + user: ['id'], + label: ['id'], + issueLabel: ['issueId', 'labelId'], +}; + +function toServer(table: string, row: JSONObject): JSONObject { + return Object.fromEntries( + Object.entries(row).map(([k, v]) => [ + serverColumn[`${table}.${k}`] ?? k, + v, + ]), + ); +} + +/** Applies a CRUD op, as the server's mutator would, to `data`. */ +function applyServer(data: ServerData, o: CRUD): ServerData { + const t = serverTable[o.table]; + const rows = data[t] ?? []; + const pk = primaryKey[o.table].map(k => serverColumn[`${o.table}.${k}`] ?? k); + const value = toServer(o.table, o.value); + const i = rows.findIndex(row => pk.every(k => row[k] === value[k])); + let next = rows; + switch (o.op) { + case 'insert': + if (i < 0) next = [...rows, value]; + break; + case 'upsert': + next = + i < 0 + ? [...rows, value] + : rows.map((row, j) => (j === i ? {...row, ...value} : row)); + break; + case 'update': + if (i >= 0) { + next = rows.map((row, j) => (j === i ? {...row, ...value} : row)); + } + break; + case 'delete': + if (i >= 0) next = rows.filter((_, j) => j !== i); + break; + } + return {...data, [t]: next}; +} + +function randomData(r: Random): ServerData { + const data: ServerData = {}; + const some = (ids: string[]) => ids.filter(() => r.bool(0.7)); + data['issues'] = some(issueIDs).map(id => + toServer('issue', clientRow(r, 'issue', id)), + ); + data['comments'] = some(commentIDs).map(id => + toServer('comment', clientRow(r, 'comment', id)), + ); + data['users'] = some(userIDs).map(id => clientRow(r, 'user', id)); + data['label'] = some(labelIDs).map(id => clientRow(r, 'label', id)); + const edges = new Map(); + for (let i = 0; i < 5; i++) { + const e = {issueId: r.pick(issueIDs), labelId: r.pick(labelIDs)}; + edges.set(JSON.stringify(e), e); + } + data['issueLabel'] = [...edges.values()]; + return data; +} + +/** A random CRUD op in client names. */ +function randomOp(r: Random): CRUD { + const table = r.pick([ + 'issue', + 'comment', + 'comment', + 'comment', + 'user', + 'issueLabel', + ]); + if (table === 'issueLabel') { + return { + op: r.pick(['insert', 'delete'] as const), + table, + value: {issueId: r.pick(issueIDs), labelId: r.pick(labelIDs)}, + }; + } + const ids = + table === 'issue' ? issueIDs : table === 'comment' ? commentIDs : userIDs; + const id = r.pick(ids); + const op = r.pick([ + 'insert', + 'upsert', + 'update', + 'update', + 'delete', + ] as const); + const full = clientRow(r, table, id); + if (op !== 'update') { + return {op, table, value: op === 'delete' ? {id} : full}; + } + // An update of one or two columns. + const columns = Object.keys(full).filter(c => c !== 'id'); + const picked = columns.filter(() => r.bool(0.4)); + const cols = picked.length > 0 ? picked : [r.pick(columns)]; + return { + op, + table, + value: Object.fromEntries([['id', id], ...cols.map(c => [c, full[c]])]), + }; +} + +function rowsKey(row: SyncedRow): string { + return JSON.stringify([row.table, row.id]); +} + +function union( + refs: QueryRef[], + data: ServerData, + version: string, +): Map { + const out = new Map(); + for (const ref of refs) { + for (const row of syncedRows(ref.name, ref.args, data, version).values()) { + out.set(rowsKey(row), row); + } + } + return out; +} + +function diff( + old: Map, + next: Map, +): ReadonlyJSONValue[] { + const patch: ReadonlyJSONValue[] = []; + for (const [key, row] of old) { + if (!next.has(key)) { + patch.push({op: 'del', tableName: row.table, id: row.id}); + } + } + for (const [key, row] of next) { + const prev = old.get(key); + const same = + prev !== undefined && + JSON.stringify({...prev.value, _0_version: null}) === + JSON.stringify({...row.value, _0_version: null}); + if (!same) { + patch.push({op: 'put', tableName: row.table, value: row.value}); + } + } + return patch; +} + +const sameRef = (a: QueryRef, b: QueryRef) => + a.name === b.name && JSON.stringify(a.args) === JSON.stringify(b.args); + +/** A seeded random scenario. */ +export function randomScenario(r: Random, name: string): Scenario { + let data = randomData(r); + const pickAgg = aggregateRefs.filter(() => r.bool(0.12)); + const aggs = pickAgg.length > 0 ? pickAgg : [r.pick(aggregateRefs)]; + const rows = rowRefs.filter(() => r.bool(0.4)); + // The views, by name, and the queries the server has answered. + const views = new Map(); + [...aggs, ...rows].forEach((ref, i) => views.set(`v${i}`, ref)); + let got: QueryRef[] = [...views.values()]; + let cookieN = 1; + const cookie = (n: number) => String(n).padStart(2, '0'); + let last = union(got, data, cookie(1)); + + const steps: Step[] = [ + start, + ...Array.from(views, ([view, ref]): Step => ({ + op: 'materialize', + view, + query: ref.name, + ...(ref.args === undefined ? {} : {args: ref.args}), + })), + connected, + advance(10), + { + op: 'receiveAll', + messages: [ + ['pokeStart', {pokeID: 'p1', baseCookie: null}], + [ + 'pokePart', + { + pokeID: 'p1', + gotQueriesPatch: got.map(ref => ({ + op: 'put', + hash: queryHash(ref.name, ref.args), + })), + rowsPatch: diff(new Map(), last), + }, + ], + ['pokeEnd', {pokeID: 'p1', cookie: cookie(1)}], + ], + }, + advance(10), + ]; + + // Pending mutations: the client (by restart count) and its mutation ID. + type Pending = {client: number; id: number; ops: CRUD[]}; + const pending: Pending[] = []; + let clientIndex = 0; + let nextID = 1; + let mutationN = 0; + let viewN = views.size; + + /** A poke to the next cookie with `part`, the rows moved to `data`. */ + const pokeTo = (part: Record) => { + const base = cookie(cookieN); + cookieN++; + const next = union(got, data, cookie(cookieN)); + const rowsPatch = diff(last, next); + last = next; + const pokeID = `p${cookieN}`; + const messages: ReadonlyJSONValue[] = [ + ['pokeStart', {pokeID, baseCookie: base}], + ['pokePart', {pokeID, ...part, rowsPatch}], + ['pokeEnd', {pokeID, cookie: cookie(cookieN)}], + ]; + // One frame per step, or all in one read. + if (r.bool()) { + steps.push({op: 'receiveAll', messages}); + } else { + for (const message of messages) steps.push({op: 'receive', message}); + } + }; + + const clientKey = (c: number) => + c === clientIndex ? '$clientID' : `$clientID.${c}`; + + const actions = 6 + r.int(14); + for (let a = 0; a < actions; a++) { + const k = r.next(); + if (k < 0.4) { + const ops = Array.from({length: 1 + r.int(2)}, () => randomOp(r)); + const reads = [...views.values()] + .filter(ref => aggregateRefs.some(x => sameRef(x, ref))) + .filter(() => r.bool(0.4)); + steps.push({ + op: 'mutate', + mutation: `m${++mutationN}`, + mutator: 'aggregates.read', + args: {ops, queries: reads} as unknown as ReadonlyJSONValue, + }); + pending.push({client: clientIndex, id: nextID++, ops}); + if (r.bool(0.7)) steps.push(advance(10)); + } else if (k < 0.65 && pending.length > 0) { + // The server confirms the oldest `n` pending mutations. + const n = 1 + r.int(pending.length); + const done = pending.splice(0, n); + for (const m of done) for (const o of m.ops) data = applyServer(data, o); + if (r.bool(0.3)) data = applyServer(data, randomOp(r)); + const lmids: Record = {}; + for (const m of done) lmids[clientKey(m.client)] = m.id; + pokeTo({lastMutationIDChanges: lmids}); + steps.push(advance(10)); + } else if (k < 0.8) { + // Another client's write. + data = applyServer(data, randomOp(r)); + pokeTo({}); + steps.push(advance(10)); + } else if (k < 0.85 && views.size > 1) { + // A view goes and the server drops its query. + const [view, ref] = r.pick([...views]); + views.delete(view); + steps.push({op: 'destroy', view}, advance(10)); + if (![...views.values()].some(v => sameRef(v, ref))) { + got = got.filter(g => !sameRef(g, ref)); + pokeTo({ + gotQueriesPatch: [{op: 'del', hash: queryHash(ref.name, ref.args)}], + }); + steps.push(advance(10)); + } + } else if (k < 0.9) { + // A view of an aggregate query (again). + const ref = r.pick(aggregateRefs); + const view = `v${viewN++}`; + views.set(view, ref); + steps.push({ + op: 'materialize', + view, + query: ref.name, + ...(ref.args === undefined ? {} : {args: ref.args}), + }); + steps.push(advance(10)); + if (!got.some(g => sameRef(g, ref))) { + got = [...got, ref]; + pokeTo({ + gotQueriesPatch: [{op: 'put', hash: queryHash(ref.name, ref.args)}], + }); + steps.push(advance(10)); + } + } else if (k < 0.95 && process.env.AGG_FUZZ_NO_RESTART !== '1') { + // A restart: the views come back, and the server catches the client up. + steps.push(advance(2000), {op: 'restart'}); + clientIndex++; + nextID = 1; + for (const [view, ref] of views) { + steps.push({ + op: 'materialize', + view, + query: ref.name, + ...(ref.args === undefined ? {} : {args: ref.args}), + }); + } + steps.push(start, connected, advance(10)); + pokeTo({}); + steps.push(advance(10)); + } else { + steps.push(advance(10)); + } + } + steps.push(advance(10)); + return {name, steps}; +} + +test('aggregate client bug hunt', {timeout: 600_000}, async () => { + const cases: (Scenario & {expect: StepResult[]})[] = []; + for (const scenario of bughuntScenarios) { + cases.push({...scenario, expect: await runScenario(scenario)}); + } + emitVectors( + 'bughunt-client', + 'client-scenarios', + 'Aggregate bug hunt: targeted client scenarios for synced aggregates. See src/client/scenarios/bughunt.ts.', + cases, + {startTime: START_TIME}, + {compact: true}, + ); +}); + +const seed = Number(process.env.AGG_FUZZ_SEED ?? 1); +const count = Number(process.env.AGG_FUZZ_CASES ?? 150); + +test('aggregate client fuzz', {timeout: 3_600_000}, async () => { + const r = new Random(seed); + const cases: (Scenario & {expect: StepResult[]})[] = []; + for (let i = 0; i < count; i++) { + const scenario = randomScenario(r, `fuzz ${seed}-${i}`); + cases.push({...scenario, expect: await runScenario(scenario)}); + } + emitGeneratedVectors( + 'client-aggregates-fuzz', + 'client-scenarios', + 'Seeded random client scenarios over synced aggregates. See src/client/bughunt.test.ts.', + cases, + {startTime: START_TIME}, + ); +}); diff --git a/packages/zero-conformance/src/client/scenarios/bughunt.ts b/packages/zero-conformance/src/client/scenarios/bughunt.ts new file mode 100644 index 0000000000..fa7f6960d6 --- /dev/null +++ b/packages/zero-conformance/src/client/scenarios/bughunt.ts @@ -0,0 +1,370 @@ +/** + * Aggregate bug hunt: targeted client scenarios for synced aggregates. The + * server rows come from JS's pipeline (`server-rows.ts`). + */ +import type {ReadonlyJSONValue} from '../../../../shared/src/json.ts'; +import type {Scenario, Step} from '../harness.ts'; +import {serverRowsPatch, type ServerData} from '../server-rows.ts'; +import { + advance, + comment, + connected, + del, + issue, + mutate, + poke, + put, + queryHash, + start, + syncPoke, + user, +} from './helpers.ts'; + +const data: ServerData = { + issues: [ + issue('i1', {ownerId: 'u1', createdAt: 3}), + issue('i2', {createdAt: 4}), + issue('i3', {ownerId: 'u1', closed: true, createdAt: 5}), + ], + comments: [ + comment('c1', 'i1', {createdAt: 5}), + comment('c2', 'i1', {authorId: 'u2', createdAt: 7}), + comment('c3', 'i2', {createdAt: 2}), + ], + users: [user('u1', 'A', {points: 1}), user('u2', 'B', {points: 2})], +}; + +const rows = (name: string, over: ServerData = data, version = '01') => + serverRowsPatch(name, undefined, undefined, over, version); + +/** Views of `names` (`v0`, ...) and of all comments and issues, synced. */ +function synced(names: string[], over: ServerData = data): Step[] { + return [ + start, + ...names.map((query, i): Step => ({ + op: 'materialize', + view: `v${i}`, + query, + })), + {op: 'materialize', view: 'comments', query: 'bughunt.allComments'}, + {op: 'materialize', view: 'issues', query: 'issues.all'}, + connected, + advance(10), + ...syncPoke( + 'p1', + null, + '01', + [...names, 'bughunt.allComments', 'issues.all'].map(n => queryHash(n)), + [ + ...names.flatMap(n => rows(n, over)), + ...(over['comments'] ?? []).map(c => put('comments', c)), + ...(over['issues'] ?? []).map(c => put('issues', c)), + ], + ), + advance(10), + ]; +} + +const ops = ( + mutation: string, + o: {op: string; table: string; value: ReadonlyJSONValue}[], + extra: Record = {}, +) => mutate(mutation, 'harden.ops', {ops: o, ...extra}); + +const newComment = (id: string, issueId: string, createdAt = 1) => ({ + op: 'insert', + table: 'comment', + value: {id, authorId: 'u1', issueId, text: '', createdAt}, +}); + +const countRow = (value: number) => ({ + _0_key: 0, + _0_value: value, + _0_version: '02', +}); +const issueCountTable = () => `aggregate:${queryHash('aggregates.issueCount')}`; +const commentCountTable = () => + `aggregate:${queryHash('aggregates.commentCounts')}:comments`; + +export const bughuntScenarios: Scenario[] = [ + { + name: 'bughunt: a poke puts and then deletes a top-level aggregate row', + steps: [ + ...synced(['aggregates.issueCount']), + ...poke('p2', '01', '02', { + rowsPatch: [ + put(issueCountTable(), countRow(9)), + del(issueCountTable(), {_0_key: 0}), + ], + }), + advance(10), + ], + }, + { + name: 'bughunt: a poke deletes and then puts a top-level aggregate row', + steps: [ + ...synced(['aggregates.issueCount']), + ...poke('p2', '01', '02', { + rowsPatch: [ + del(issueCountTable(), {_0_key: 0}), + put(issueCountTable(), countRow(9)), + ], + }), + advance(10), + ], + }, + { + name: 'bughunt: a poke deletes and puts a relationship aggregate row, then updates it', + steps: [ + ...synced(['aggregates.commentCounts']), + ...poke('p2', '01', '02', { + rowsPatch: [ + del(commentCountTable(), {issue_id: 'i1'}), + put(commentCountTable(), { + issue_id: 'i1', + _0_value: 5, + _0_version: '02', + }), + { + op: 'update', + tableName: commentCountTable(), + id: {issue_id: 'i2'}, + merge: {_0_value: 7}, + }, + ], + }), + advance(10), + ops('m1', [newComment('c9', 'i1'), newComment('c8', 'i2')]), + advance(10), + ], + }, + { + name: 'bughunt: a poke clears the rows and puts them again', + steps: [ + ...synced(['aggregates.issueCount', 'aggregates.commentCounts']), + ...poke('p2', '01', '02', { + rowsPatch: [ + {op: 'clear'}, + ...rows('aggregates.commentCounts', data, '02'), + ...(data['issues'] ?? []).map(c => put('issues', c)), + ], + }), + advance(10), + ops('m1', [newComment('c9', 'i1')]), + advance(10), + ], + }, + { + name: 'bughunt: rows of a query the client never asked for, then its view', + steps: [ + ...synced([]), + ...poke('p2', '01', '02', { + rowsPatch: rows('aggregates.commentCounts', data, '02'), + }), + advance(10), + ops('m1', [newComment('c9', 'i1')]), + advance(10), + {op: 'materialize', view: 'late', query: 'aggregates.commentCounts'}, + advance(10), + ops('m2', [newComment('c8', 'i1')]), + advance(10), + advance(2000), + {op: 'restart'}, + {op: 'materialize', view: 'again', query: 'aggregates.commentCounts'}, + advance(10), + ], + }, + { + name: 'bughunt: a mutator that moves aggregates and then throws moves nothing', + steps: [ + ...synced([ + 'aggregates.commentCounts', + 'aggregates.commentsByIssue', + 'aggregates.timeByAuthor', + ]), + ops('m1', [newComment('c9', 'i1'), newComment('c8', 'i9')], { + fail: 'boom', + }), + advance(10), + ops('m2', [{op: 'delete', table: 'comment', value: {id: 'c3'}}], { + fail: 'boom', + }), + advance(10), + ], + }, + { + name: 'bughunt: a group emptied and refilled in one mutation', + steps: [ + ...synced([ + 'aggregates.commentsByIssue', + 'aggregates.timeByAuthor', + 'bughunt.commentsByAuthorAndIssue', + 'bughunt.avgTimeByIssueWhere', + ]), + ops('m1', [ + {op: 'delete', table: 'comment', value: {id: 'c3'}}, + newComment('c9', 'i2', 8), + ]), + advance(10), + ops('m2', [ + {op: 'update', table: 'comment', value: {id: 'c9', issueId: 'i7'}}, + {op: 'update', table: 'comment', value: {id: 'c9', issueId: 'i2'}}, + ]), + advance(10), + ops('m3', [ + {op: 'delete', table: 'comment', value: {id: 'c9'}}, + {op: 'delete', table: 'comment', value: {id: 'c1'}}, + {op: 'delete', table: 'comment', value: {id: 'c2'}}, + ]), + advance(10), + ], + }, + { + name: 'bughunt: rebases of several pending mutations over moved aggregates', + steps: [ + ...synced([ + 'aggregates.commentCounts', + 'aggregates.commentTimes', + 'aggregates.commentsByIssue', + 'aggregates.issueCount', + ]), + ops('m1', [newComment('c9', 'i1', 9)]), + ops('m2', [{op: 'delete', table: 'comment', value: {id: 'c3'}}]), + ops('m3', [ + {op: 'update', table: 'comment', value: {id: 'c1', issueId: 'i3'}}, + ]), + advance(10), + // Another client adds a comment to i2. + ...poke('p2', '01', '02', { + rowsPatch: [ + ...serverRowsPatch( + 'aggregates.commentCounts', + undefined, + data, + {...data, comments: [...data['comments'], comment('x1', 'i2')]}, + '02', + ), + ...serverRowsPatch( + 'aggregates.commentsByIssue', + undefined, + data, + {...data, comments: [...data['comments'], comment('x1', 'i2')]}, + '02', + ), + put('comments', comment('x1', 'i2')), + ], + }), + advance(10), + // The server confirms m1 only. + ...poke('p3', '02', '03', { + lastMutationIDChanges: {$clientID: 1}, + rowsPatch: [ + ...serverRowsPatch( + 'aggregates.commentCounts', + undefined, + {...data, comments: [...data['comments'], comment('x1', 'i2')]}, + { + ...data, + comments: [ + ...data['comments'], + comment('x1', 'i2'), + comment('c9', 'i1', {createdAt: 9}), + ], + }, + '03', + ), + put('comments', comment('c9', 'i1', {createdAt: 9})), + ], + }), + advance(2000), + {op: 'restart'}, + {op: 'materialize', view: 'v0', query: 'aggregates.commentCounts'}, + {op: 'materialize', view: 'v2', query: 'aggregates.commentsByIssue'}, + advance(10), + ], + }, + { + // Swift's rebase when an aggregate first registers after a restart + // (AGGREGATES-PLAN §6) replays every pending mutation, also one made + // after the launch, which JS moves only at its next rebase. + name: 'bughunt: after a restart, registering a groupBy moves it by a mutation made since', + steps: [ + start, + connected, + advance(10), + mutate('m1', 'issue.create', {id: 'i9'}), + advance(2000), + {op: 'restart'}, + start, + connected, + advance(10), + mutate('m2', 'comment.add', {id: 'c9', issueId: 'i1'}), + advance(10), + {op: 'materialize', view: 'v', query: 'aggregates.commentsByIssue'}, + advance(10), + ], + }, + { + // The same for a synced relationship count: the server's count is + // stored, and a comment added after the launch moves it at once. + name: 'bughunt: after a restart, registering a relationship count moves it by a mutation made since', + steps: [ + ...synced(['aggregates.commentCounts']), + mutate('m1', 'issue.create', {id: 'i9'}), + advance(2000), + {op: 'restart'}, + start, + connected, + advance(10), + mutate('m2', 'comment.add', {id: 'c9', issueId: 'i1'}), + advance(10), + {op: 'materialize', view: 'v', query: 'aggregates.commentCounts'}, + advance(10), + ], + }, + { + // The same rebase replays a mutation from before the restart into a + // query that wasn't registered when it ran: JS's persisted write never + // moved it. + name: 'bughunt: after a restart, a groupBy first materialized is moved by a mutation from before', + steps: [ + start, + connected, + advance(10), + mutate('m1', 'issue.create', {id: 'i9', closed: true}), + advance(2000), + {op: 'restart'}, + start, + connected, + advance(10), + {op: 'materialize', view: 'v', query: 'aggregates.countByState'}, + advance(10), + ], + }, + { + name: 'bughunt: a sum over a JSON path and a nested relationship count move optimistically', + steps: [ + ...synced(['bughunt.pointsSum', 'bughunt.ownerIssueCounts']), + ops('m1', [ + { + op: 'insert', + table: 'user', + value: {id: 'u3', name: 'C', metadata: {points: 4}}, + }, + { + op: 'insert', + table: 'issue', + value: { + id: 'i9', + title: '', + description: '', + closed: false, + ownerId: 'u1', + createdAt: 1, + }, + }, + ]), + advance(10), + ], + }, +]; diff --git a/packages/zero-conformance/src/client/server-rows.ts b/packages/zero-conformance/src/client/server-rows.ts index 75a42b896d..160c567d90 100644 --- a/packages/zero-conformance/src/client/server-rows.ts +++ b/packages/zero-conformance/src/client/server-rows.ts @@ -27,7 +27,7 @@ type JSONObject = {readonly [key: string]: ReadonlyJSONValue}; /** Server-named rows by server table name. */ export type ServerData = Record; -type SyncedRow = {table: string; id: JSONObject; value: JSONObject}; +export type SyncedRow = {table: string; id: JSONObject; value: JSONObject}; function lookup(name: string) { let v: unknown = queries; @@ -38,7 +38,7 @@ function lookup(name: string) { } /** The rows the server syncs for `query(args)` over `data`, by table and key. */ -function syncedRows( +export function syncedRows( query: string, args: ReadonlyJSONValue | undefined, data: ServerData, diff --git a/packages/zero-conformance/vectors/bughunt-client.json b/packages/zero-conformance/vectors/bughunt-client.json new file mode 100644 index 0000000000..b6392467fe --- /dev/null +++ b/packages/zero-conformance/vectors/bughunt-client.json @@ -0,0 +1,14 @@ +{"formatVersion":1,"kind":"client-scenarios","description":"Aggregate bug hunt: targeted client scenarios for synced aggregates. See src/client/scenarios/bughunt.ts.","shared":{"startTime":1700000000000},"cases":[ +{"name":"bughunt: a poke puts and then deletes a top-level aggregate row","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.issueCount"},{"op":"materialize","view":"comments","query":"bughunt.allComments"},{"op":"materialize","view":"issues","query":"issues.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0oql89w09s2pr4"},{"op":"put","hash":"0rsht6z1lahgep"},{"op":"put","hash":"1y7zr0i1xir4ek"}],"rowsPatch":[{"op":"put","tableName":"aggregate:0oql89w09s2pr4","value":{"_0_key":0,"_0_value":3,"_0_version":"01"}},{"op":"put","tableName":"comments","value":{"id":"c1","authorId":"u1","issue_id":"i1","text":"","createdAt":5}},{"op":"put","tableName":"comments","value":{"id":"c2","authorId":"u2","issue_id":"i1","text":"","createdAt":7}},{"op":"put","tableName":"comments","value":{"id":"c3","authorId":"u1","issue_id":"i2","text":"","createdAt":2}},{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2","rowsPatch":[{"op":"put","tableName":"aggregate:0oql89w09s2pr4","value":{"_0_key":0,"_0_value":9,"_0_version":"02"}},{"op":"del","tableName":"aggregate:0oql89w09s2pr4","id":{"_0_key":0}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0oql89w09s2pr4","name":"aggregates.issueCount","args":[],"ttl":300000},{"op":"put","hash":"0rsht6z1lahgep","name":"bughunt.allComments","args":[],"ttl":300000},{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0oql89w09s2pr4","name":"aggregates.issueCount","args":[],"ttl":300000},{"op":"put","hash":"0rsht6z1lahgep","name":"bughunt.allComments","args":[],"ttl":300000},{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":3,"resultType":"complete","notifications":2},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":2},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":2}}},{"state":{"name":"connected"},"views":{"v0":{"data":3,"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":3,"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":3,"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"complete","notifications":1},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}}]}, +{"name":"bughunt: a poke deletes and then puts a top-level aggregate row","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.issueCount"},{"op":"materialize","view":"comments","query":"bughunt.allComments"},{"op":"materialize","view":"issues","query":"issues.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0oql89w09s2pr4"},{"op":"put","hash":"0rsht6z1lahgep"},{"op":"put","hash":"1y7zr0i1xir4ek"}],"rowsPatch":[{"op":"put","tableName":"aggregate:0oql89w09s2pr4","value":{"_0_key":0,"_0_value":3,"_0_version":"01"}},{"op":"put","tableName":"comments","value":{"id":"c1","authorId":"u1","issue_id":"i1","text":"","createdAt":5}},{"op":"put","tableName":"comments","value":{"id":"c2","authorId":"u2","issue_id":"i1","text":"","createdAt":7}},{"op":"put","tableName":"comments","value":{"id":"c3","authorId":"u1","issue_id":"i2","text":"","createdAt":2}},{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2","rowsPatch":[{"op":"del","tableName":"aggregate:0oql89w09s2pr4","id":{"_0_key":0}},{"op":"put","tableName":"aggregate:0oql89w09s2pr4","value":{"_0_key":0,"_0_value":9,"_0_version":"02"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0oql89w09s2pr4","name":"aggregates.issueCount","args":[],"ttl":300000},{"op":"put","hash":"0rsht6z1lahgep","name":"bughunt.allComments","args":[],"ttl":300000},{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0oql89w09s2pr4","name":"aggregates.issueCount","args":[],"ttl":300000},{"op":"put","hash":"0rsht6z1lahgep","name":"bughunt.allComments","args":[],"ttl":300000},{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":3,"resultType":"complete","notifications":2},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":2},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":2}}},{"state":{"name":"connected"},"views":{"v0":{"data":3,"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":3,"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":3,"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":9,"resultType":"complete","notifications":1},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":9,"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}}]}, +{"name":"bughunt: a poke deletes and puts a relationship aggregate row, then updates it","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.commentCounts"},{"op":"materialize","view":"comments","query":"bughunt.allComments"},{"op":"materialize","view":"issues","query":"issues.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr"},{"op":"put","hash":"0rsht6z1lahgep"},{"op":"put","hash":"1y7zr0i1xir4ek"}],"rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i1","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i2","_0_value":1,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i3","_0_value":0,"_0_version":"01"}},{"op":"put","tableName":"comments","value":{"id":"c1","authorId":"u1","issue_id":"i1","text":"","createdAt":5}},{"op":"put","tableName":"comments","value":{"id":"c2","authorId":"u2","issue_id":"i1","text":"","createdAt":7}},{"op":"put","tableName":"comments","value":{"id":"c3","authorId":"u1","issue_id":"i2","text":"","createdAt":2}},{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2","rowsPatch":[{"op":"del","tableName":"aggregate:0u3s9wi0kzvflr:comments","id":{"issue_id":"i1"}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i1","_0_value":5,"_0_version":"02"}},{"op":"update","tableName":"aggregate:0u3s9wi0kzvflr:comments","id":{"issue_id":"i2"},"merge":{"_0_value":7}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]},{"op":"advance","ms":10},{"op":"mutate","mutation":"m1","mutator":"harden.ops","args":{"ops":[{"op":"insert","table":"comment","value":{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":1}},{"op":"insert","table":"comment","value":{"id":"c8","authorId":"u1","issueId":"i2","text":"","createdAt":1}}]}},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000},{"op":"put","hash":"0rsht6z1lahgep","name":"bughunt.allComments","args":[],"ttl":300000},{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000},{"op":"put","hash":"0rsht6z1lahgep","name":"bughunt.allComments","args":[],"ttl":300000},{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":2},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":2},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":2}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":5},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":7},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":1},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":5},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":7},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"sent":[["push",{"timestamp":1700000000030,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000030,"id":1,"clientID":"$clientID","name":"harden.ops","args":[{"ops":[{"op":"insert","table":"comment","value":{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":1}},{"op":"insert","table":"comment","value":{"id":"c8","authorId":"u1","issueId":"i2","text":"","createdAt":1}}]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":6},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":8},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":1},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2},{"id":"c8","authorId":"u1","issueId":"i2","text":"","createdAt":1},{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":1}],"resultType":"complete","notifications":1},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":6},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":8},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2},{"id":"c8","authorId":"u1","issueId":"i2","text":"","createdAt":1},{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":1}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}}]}, +{"name":"bughunt: a poke clears the rows and puts them again","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.issueCount"},{"op":"materialize","view":"v1","query":"aggregates.commentCounts"},{"op":"materialize","view":"comments","query":"bughunt.allComments"},{"op":"materialize","view":"issues","query":"issues.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0oql89w09s2pr4"},{"op":"put","hash":"0u3s9wi0kzvflr"},{"op":"put","hash":"0rsht6z1lahgep"},{"op":"put","hash":"1y7zr0i1xir4ek"}],"rowsPatch":[{"op":"put","tableName":"aggregate:0oql89w09s2pr4","value":{"_0_key":0,"_0_value":3,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i1","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i2","_0_value":1,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i3","_0_value":0,"_0_version":"01"}},{"op":"put","tableName":"comments","value":{"id":"c1","authorId":"u1","issue_id":"i1","text":"","createdAt":5}},{"op":"put","tableName":"comments","value":{"id":"c2","authorId":"u2","issue_id":"i1","text":"","createdAt":7}},{"op":"put","tableName":"comments","value":{"id":"c3","authorId":"u1","issue_id":"i2","text":"","createdAt":2}},{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2","rowsPatch":[{"op":"clear"},{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i1","_0_value":2,"_0_version":"02"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i2","_0_value":1,"_0_version":"02"}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i3","_0_value":0,"_0_version":"02"}},{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]},{"op":"advance","ms":10},{"op":"mutate","mutation":"m1","mutator":"harden.ops","args":{"ops":[{"op":"insert","table":"comment","value":{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":1}}]}},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0oql89w09s2pr4","name":"aggregates.issueCount","args":[],"ttl":300000},{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000},{"op":"put","hash":"0rsht6z1lahgep","name":"bughunt.allComments","args":[],"ttl":300000},{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0oql89w09s2pr4","name":"aggregates.issueCount","args":[],"ttl":300000},{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000},{"op":"put","hash":"0rsht6z1lahgep","name":"bughunt.allComments","args":[],"ttl":300000},{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":3,"resultType":"complete","notifications":2},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":2},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":2},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":2}}},{"state":{"name":"connected"},"views":{"v0":{"data":3,"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":3,"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":3,"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"complete","notifications":1},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":1},"comments":{"data":[],"resultType":"complete","notifications":1},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0},"comments":{"data":[],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"sent":[["push",{"timestamp":1700000000030,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000030,"id":1,"clientID":"$clientID","name":"harden.ops","args":[{"ops":[{"op":"insert","table":"comment","value":{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":1}}]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":1},"comments":{"data":[{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":1}],"resultType":"complete","notifications":1},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":0,"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":1}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}}]}, +{"name":"bughunt: rows of a query the client never asked for, then its view","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"comments","query":"bughunt.allComments"},{"op":"materialize","view":"issues","query":"issues.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0rsht6z1lahgep"},{"op":"put","hash":"1y7zr0i1xir4ek"}],"rowsPatch":[{"op":"put","tableName":"comments","value":{"id":"c1","authorId":"u1","issue_id":"i1","text":"","createdAt":5}},{"op":"put","tableName":"comments","value":{"id":"c2","authorId":"u2","issue_id":"i1","text":"","createdAt":7}},{"op":"put","tableName":"comments","value":{"id":"c3","authorId":"u1","issue_id":"i2","text":"","createdAt":2}},{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2","rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i1","_0_value":2,"_0_version":"02"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i2","_0_value":1,"_0_version":"02"}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i3","_0_value":0,"_0_version":"02"}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]},{"op":"advance","ms":10},{"op":"mutate","mutation":"m1","mutator":"harden.ops","args":{"ops":[{"op":"insert","table":"comment","value":{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":1}}]}},{"op":"advance","ms":10},{"op":"materialize","view":"late","query":"aggregates.commentCounts"},{"op":"advance","ms":10},{"op":"mutate","mutation":"m2","mutator":"harden.ops","args":{"ops":[{"op":"insert","table":"comment","value":{"id":"c8","authorId":"u1","issueId":"i1","text":"","createdAt":1}}]}},{"op":"advance","ms":10},{"op":"advance","ms":2000},{"op":"restart"},{"op":"materialize","view":"again","query":"aggregates.commentCounts"},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"comments":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0rsht6z1lahgep","name":"bughunt.allComments","args":[],"ttl":300000},{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0rsht6z1lahgep","name":"bughunt.allComments","args":[],"ttl":300000},{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":2},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":2}}},{"state":{"name":"connected"},"views":{"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"state":{"name":"connected"},"views":{"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"state":{"name":"connected"},"views":{"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"state":{"name":"connected"},"views":{"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"state":{"name":"connected"},"views":{"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"sent":[["push",{"timestamp":1700000000030,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000030,"id":1,"clientID":"$clientID","name":"harden.ops","args":[{"ops":[{"op":"insert","table":"comment","value":{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":1}}]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2},{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":1}],"resultType":"complete","notifications":1},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2},{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":1}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2},{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":1}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0},"late":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2},{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":1}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0},"late":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000050,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000050,"id":2,"clientID":"$clientID","name":"harden.ops","args":[{"ops":[{"op":"insert","table":"comment","value":{"id":"c8","authorId":"u1","issueId":"i1","text":"","createdAt":1}}]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2},{"id":"c8","authorId":"u1","issueId":"i1","text":"","createdAt":1},{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":1}],"resultType":"complete","notifications":1},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0},"late":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"unknown","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2},{"id":"c8","authorId":"u1","issueId":"i1","text":"","createdAt":1},{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":1}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0},"late":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2},{"id":"c8","authorId":"u1","issueId":"i1","text":"","createdAt":1},{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":1}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0},"late":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"unknown","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie","02"],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"activeClients":["$clientID"]}]}}],"closed":[0],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"again":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":4},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"again":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":4},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"unknown","notifications":0}}}]}, +{"name":"bughunt: a mutator that moves aggregates and then throws moves nothing","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.commentCounts"},{"op":"materialize","view":"v1","query":"aggregates.commentsByIssue"},{"op":"materialize","view":"v2","query":"aggregates.timeByAuthor"},{"op":"materialize","view":"comments","query":"bughunt.allComments"},{"op":"materialize","view":"issues","query":"issues.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr"},{"op":"put","hash":"1sx56i91c6nbxb"},{"op":"put","hash":"0t6mull0l7zix6"},{"op":"put","hash":"0rsht6z1lahgep"},{"op":"put","hash":"1y7zr0i1xir4ek"}],"rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i1","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i2","_0_value":1,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i3","_0_value":0,"_0_version":"01"}},{"op":"put","tableName":"aggregate:1sx56i91c6nbxb:#group","value":{"issue_id":"i1","_0_key":"si1","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"aggregate:1sx56i91c6nbxb:#group","value":{"issue_id":"i2","_0_key":"si2","_0_value":1,"_0_version":"01"}},{"op":"put","tableName":"aggregate:0t6mull0l7zix6:#group","value":{"authorId":"u1","_0_key":"su1","_0_value":7,"_0_sum":7,"_0_count":2,"_0_rows":2,"_0_version":"01"}},{"op":"put","tableName":"aggregate:0t6mull0l7zix6:#group","value":{"authorId":"u2","_0_key":"su2","_0_value":7,"_0_sum":7,"_0_count":1,"_0_rows":1,"_0_version":"01"}},{"op":"put","tableName":"comments","value":{"id":"c1","authorId":"u1","issue_id":"i1","text":"","createdAt":5}},{"op":"put","tableName":"comments","value":{"id":"c2","authorId":"u2","issue_id":"i1","text":"","createdAt":7}},{"op":"put","tableName":"comments","value":{"id":"c3","authorId":"u1","issue_id":"i2","text":"","createdAt":2}},{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"advance","ms":10},{"op":"mutate","mutation":"m1","mutator":"harden.ops","args":{"ops":[{"op":"insert","table":"comment","value":{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":1}},{"op":"insert","table":"comment","value":{"id":"c8","authorId":"u1","issueId":"i9","text":"","createdAt":1}}],"fail":"boom"}},{"op":"advance","ms":10},{"op":"mutate","mutation":"m2","mutator":"harden.ops","args":{"ops":[{"op":"delete","table":"comment","value":{"id":"c3"}}],"fail":"boom"}},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000},{"op":"put","hash":"1sx56i91c6nbxb","name":"aggregates.commentsByIssue","args":[],"ttl":300000},{"op":"put","hash":"0t6mull0l7zix6","name":"aggregates.timeByAuthor","args":[],"ttl":300000},{"op":"put","hash":"0rsht6z1lahgep","name":"bughunt.allComments","args":[],"ttl":300000},{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000},{"op":"put","hash":"1sx56i91c6nbxb","name":"aggregates.commentsByIssue","args":[],"ttl":300000},{"op":"put","hash":"0t6mull0l7zix6","name":"aggregates.timeByAuthor","args":[],"ttl":300000},{"op":"put","hash":"0rsht6z1lahgep","name":"bughunt.allComments","args":[],"ttl":300000},{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":2},"v1":{"data":[{"issueId":"i1","count":2},{"issueId":"i2","count":1}],"resultType":"complete","notifications":2},"v2":{"data":[{"authorId":"u1","sum":7},{"authorId":"u2","sum":7}],"resultType":"complete","notifications":2},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":2},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":2}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0},"v1":{"data":[{"issueId":"i1","count":2},{"issueId":"i2","count":1}],"resultType":"complete","notifications":0},"v2":{"data":[{"authorId":"u1","sum":7},{"authorId":"u2","sum":7}],"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0},"v1":{"data":[{"issueId":"i1","count":2},{"issueId":"i2","count":1}],"resultType":"complete","notifications":0},"v2":{"data":[{"authorId":"u1","sum":7},{"authorId":"u2","sum":7}],"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"error","error":{"type":"app","message":"boom"}},"server":{"type":"error","error":{"type":"app","message":"boom"}}}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0},"v1":{"data":[{"issueId":"i1","count":2},{"issueId":"i2","count":1}],"resultType":"complete","notifications":0},"v2":{"data":[{"authorId":"u1","sum":7},{"authorId":"u2","sum":7}],"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"error","error":{"type":"app","message":"boom"}},"server":{"type":"error","error":{"type":"app","message":"boom"}}}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0},"v1":{"data":[{"issueId":"i1","count":2},{"issueId":"i2","count":1}],"resultType":"complete","notifications":0},"v2":{"data":[{"authorId":"u1","sum":7},{"authorId":"u2","sum":7}],"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"error","error":{"type":"app","message":"boom"}},"server":{"type":"error","error":{"type":"app","message":"boom"}}},"m2":{"client":{"type":"error","error":{"type":"app","message":"boom"}},"server":{"type":"error","error":{"type":"app","message":"boom"}}}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0},"v1":{"data":[{"issueId":"i1","count":2},{"issueId":"i2","count":1}],"resultType":"complete","notifications":0},"v2":{"data":[{"authorId":"u1","sum":7},{"authorId":"u2","sum":7}],"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"error","error":{"type":"app","message":"boom"}},"server":{"type":"error","error":{"type":"app","message":"boom"}}},"m2":{"client":{"type":"error","error":{"type":"app","message":"boom"}},"server":{"type":"error","error":{"type":"app","message":"boom"}}}}}]}, +{"name":"bughunt: a group emptied and refilled in one mutation","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.commentsByIssue"},{"op":"materialize","view":"v1","query":"aggregates.timeByAuthor"},{"op":"materialize","view":"v2","query":"bughunt.commentsByAuthorAndIssue"},{"op":"materialize","view":"v3","query":"bughunt.avgTimeByIssueWhere"},{"op":"materialize","view":"comments","query":"bughunt.allComments"},{"op":"materialize","view":"issues","query":"issues.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"1sx56i91c6nbxb"},{"op":"put","hash":"0t6mull0l7zix6"},{"op":"put","hash":"1js02dv0fx4lm1"},{"op":"put","hash":"1io8hgq0hm7dn0"},{"op":"put","hash":"0rsht6z1lahgep"},{"op":"put","hash":"1y7zr0i1xir4ek"}],"rowsPatch":[{"op":"put","tableName":"aggregate:1sx56i91c6nbxb:#group","value":{"issue_id":"i1","_0_key":"si1","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"aggregate:1sx56i91c6nbxb:#group","value":{"issue_id":"i2","_0_key":"si2","_0_value":1,"_0_version":"01"}},{"op":"put","tableName":"aggregate:0t6mull0l7zix6:#group","value":{"authorId":"u1","_0_key":"su1","_0_value":7,"_0_sum":7,"_0_count":2,"_0_rows":2,"_0_version":"01"}},{"op":"put","tableName":"aggregate:0t6mull0l7zix6:#group","value":{"authorId":"u2","_0_key":"su2","_0_value":7,"_0_sum":7,"_0_count":1,"_0_rows":1,"_0_version":"01"}},{"op":"put","tableName":"aggregate:1js02dv0fx4lm1:#group","value":{"authorId":"u1","issue_id":"i1","_0_key":"[\"u1\",\"i1\"]","_0_value":1,"_0_version":"01"}},{"op":"put","tableName":"aggregate:1js02dv0fx4lm1:#group","value":{"authorId":"u1","issue_id":"i2","_0_key":"[\"u1\",\"i2\"]","_0_value":1,"_0_version":"01"}},{"op":"put","tableName":"aggregate:1js02dv0fx4lm1:#group","value":{"authorId":"u2","issue_id":"i1","_0_key":"[\"u2\",\"i1\"]","_0_value":1,"_0_version":"01"}},{"op":"put","tableName":"aggregate:1io8hgq0hm7dn0:#group","value":{"issue_id":"i1","_0_key":"si1","_0_value":6,"_0_sum":12,"_0_count":2,"_0_rows":2,"_0_version":"01"}},{"op":"put","tableName":"aggregate:1io8hgq0hm7dn0:#group","value":{"issue_id":"i2","_0_key":"si2","_0_value":2,"_0_sum":2,"_0_count":1,"_0_rows":1,"_0_version":"01"}},{"op":"put","tableName":"comments","value":{"id":"c1","authorId":"u1","issue_id":"i1","text":"","createdAt":5}},{"op":"put","tableName":"comments","value":{"id":"c2","authorId":"u2","issue_id":"i1","text":"","createdAt":7}},{"op":"put","tableName":"comments","value":{"id":"c3","authorId":"u1","issue_id":"i2","text":"","createdAt":2}},{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"advance","ms":10},{"op":"mutate","mutation":"m1","mutator":"harden.ops","args":{"ops":[{"op":"delete","table":"comment","value":{"id":"c3"}},{"op":"insert","table":"comment","value":{"id":"c9","authorId":"u1","issueId":"i2","text":"","createdAt":8}}]}},{"op":"advance","ms":10},{"op":"mutate","mutation":"m2","mutator":"harden.ops","args":{"ops":[{"op":"update","table":"comment","value":{"id":"c9","issueId":"i7"}},{"op":"update","table":"comment","value":{"id":"c9","issueId":"i2"}}]}},{"op":"advance","ms":10},{"op":"mutate","mutation":"m3","mutator":"harden.ops","args":{"ops":[{"op":"delete","table":"comment","value":{"id":"c9"}},{"op":"delete","table":"comment","value":{"id":"c1"}},{"op":"delete","table":"comment","value":{"id":"c2"}}]}},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":0},"v3":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":0},"v3":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":0},"v3":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1sx56i91c6nbxb","name":"aggregates.commentsByIssue","args":[],"ttl":300000},{"op":"put","hash":"0t6mull0l7zix6","name":"aggregates.timeByAuthor","args":[],"ttl":300000},{"op":"put","hash":"1js02dv0fx4lm1","name":"bughunt.commentsByAuthorAndIssue","args":[],"ttl":300000},{"op":"put","hash":"1io8hgq0hm7dn0","name":"bughunt.avgTimeByIssueWhere","args":[],"ttl":300000},{"op":"put","hash":"0rsht6z1lahgep","name":"bughunt.allComments","args":[],"ttl":300000},{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":0},"v3":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1sx56i91c6nbxb","name":"aggregates.commentsByIssue","args":[],"ttl":300000},{"op":"put","hash":"0t6mull0l7zix6","name":"aggregates.timeByAuthor","args":[],"ttl":300000},{"op":"put","hash":"1js02dv0fx4lm1","name":"bughunt.commentsByAuthorAndIssue","args":[],"ttl":300000},{"op":"put","hash":"1io8hgq0hm7dn0","name":"bughunt.avgTimeByIssueWhere","args":[],"ttl":300000},{"op":"put","hash":"0rsht6z1lahgep","name":"bughunt.allComments","args":[],"ttl":300000},{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":0},"v3":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":0},"v3":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":0},"v3":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"issueId":"i1","count":2},{"issueId":"i2","count":1}],"resultType":"complete","notifications":2},"v1":{"data":[{"authorId":"u1","sum":7},{"authorId":"u2","sum":7}],"resultType":"complete","notifications":2},"v2":{"data":[{"authorId":"u1","issueId":"i1","count":1},{"authorId":"u1","issueId":"i2","count":1},{"authorId":"u2","issueId":"i1","count":1}],"resultType":"complete","notifications":2},"v3":{"data":[{"issueId":"i1","avg":6},{"issueId":"i2","avg":2}],"resultType":"complete","notifications":2},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":2},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":2}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"issueId":"i1","count":2},{"issueId":"i2","count":1}],"resultType":"complete","notifications":0},"v1":{"data":[{"authorId":"u1","sum":7},{"authorId":"u2","sum":7}],"resultType":"complete","notifications":0},"v2":{"data":[{"authorId":"u1","issueId":"i1","count":1},{"authorId":"u1","issueId":"i2","count":1},{"authorId":"u2","issueId":"i1","count":1}],"resultType":"complete","notifications":0},"v3":{"data":[{"issueId":"i1","avg":6},{"issueId":"i2","avg":2}],"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"sent":[["push",{"timestamp":1700000000020,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000020,"id":1,"clientID":"$clientID","name":"harden.ops","args":[{"ops":[{"op":"delete","table":"comment","value":{"id":"c3"}},{"op":"insert","table":"comment","value":{"id":"c9","authorId":"u1","issueId":"i2","text":"","createdAt":8}}]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"issueId":"i1","count":2},{"issueId":"i2","count":1}],"resultType":"complete","notifications":0},"v1":{"data":[{"authorId":"u1","sum":13},{"authorId":"u2","sum":7}],"resultType":"complete","notifications":1},"v2":{"data":[{"authorId":"u1","issueId":"i1","count":1},{"authorId":"u1","issueId":"i2","count":1},{"authorId":"u2","issueId":"i1","count":1}],"resultType":"complete","notifications":0},"v3":{"data":[{"issueId":"i1","avg":6},{"issueId":"i2","avg":8}],"resultType":"complete","notifications":1},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c9","authorId":"u1","issueId":"i2","text":"","createdAt":8}],"resultType":"complete","notifications":1},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"issueId":"i1","count":2},{"issueId":"i2","count":1}],"resultType":"complete","notifications":0},"v1":{"data":[{"authorId":"u1","sum":13},{"authorId":"u2","sum":7}],"resultType":"complete","notifications":0},"v2":{"data":[{"authorId":"u1","issueId":"i1","count":1},{"authorId":"u1","issueId":"i2","count":1},{"authorId":"u2","issueId":"i1","count":1}],"resultType":"complete","notifications":0},"v3":{"data":[{"issueId":"i1","avg":6},{"issueId":"i2","avg":8}],"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c9","authorId":"u1","issueId":"i2","text":"","createdAt":8}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000030,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000030,"id":2,"clientID":"$clientID","name":"harden.ops","args":[{"ops":[{"op":"update","table":"comment","value":{"id":"c9","issueId":"i7"}},{"op":"update","table":"comment","value":{"id":"c9","issueId":"i2"}}]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"issueId":"i1","count":2},{"issueId":"i2","count":1}],"resultType":"complete","notifications":0},"v1":{"data":[{"authorId":"u1","sum":13},{"authorId":"u2","sum":7}],"resultType":"complete","notifications":0},"v2":{"data":[{"authorId":"u1","issueId":"i1","count":1},{"authorId":"u1","issueId":"i2","count":1},{"authorId":"u2","issueId":"i1","count":1}],"resultType":"complete","notifications":0},"v3":{"data":[{"issueId":"i1","avg":6},{"issueId":"i2","avg":8}],"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c9","authorId":"u1","issueId":"i2","text":"","createdAt":8}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"issueId":"i1","count":2},{"issueId":"i2","count":1}],"resultType":"complete","notifications":0},"v1":{"data":[{"authorId":"u1","sum":13},{"authorId":"u2","sum":7}],"resultType":"complete","notifications":0},"v2":{"data":[{"authorId":"u1","issueId":"i1","count":1},{"authorId":"u1","issueId":"i2","count":1},{"authorId":"u2","issueId":"i1","count":1}],"resultType":"complete","notifications":0},"v3":{"data":[{"issueId":"i1","avg":6},{"issueId":"i2","avg":8}],"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c9","authorId":"u1","issueId":"i2","text":"","createdAt":8}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000040,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000040,"id":3,"clientID":"$clientID","name":"harden.ops","args":[{"ops":[{"op":"delete","table":"comment","value":{"id":"c9"}},{"op":"delete","table":"comment","value":{"id":"c1"}},{"op":"delete","table":"comment","value":{"id":"c2"}}]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"complete","notifications":1},"v1":{"data":[],"resultType":"complete","notifications":1},"v2":{"data":[],"resultType":"complete","notifications":1},"v3":{"data":[],"resultType":"complete","notifications":1},"comments":{"data":[],"resultType":"complete","notifications":1},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"complete","notifications":0},"v1":{"data":[],"resultType":"complete","notifications":0},"v2":{"data":[],"resultType":"complete","notifications":0},"v3":{"data":[],"resultType":"complete","notifications":0},"comments":{"data":[],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}}]}, +{"name":"bughunt: rebases of several pending mutations over moved aggregates","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.commentCounts"},{"op":"materialize","view":"v1","query":"aggregates.commentTimes"},{"op":"materialize","view":"v2","query":"aggregates.commentsByIssue"},{"op":"materialize","view":"v3","query":"aggregates.issueCount"},{"op":"materialize","view":"comments","query":"bughunt.allComments"},{"op":"materialize","view":"issues","query":"issues.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr"},{"op":"put","hash":"0puwc8m0bnu56k"},{"op":"put","hash":"1sx56i91c6nbxb"},{"op":"put","hash":"0oql89w09s2pr4"},{"op":"put","hash":"0rsht6z1lahgep"},{"op":"put","hash":"1y7zr0i1xir4ek"}],"rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i1","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i2","_0_value":1,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i3","_0_value":0,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:0puwc8m0bnu56k:comments","value":{"issue_id":"i1","_0_value":6,"_0_sum":12,"_0_count":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"aggregate:0puwc8m0bnu56k:comments","value":{"issue_id":"i2","_0_value":2,"_0_sum":2,"_0_count":1,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"aggregate:0puwc8m0bnu56k:comments","value":{"issue_id":"i3","_0_value":null,"_0_sum":0,"_0_count":0,"_0_version":"01"}},{"op":"put","tableName":"aggregate:1sx56i91c6nbxb:#group","value":{"issue_id":"i1","_0_key":"si1","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"aggregate:1sx56i91c6nbxb:#group","value":{"issue_id":"i2","_0_key":"si2","_0_value":1,"_0_version":"01"}},{"op":"put","tableName":"aggregate:0oql89w09s2pr4","value":{"_0_key":0,"_0_value":3,"_0_version":"01"}},{"op":"put","tableName":"comments","value":{"id":"c1","authorId":"u1","issue_id":"i1","text":"","createdAt":5}},{"op":"put","tableName":"comments","value":{"id":"c2","authorId":"u2","issue_id":"i1","text":"","createdAt":7}},{"op":"put","tableName":"comments","value":{"id":"c3","authorId":"u1","issue_id":"i2","text":"","createdAt":2}},{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"advance","ms":10},{"op":"mutate","mutation":"m1","mutator":"harden.ops","args":{"ops":[{"op":"insert","table":"comment","value":{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":9}}]}},{"op":"mutate","mutation":"m2","mutator":"harden.ops","args":{"ops":[{"op":"delete","table":"comment","value":{"id":"c3"}}]}},{"op":"mutate","mutation":"m3","mutator":"harden.ops","args":{"ops":[{"op":"update","table":"comment","value":{"id":"c1","issueId":"i3"}}]}},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p2","baseCookie":"01"}]},{"op":"receive","message":["pokePart",{"pokeID":"p2","rowsPatch":[{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i2","_0_value":2,"_0_version":"02"}},{"op":"put","tableName":"aggregate:1sx56i91c6nbxb:#group","value":{"issue_id":"i2","_0_key":"si2","_0_value":2,"_0_version":"02"}},{"op":"put","tableName":"comments","value":{"id":"x1","authorId":"u1","issue_id":"i2","text":"","createdAt":1}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p2","cookie":"02"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p3","baseCookie":"02"}]},{"op":"receive","message":["pokePart",{"pokeID":"p3","lastMutationIDChanges":{"$clientID":1},"rowsPatch":[{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i1","_0_value":3,"_0_version":"03"}},{"op":"put","tableName":"comments","value":{"id":"c9","authorId":"u1","issue_id":"i1","text":"","createdAt":9}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p3","cookie":"03"}]},{"op":"advance","ms":2000},{"op":"restart"},{"op":"materialize","view":"v0","query":"aggregates.commentCounts"},{"op":"materialize","view":"v2","query":"aggregates.commentsByIssue"},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":0},"v3":{"data":0,"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":0},"v3":{"data":0,"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":0},"v3":{"data":0,"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000},{"op":"put","hash":"0puwc8m0bnu56k","name":"aggregates.commentTimes","args":[],"ttl":300000},{"op":"put","hash":"1sx56i91c6nbxb","name":"aggregates.commentsByIssue","args":[],"ttl":300000},{"op":"put","hash":"0oql89w09s2pr4","name":"aggregates.issueCount","args":[],"ttl":300000},{"op":"put","hash":"0rsht6z1lahgep","name":"bughunt.allComments","args":[],"ttl":300000},{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":0},"v3":{"data":0,"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000},{"op":"put","hash":"0puwc8m0bnu56k","name":"aggregates.commentTimes","args":[],"ttl":300000},{"op":"put","hash":"1sx56i91c6nbxb","name":"aggregates.commentsByIssue","args":[],"ttl":300000},{"op":"put","hash":"0oql89w09s2pr4","name":"aggregates.issueCount","args":[],"ttl":300000},{"op":"put","hash":"0rsht6z1lahgep","name":"bughunt.allComments","args":[],"ttl":300000},{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":0},"v3":{"data":0,"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":0},"v3":{"data":0,"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"v2":{"data":[],"resultType":"unknown","notifications":0},"v3":{"data":0,"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":2},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":6},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":null}],"resultType":"complete","notifications":2},"v2":{"data":[{"issueId":"i1","count":2},{"issueId":"i2","count":1}],"resultType":"complete","notifications":2},"v3":{"data":3,"resultType":"complete","notifications":2},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":2},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":2}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":6},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":null}],"resultType":"complete","notifications":0},"v2":{"data":[{"issueId":"i1","count":2},{"issueId":"i2","count":1}],"resultType":"complete","notifications":0},"v3":{"data":3,"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"sent":[["push",{"timestamp":1700000000020,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000020,"id":1,"clientID":"$clientID","name":"harden.ops","args":[{"ops":[{"op":"insert","table":"comment","value":{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":9}}]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":1},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":7},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":2},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":null}],"resultType":"complete","notifications":1},"v2":{"data":[{"issueId":"i1","count":3},{"issueId":"i2","count":1}],"resultType":"complete","notifications":1},"v3":{"data":3,"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2},{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":9}],"resultType":"complete","notifications":1},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000020,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000020,"id":2,"clientID":"$clientID","name":"harden.ops","args":[{"ops":[{"op":"delete","table":"comment","value":{"id":"c3"}}]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":0},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":1},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":7},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":null},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":null}],"resultType":"complete","notifications":1},"v2":{"data":[{"issueId":"i1","count":3}],"resultType":"complete","notifications":1},"v3":{"data":3,"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":9}],"resultType":"complete","notifications":1},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["push",{"timestamp":1700000000020,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000020,"id":3,"clientID":"$clientID","name":"harden.ops","args":[{"ops":[{"op":"update","table":"comment","value":{"id":"c1","issueId":"i3"}}]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":0},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":1}],"resultType":"complete","notifications":1},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":8},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":null},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":5}],"resultType":"complete","notifications":1},"v2":{"data":[{"issueId":"i1","count":2},{"issueId":"i3","count":1}],"resultType":"complete","notifications":1},"v3":{"data":3,"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i3","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":9}],"resultType":"complete","notifications":1},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":0},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":1}],"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":8},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":null},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":5}],"resultType":"complete","notifications":0},"v2":{"data":[{"issueId":"i1","count":2},{"issueId":"i3","count":1}],"resultType":"complete","notifications":0},"v3":{"data":3,"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i3","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":9}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":0},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":1}],"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":8},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":null},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":5}],"resultType":"complete","notifications":0},"v2":{"data":[{"issueId":"i1","count":2},{"issueId":"i3","count":1}],"resultType":"complete","notifications":0},"v3":{"data":3,"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i3","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":9}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":0},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":1}],"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":8},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":null},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":5}],"resultType":"complete","notifications":0},"v2":{"data":[{"issueId":"i1","count":2},{"issueId":"i3","count":1}],"resultType":"complete","notifications":0},"v3":{"data":3,"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i3","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":9}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":1}],"resultType":"complete","notifications":1},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":8},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":null},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":5}],"resultType":"complete","notifications":0},"v2":{"data":[{"issueId":"i1","count":2},{"issueId":"i2","count":1},{"issueId":"i3","count":1}],"resultType":"complete","notifications":1},"v3":{"data":3,"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i3","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":9},{"id":"x1","authorId":"u1","issueId":"i2","text":"","createdAt":1}],"resultType":"complete","notifications":1},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":1}],"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":8},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":null},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":5}],"resultType":"complete","notifications":0},"v2":{"data":[{"issueId":"i1","count":2},{"issueId":"i2","count":1},{"issueId":"i3","count":1}],"resultType":"complete","notifications":0},"v3":{"data":3,"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i3","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":9},{"id":"x1","authorId":"u1","issueId":"i2","text":"","createdAt":1}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":1}],"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":8},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":null},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":5}],"resultType":"complete","notifications":0},"v2":{"data":[{"issueId":"i1","count":2},{"issueId":"i2","count":1},{"issueId":"i3","count":1}],"resultType":"complete","notifications":0},"v3":{"data":3,"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i3","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":9},{"id":"x1","authorId":"u1","issueId":"i2","text":"","createdAt":1}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":1}],"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":8},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":null},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":5}],"resultType":"complete","notifications":0},"v2":{"data":[{"issueId":"i1","count":2},{"issueId":"i2","count":1},{"issueId":"i3","count":1}],"resultType":"complete","notifications":0},"v3":{"data":3,"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i3","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":9},{"id":"x1","authorId":"u1","issueId":"i2","text":"","createdAt":1}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":1}],"resultType":"complete","notifications":1},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":7},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":null},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":5}],"resultType":"complete","notifications":1},"v2":{"data":[{"issueId":"i1","count":1},{"issueId":"i2","count":1},{"issueId":"i3","count":1}],"resultType":"complete","notifications":1},"v3":{"data":3,"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i3","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":9},{"id":"x1","authorId":"u1","issueId":"i2","text":"","createdAt":1}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":{"type":"success"}},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":1}],"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":7},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":null},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":5}],"resultType":"complete","notifications":0},"v2":{"data":[{"issueId":"i1","count":1},{"issueId":"i2","count":1},{"issueId":"i3","count":1}],"resultType":"complete","notifications":0},"v3":{"data":3,"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i3","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c9","authorId":"u1","issueId":"i1","text":"","createdAt":9},{"id":"x1","authorId":"u1","issueId":"i2","text":"","createdAt":1}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":{"type":"success"}},"m2":{"client":{"type":"success"},"server":"pending"},"m3":{"client":{"type":"success"},"server":"pending"}}},{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie","03"],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"activeClients":["$clientID"]}]}}],"closed":[0],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":1}],"resultType":"cached","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":1}],"resultType":"cached","notifications":0},"v2":{"data":[{"issueId":"i1","count":1},{"issueId":"i2","count":1},{"issueId":"i3","count":1}],"resultType":"cached","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":1}],"resultType":"cached","notifications":0},"v2":{"data":[{"issueId":"i1","count":1},{"issueId":"i2","count":1},{"issueId":"i3","count":1}],"resultType":"cached","notifications":0}}}]}, +{"name":"bughunt: after a restart, registering a groupBy moves it by a mutation made since","steps":[{"op":"advance","ms":0},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"mutate","mutation":"m1","mutator":"issue.create","args":{"id":"i9"}},{"op":"advance","ms":2000},{"op":"restart"},{"op":"advance","ms":0},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"mutate","mutation":"m2","mutator":"comment.add","args":{"id":"c9","issueId":"i1"}},{"op":"advance","ms":10},{"op":"materialize","view":"v","query":"aggregates.commentsByIssue"},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connected"}},{"state":{"name":"connected"}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"issue.create","args":[{"id":"i9"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"closed":[0],"state":{"name":"connecting"}},{"state":{"name":"connecting"}},{"sent":[["push",{"timestamp":1700000002010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID.0","name":"issue.create","args":[{"id":"i9"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"}},{"state":{"name":"connected"}},{"sent":[["push",{"timestamp":1700000002020,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000002020,"id":1,"clientID":"$clientID","name":"comment.add","args":[{"id":"c9","issueId":"i1"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"mutations":{"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"mutations":{"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}},"mutations":{"m2":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1sx56i91c6nbxb","name":"aggregates.commentsByIssue","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}},"mutations":{"m2":{"client":{"type":"success"},"server":"pending"}}}]}, +{"name":"bughunt: after a restart, registering a relationship count moves it by a mutation made since","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"aggregates.commentCounts"},{"op":"materialize","view":"comments","query":"bughunt.allComments"},{"op":"materialize","view":"issues","query":"issues.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr"},{"op":"put","hash":"0rsht6z1lahgep"},{"op":"put","hash":"1y7zr0i1xir4ek"}],"rowsPatch":[{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i1","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i2","_0_value":1,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"aggregate:0u3s9wi0kzvflr:comments","value":{"issue_id":"i3","_0_value":0,"_0_version":"01"}},{"op":"put","tableName":"comments","value":{"id":"c1","authorId":"u1","issue_id":"i1","text":"","createdAt":5}},{"op":"put","tableName":"comments","value":{"id":"c2","authorId":"u2","issue_id":"i1","text":"","createdAt":7}},{"op":"put","tableName":"comments","value":{"id":"c3","authorId":"u1","issue_id":"i2","text":"","createdAt":2}},{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"advance","ms":10},{"op":"mutate","mutation":"m1","mutator":"issue.create","args":{"id":"i9"}},{"op":"advance","ms":2000},{"op":"restart"},{"op":"advance","ms":0},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"mutate","mutation":"m2","mutator":"comment.add","args":{"id":"c9","issueId":"i1"}},{"op":"advance","ms":10},{"op":"materialize","view":"v","query":"aggregates.commentCounts"},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000},{"op":"put","hash":"0rsht6z1lahgep","name":"bughunt.allComments","args":[],"ttl":300000},{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000},{"op":"put","hash":"0rsht6z1lahgep","name":"bughunt.allComments","args":[],"ttl":300000},{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":2},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":2},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":2}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0}],"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"sent":[["push",{"timestamp":1700000000020,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000020,"id":1,"clientID":"$clientID","name":"issue.create","args":[{"id":"i9"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0},{"id":"i9","title":"","description":"","closed":false,"ownerId":null,"createdAt":1,"comments":0}],"resultType":"complete","notifications":1},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5},{"id":"i9","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0},{"id":"i9","title":"","description":"","closed":false,"ownerId":null,"createdAt":1,"comments":0}],"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5},{"id":"i9","title":"","description":"","closed":false,"ownerId":null,"createdAt":1}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie","01"],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"activeClients":["$clientID"]}]}}],"closed":[0],"state":{"name":"connecting"}},{"state":{"name":"connecting"}},{"sent":[["push",{"timestamp":1700000002020,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000020,"id":1,"clientID":"$clientID.0","name":"issue.create","args":[{"id":"i9"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"}},{"state":{"name":"connected"}},{"sent":[["push",{"timestamp":1700000002030,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000002030,"id":1,"clientID":"$clientID","name":"comment.add","args":[{"id":"c9","issueId":"i1"}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"mutations":{"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"mutations":{"m2":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0},{"id":"i9","title":"","description":"","closed":false,"ownerId":null,"createdAt":1,"comments":0}],"resultType":"cached","notifications":1}},"mutations":{"m2":{"client":{"type":"success"},"server":"pending"}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0u3s9wi0kzvflr","name":"aggregates.commentCounts","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"comments":2},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4,"comments":1},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"comments":0},{"id":"i9","title":"","description":"","closed":false,"ownerId":null,"createdAt":1,"comments":0}],"resultType":"cached","notifications":0}},"mutations":{"m2":{"client":{"type":"success"},"server":"pending"}}}]}, +{"name":"bughunt: after a restart, a groupBy first materialized is moved by a mutation from before","steps":[{"op":"advance","ms":0},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"mutate","mutation":"m1","mutator":"issue.create","args":{"id":"i9","closed":true}},{"op":"advance","ms":2000},{"op":"restart"},{"op":"advance","ms":0},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"materialize","view":"v","query":"aggregates.countByState"},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connected"}},{"state":{"name":"connected"}},{"sent":[["push",{"timestamp":1700000000010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID","name":"issue.create","args":[{"id":"i9","closed":true}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"closed":[0],"state":{"name":"connecting"}},{"state":{"name":"connecting"}},{"sent":[["push",{"timestamp":1700000002010,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000010,"id":1,"clientID":"$clientID.0","name":"issue.create","args":[{"id":"i9","closed":true}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"}},{"state":{"name":"connected"}},{"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"0ovq3ue0294kbv","name":"aggregates.countByState","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v":{"data":[],"resultType":"unknown","notifications":0}}}]}, +{"name":"bughunt: a sum over a JSON path and a nested relationship count move optimistically","steps":[{"op":"advance","ms":0},{"op":"materialize","view":"v0","query":"bughunt.pointsSum"},{"op":"materialize","view":"v1","query":"bughunt.ownerIssueCounts"},{"op":"materialize","view":"comments","query":"bughunt.allComments"},{"op":"materialize","view":"issues","query":"issues.all"},{"op":"receive","message":["connected",{"wsid":"w1"}]},{"op":"advance","ms":10},{"op":"receive","message":["pokeStart",{"pokeID":"p1","baseCookie":null}]},{"op":"receive","message":["pokePart",{"pokeID":"p1","gotQueriesPatch":[{"op":"put","hash":"1u407mn0mindlm"},{"op":"put","hash":"11zsln70apsm88"},{"op":"put","hash":"0rsht6z1lahgep"},{"op":"put","hash":"1y7zr0i1xir4ek"}],"rowsPatch":[{"op":"put","tableName":"aggregate:1u407mn0mindlm","value":{"_0_key":0,"_0_value":3,"_0_sum":3,"_0_count":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"users","value":{"id":"u1","name":"A","metadata":{"points":1}}},{"op":"put","tableName":"aggregate:11zsln70apsm88:owner.issues","value":{"owner_id":"u1","_0_value":2,"_0_version":"01"}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}},{"op":"put","tableName":"comments","value":{"id":"c1","authorId":"u1","issue_id":"i1","text":"","createdAt":5}},{"op":"put","tableName":"comments","value":{"id":"c2","authorId":"u2","issue_id":"i1","text":"","createdAt":7}},{"op":"put","tableName":"comments","value":{"id":"c3","authorId":"u1","issue_id":"i2","text":"","createdAt":2}},{"op":"put","tableName":"issues","value":{"id":"i1","title":"I1","description":"","closed":false,"owner_id":"u1","createdAt":3}},{"op":"put","tableName":"issues","value":{"id":"i2","title":"I2","description":"","closed":false,"owner_id":null,"createdAt":4}},{"op":"put","tableName":"issues","value":{"id":"i3","title":"I3","description":"","closed":true,"owner_id":"u1","createdAt":5}}]}]},{"op":"receive","message":["pokeEnd",{"pokeID":"p1","cookie":"01"}]},{"op":"advance","ms":10},{"op":"mutate","mutation":"m1","mutator":"harden.ops","args":{"ops":[{"op":"insert","table":"user","value":{"id":"u3","name":"C","metadata":{"points":4}}},{"op":"insert","table":"issue","value":{"id":"i9","title":"","description":"","closed":false,"ownerId":"u1","createdAt":1}}]}},{"op":"advance","ms":10}],"expect":[{"opened":[{"url":{"origin":"ws://zero.test","path":"/sync/v57/connect","query":[["clientID","$clientID"],["clientGroupID","$clientGroupID"],["userID","u1"],["baseCookie",""],["lmid","0"],["wsid","$wsid"],["profileID","$profileID"]]},"protocol":{"initConnectionMessage":["initConnection",{"desiredQueriesPatch":[],"clientSchema":{"tables":{"comments":{"columns":{"authorId":{"type":"string"},"createdAt":{"type":"number"},"id":{"type":"string"},"issue_id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"issueLabel":{"columns":{"issueId":{"type":"string"},"labelId":{"type":"string"}},"primaryKey":["issueId","labelId"]},"issues":{"columns":{"closed":{"type":"boolean"},"createdAt":{"type":"number"},"description":{"type":"string"},"id":{"type":"string"},"owner_id":{"type":"string"},"title":{"type":"string"}},"primaryKey":["id"]},"label":{"columns":{"id":{"type":"string"},"name":{"type":"string"}},"primaryKey":["id"]},"revision":{"columns":{"authorId":{"type":"string"},"commentId":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"primaryKey":["id"]},"users":{"columns":{"id":{"type":"string"},"metadata":{"type":"json"},"name":{"type":"string"}},"primaryKey":["id"]}}},"activeClients":["$clientID"]}]}}],"state":{"name":"connecting"}},{"state":{"name":"connecting"},"views":{"v0":{"data":null,"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":null,"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":null,"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":1}}},{"state":{"name":"connecting"},"views":{"v0":{"data":null,"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":1}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1u407mn0mindlm","name":"bughunt.pointsSum","args":[],"ttl":300000},{"op":"put","hash":"11zsln70apsm88","name":"bughunt.ownerIssueCounts","args":[],"ttl":300000},{"op":"put","hash":"0rsht6z1lahgep","name":"bughunt.allComments","args":[],"ttl":300000},{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":null,"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"sent":[["changeDesiredQueries",{"desiredQueriesPatch":[{"op":"put","hash":"1u407mn0mindlm","name":"bughunt.pointsSum","args":[],"ttl":300000},{"op":"put","hash":"11zsln70apsm88","name":"bughunt.ownerIssueCounts","args":[],"ttl":300000},{"op":"put","hash":"0rsht6z1lahgep","name":"bughunt.allComments","args":[],"ttl":300000},{"op":"put","hash":"1y7zr0i1xir4ek","name":"issues.all","args":[],"ttl":300000}]}]],"state":{"name":"connected"},"views":{"v0":{"data":null,"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":null,"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":null,"resultType":"unknown","notifications":0},"v1":{"data":[],"resultType":"unknown","notifications":0},"comments":{"data":[],"resultType":"unknown","notifications":0},"issues":{"data":[],"resultType":"unknown","notifications":0}}},{"state":{"name":"connected"},"views":{"v0":{"data":3,"resultType":"complete","notifications":2},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"owner":{"id":"u1","name":"A","metadata":{"points":1},"issues":2}},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"owner":{"id":"u1","name":"A","metadata":{"points":1},"issues":2}}],"resultType":"complete","notifications":2},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":2},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":2}}},{"state":{"name":"connected"},"views":{"v0":{"data":3,"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"owner":{"id":"u1","name":"A","metadata":{"points":1},"issues":2}},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"owner":{"id":"u1","name":"A","metadata":{"points":1},"issues":2}}],"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5}],"resultType":"complete","notifications":0}}},{"sent":[["push",{"timestamp":1700000000020,"clientGroupID":"$clientGroupID","mutations":[{"type":"custom","timestamp":1700000000020,"id":1,"clientID":"$clientID","name":"harden.ops","args":[{"ops":[{"op":"insert","table":"user","value":{"id":"u3","name":"C","metadata":{"points":4}}},{"op":"insert","table":"issue","value":{"id":"i9","title":"","description":"","closed":false,"ownerId":"u1","createdAt":1}}]}]}],"pushVersion":1,"requestID":"$requestID"}]],"state":{"name":"connected"},"views":{"v0":{"data":3,"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"owner":{"id":"u1","name":"A","metadata":{"points":1},"issues":3}},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"owner":{"id":"u1","name":"A","metadata":{"points":1},"issues":3}},{"id":"i9","title":"","description":"","closed":false,"ownerId":"u1","createdAt":1,"owner":{"id":"u1","name":"A","metadata":{"points":1},"issues":3}}],"resultType":"complete","notifications":1},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5},{"id":"i9","title":"","description":"","closed":false,"ownerId":"u1","createdAt":1}],"resultType":"complete","notifications":1}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}},{"state":{"name":"connected"},"views":{"v0":{"data":3,"resultType":"complete","notifications":0},"v1":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3,"owner":{"id":"u1","name":"A","metadata":{"points":1},"issues":3}},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5,"owner":{"id":"u1","name":"A","metadata":{"points":1},"issues":3}},{"id":"i9","title":"","description":"","closed":false,"ownerId":"u1","createdAt":1,"owner":{"id":"u1","name":"A","metadata":{"points":1},"issues":3}}],"resultType":"complete","notifications":0},"comments":{"data":[{"id":"c1","authorId":"u1","issueId":"i1","text":"","createdAt":5},{"id":"c2","authorId":"u2","issueId":"i1","text":"","createdAt":7},{"id":"c3","authorId":"u1","issueId":"i2","text":"","createdAt":2}],"resultType":"complete","notifications":0},"issues":{"data":[{"id":"i1","title":"I1","description":"","closed":false,"ownerId":"u1","createdAt":3},{"id":"i2","title":"I2","description":"","closed":false,"ownerId":null,"createdAt":4},{"id":"i3","title":"I3","description":"","closed":true,"ownerId":"u1","createdAt":5},{"id":"i9","title":"","description":"","closed":false,"ownerId":"u1","createdAt":1}],"resultType":"complete","notifications":0}},"mutations":{"m1":{"client":{"type":"success"},"server":"pending"}}}]} +]} diff --git a/swift/DESIGN.md b/swift/DESIGN.md index 7120b45b9d..b20a58138c 100644 --- a/swift/DESIGN.md +++ b/swift/DESIGN.md @@ -108,7 +108,7 @@ Rationale: - SQLite (system `libsqlite3`), WAL mode, `synchronous = NORMAL`. - One database file per JS database name. The name covers the user, the storage key, the mutate and query URLs, the client schema's hash, and the storage version, so a schema change starts a new database as in JS. The file name is a hash of it plus a Swift layout version. - The file holds the client groups, the clients with their heartbeats, the deleted clients the server hasn't confirmed, and per client group the last server snapshot and the pending mutations. At launch the client joins the group with its set of mutator names (client group forking is off in Zero) and replays the pending mutations over the snapshot, as a rebase does. -- Changes are written through. The clients and groups are mirrored in memory, so every decision is made on the main actor in the JS order. The writes run in order on a background queue, one transaction per mutation or poke. JS persists about a second after a change; the Swift client writes right away. +- Changes are written through. The clients and groups are mirrored in memory, so every decision is made on the main actor in the JS order. The writes run in order on a background queue, one transaction per mutation or poke. JS persists about a second after a change; the Swift client writes right away. The one thing that timing decides is which synced aggregates a pending mutation's stored writes move: those registered when JS persists. So Swift keeps that schedule for them only: about a second after a mutation or poke, it reruns the mutations not yet persisted and stores the `a/` rows each wrote, which a relaunch puts back. - The client lifecycle follows Replicache: a heartbeat every minute; every five minutes, clients inactive for a day are deleted (and the server told with `deleteClients`, and in `initConnection` until it confirms) and client groups without clients are dropped; five minutes after launch and then every 12 hours, databases no client used for two days are deleted. Only our databases are: of this layout version or an older one, holding their name, and of a format the client knows. The collector reads the files in the background; the main actor then keeps any opened or closed since and renames the others away before they are deleted, so a client opening one meanwhile starts a new file. A group is disabled after `ClientNotFound`, `SchemaVersionNotSupported`, or a 1009 close, and the database dropped after `InvalidConnectionRequestBaseCookie` or `InvalidConnectionRequestLastMutationID`. - `ZeroStorage.memory` keeps databases for the life of the process, keyed by name, like JS `kvStore: 'mem'`. The client scenarios run on both storages. - Default location `Library/Application Support/Zero` on Apple platforms and `$XDG_DATA_HOME/zero` elsewhere, configurable (for example an App Group container). diff --git a/swift/Sources/Zero/Client/Engine.swift b/swift/Sources/Zero/Client/Engine.swift index 2180d74c70..fc09ae633f 100644 --- a/swift/Sources/Zero/Client/Engine.swift +++ b/swift/Sources/Zero/Client/Engine.swift @@ -124,9 +124,11 @@ final class Engine { private var deletedClients: DeleteClientsBody? private var lastMutationIDReceived: Double = 0 private var lastMutationIDsSent: [String: Double] = [:] - /// The last mutation ID of each client pending at launch: the mutations - /// `rebasePending` stands in for JS's persisted writes of. - private var launchPendingIDs: [String: Double] = [:] + /// What the store holds of the replica as JS would have persisted it; + /// see `persist`. + private var persisted = PersistedState(cookie: .null, main: KVMap(), touched: [], mutations: []) + private var persistTimer: (any ScheduledTimer)? + private var lastPersistAt: Double? private var additionalConnectParams: [(String, String)]? private var currentAttempt: ConnectAttempt? private var connectionReady = ReadyPromise() @@ -232,6 +234,9 @@ final class Engine { id: $0.id, clientID: $0.clientID, name: $0.name, args: $0.args, timestamp: $0.timestamp, writes: []) }) + let storedAggregateWrites = Dictionary( + mutations.map { (MutationKey(clientID: $0.clientID, id: $0.id), $0.aggregateWrites) }, + uniquingKeysWith: { $1 }) self.ivmMain = IVMBranch(schema: schema) let loop = self.loop self.connectionManager = ConnectionManager( @@ -261,7 +266,6 @@ final class Engine { guard case .closed(let reason) = self?.connectionManager.state else { return nil } return reason }) - context.rebasePending = { [weak self] in try self?.rebasePending() } _ = connectionManager.subscribe { [weak self] state in self?.onConnectionStateChange(state) } onConnectionStateChange(connectionManager.state) queryManager = QueryManager( @@ -286,15 +290,19 @@ final class Engine { }) // Load the snapshot into the sources and replay the pending mutations - // on it. + // on it, with the synced aggregate rows they wrote when they were last + // persisted, as JS's stored commits have them. ivmMain.apply(KVDiff.between(KVMap(), store.snapshot.map)) if !store.pending.isEmpty { - for m in store.pending { launchPendingIDs[m.clientID] = m.id } let (main, replayed, touched, _) = replay( - store.pending, over: store.snapshot.map, branch: ivmMain.fork()) + store.pending, over: store.snapshot.map, branch: ivmMain.fork(), + restoring: storedAggregateWrites) ivmMain.apply( store.advance(to: store.snapshot, main: main, pending: replayed, touched: touched)) } + persisted = PersistedState( + cookie: store.snapshot.cookie, main: store.main, touched: store.pendingWrites, + mutations: Set(store.pending.map(MutationKey.init))) database.addWriteFailureListener(clientID) { [weak self] failure in self?.storageFailed(failure) } @@ -1146,6 +1154,9 @@ final class Engine { repClosed = true pushTimer?.cancel() pushTimer = nil + // JS's close aborts a persist that hasn't run. + persistTimer?.cancel() + persistTimer = nil for t in lifecycleTimers { t.cancel() } lifecycleTimers = [] database.clientStopped(clientID) @@ -1387,7 +1398,7 @@ final class Engine { group: clientGroupID, StoredMutation( clientID: clientID, id: mutationID, name: name, args: pending.args, - timestamp: pending.timestamp)) + timestamp: pending.timestamp, aggregateWrites: Self.aggregateWrites(write))) ]) do { try context.processChanges(diff, rows: tx.rows) @@ -1402,6 +1413,7 @@ final class Engine { } requestPush(now: false) fireWatchers(diff) + schedulePersist() client.resolve(.success(data: result)) } @@ -1566,6 +1578,7 @@ final class Engine { // A push that fails is a poke error: the client disconnects. try context.processChanges(diff) fireWatchers(diff) + schedulePersist() markGotQueriesAuthoritative(ifStillOn: socketAtStart) } @@ -1578,36 +1591,19 @@ final class Engine { } } - /// Runs the pending mutations again over the server snapshot, as a poke - /// that changes nothing would, so they move the synced aggregates a query - /// registered since they last ran. Only while a mutation replayed at - /// launch is pending: JS kept the moves it made before the restart, but a - /// mutation made since moved only what was registered then, until the - /// next rebase. Not while a mutator runs: the next rebase replays them then. - private func rebasePending() throws { - guard !writeLocked, - store.pending.contains(where: { $0.id <= launchPendingIDs[$0.clientID] ?? 0 }) - else { return } - try withWriteLock { - let snapshot = store.snapshot - let touched = store.pendingWrites - let branch = ivmMain.fork() - branch.apply(KVDiff.between(store.main, snapshot.map, keys: touched)) - let rebased = replay(store.pending, over: snapshot.map, branch: branch) - let diff = store.advance( - to: snapshot, main: rebased.main, pending: rebased.replayed, - touched: touched.union(rebased.touched)) - try context.processChanges(diff) - fireWatchers(diff) - } - } - /// Runs `pending` again, in order, over `map` and on forks of `branch` /// (the rebase of `maybeEndPull`). A mutation that throws stays pending /// without writes. Returns the new main map, the mutations with what they /// wrote, every key they wrote, and the branch they ran on. + /// + /// At launch, no query has registered the synced aggregates a mutation + /// moves yet, so each run puts back the aggregate rows `restoring` has for + /// the mutation, as JS's stored commit holds them. `ran` hears each + /// mutation with its write, nil when it threw. private func replay( - _ pending: [ReplicaStore.PendingMutation], over map: KVMap, branch: IVMBranch + _ pending: [ReplicaStore.PendingMutation], over map: KVMap, branch: IVMBranch, + restoring: [MutationKey: [JSKey: JSONValue?]] = [:], + ran: (ReplicaStore.PendingMutation, KVWrite?) -> Void = { _, _ in } ) -> (main: KVMap, replayed: [ReplicaStore.PendingMutation], touched: Set, IVMBranch) { var main = map var branch = branch @@ -1630,19 +1626,112 @@ final class Engine { throw ApplicationError("Unknown mutator: \(m.name)") } _ = try mutator(tx, m.args) + for (key, value) in restoring[MutationKey(m)] ?? [:] { + if let value { write.set(key.string, value) } else { write.delete(key.string) } + } main = write.map branch = fork m.writes = write.writes touched.formUnion(write.writes) + ran(m, write) } catch { // The mutation stays pending; its writes are dropped. m.writes = [] + ran(m, nil) } replayed.append(m) } return (main, replayed, touched, branch) } + /// The synced aggregate rows `write` wrote, with their values now. + private static func aggregateWrites(_ write: KVWrite) -> [JSKey: JSONValue?] { + var writes: [JSKey: JSONValue?] = [:] + for key in write.writes where key.string.hasPrefix(Keys.aggregatesPrefix) { + writes[key] = .some(write.get(key.string)) + } + return writes + } + + /// A pending mutation's identity. + private struct MutationKey: Hashable { + let clientID: String + let id: Double + init(clientID: String, id: Double) { + self.clientID = clientID + self.id = id + } + init(_ m: ReplicaStore.PendingMutation) { self.init(clientID: m.clientID, id: m.id) } + } + + /// The replica as JS's last persist left it in the store: the snapshot it + /// persisted (by cookie), its main map over that snapshot, the keys where + /// the two may differ, and the pending mutations it ran. + private struct PersistedState { + var cookie: JSONValue + var main: KVMap + var touched: Set + var mutations: Set + } + + /// `PERSIST_IDLE_TIMEOUT_MS` and `PERSIST_THROTTLE_MS`. + static let persistIdleTimeoutMs: Double = 1000 + static let persistThrottleMs: Double = 500 + + /// Replicache's persist scheduler (`ProcessScheduler`): after a mutation + /// or a poke, a persist runs once the last one is `persistThrottleMs` + /// old, then after `persistIdleTimeoutMs`; requests while one waits join + /// it. + private func schedulePersist() { + guard persistTimer == nil, !repClosed else { return } + let now = scheduler.monotonicNow + let throttled = lastPersistAt.map { max(0, $0 + Self.persistThrottleMs - now) } ?? 0 + persistTimer = scheduler.schedule(after: throttled + Self.persistIdleTimeoutMs) { + [weak self] in self?.persist() + } + } + + /// `persistDD31`, for the synced aggregate rows the store keeps of each + /// pending mutation. Swift writes the snapshot and the mutations through + /// as they come, and replays the mutations at launch; JS persists its + /// commits now and then, running the mutations again for it, so the + /// aggregates they move are the ones registered at that persist, not + /// when they ran. A persist runs the mutations it hasn't persisted over + /// what it persisted before, or, when the snapshot is newer, all of them + /// over it, and stores the aggregate rows each wrote. + private func persist() { + persistTimer = nil + lastPersistAt = scheduler.monotonicNow + let pending = store.pending + let toRun: [ReplicaStore.PendingMutation] + if persisted.cookie != store.snapshot.cookie { + persisted.cookie = store.snapshot.cookie + persisted.main = store.snapshot.map + persisted.touched = [] + toRun = pending + } else { + toRun = pending.filter { !persisted.mutations.contains(MutationKey($0)) } + } + persisted.mutations = Set(pending.map(MutationKey.init)) + guard !toRun.isEmpty else { return } + // The persist runs over a fork of the views' branch moved to what it + // persisted. + let branch = ivmMain.fork() + branch.apply( + KVDiff.between( + store.main, persisted.main, keys: store.pendingWrites.union(persisted.touched))) + var ops: [StorageOp] = [] + let rebased = replay(toRun, over: persisted.main, branch: branch) { m, write in + ops.append( + .setAggregateWrites( + group: clientGroupID, clientID: m.clientID, id: m.id, + write.map(Self.aggregateWrites) ?? [:])) + } + persisted.main = rebased.main + persisted.touched.formUnion(rebased.touched) + database.apply(ops) + } + /// `JSON.stringify(recentSentMessages, null, 2)`. static func prettyRecentMessages(_ messages: [JSONValue]) -> String { let entries = messages.map { m in diff --git a/swift/Sources/Zero/Client/IVMBranch.swift b/swift/Sources/Zero/Client/IVMBranch.swift index c046e103bf..c55f804db8 100644 --- a/swift/Sources/Zero/Client/IVMBranch.swift +++ b/swift/Sources/Zero/Client/IVMBranch.swift @@ -14,9 +14,6 @@ final class IVMBranch { /// Only the main branch registers optimistic aggregates and releases /// aggregate sources (see `aggregateSource`). private let isFork: Bool - /// Set when an aggregate's optimism is registered for the first time - /// since it was released, or since launch; see `takeNewRegistration`. - private var newRegistration = false convenience init(schema: ZeroSchema) { self.init( @@ -68,7 +65,6 @@ final class IVMBranch { // A fork's queries are never synced, so only the main branch, which // releases them, registers. if let optimistic, !isFork { - if optimism.byTable[optimistic.table]?[name] == nil { newRegistration = true } optimism.byTable[optimistic.table, default: [:]][name] = optimistic } if let existing = sources[name] ?? nil { return existing } @@ -77,17 +73,6 @@ final class IVMBranch { return source } - /// Whether an aggregate's optimism was registered for the first time since - /// the last call. Swift only: JS persists a pending mutation's writes, so - /// after a restart its view still has the moves the mutation made. Swift - /// stores the mutation and replays it at launch, before any query - /// registers, so the client rebases the pending mutations once one does, - /// while one replayed at launch is pending. - func takeNewRegistration() -> Bool { - defer { newRegistration = false } - return newRegistration - } - /// `serverColumnNames`: the server names of `columns` of `table`. func serverColumnNames(_ table: String, _ columns: [String]) -> [String] { let tableColumns = schema.tables[table]?.columns diff --git a/swift/Sources/Zero/Client/QueryContext.swift b/swift/Sources/Zero/Client/QueryContext.swift index 884457cf49..e35d489155 100644 --- a/swift/Sources/Zero/Client/QueryContext.swift +++ b/swift/Sources/Zero/Client/QueryContext.swift @@ -166,10 +166,6 @@ final class QueryContext { /// on, and every later push, `materialize`, and mutation fails with it. private(set) var branchFailure: PipelineError? - /// Rebases the pending mutations over the server snapshot. The engine - /// sets it; see `IVMBranch.takeNewRegistration`. - var rebasePending: () throws -> Void = {} - /// Pushes `diff` into the branch and flushes the views. A push an /// operator fails (where JS throws from it) still flushes what the views /// got, as JS's `finally` does, and then throws. @@ -280,10 +276,6 @@ final class QueryContext { } // A view of a grouped query shows only its columns and value. input = ast.groupBy != nil ? try groupViewInput(pipeline, ast, delegate) : pipeline - // The pending mutations moved no synced aggregate the query now lets - // them move; rebasing them does, before the view hydrates. The new - // pipeline has no output yet, so it drops what the rebase pushes. - if branch.takeNewRegistration() { try rebasePending() } } catch { removeAddedQuery() throw error diff --git a/swift/Sources/Zero/Storage/ReplicaDatabase.swift b/swift/Sources/Zero/Storage/ReplicaDatabase.swift index 7295d9627e..49c3867058 100644 --- a/swift/Sources/Zero/Storage/ReplicaDatabase.swift +++ b/swift/Sources/Zero/Storage/ReplicaDatabase.swift @@ -111,6 +111,11 @@ struct StoredMutation: Sendable, Hashable { let args: JSONValue /// `performance.now()` of the client that made it. let timestamp: Double + /// The synced aggregate rows (`a/` keys) its last run wrote, with their + /// values after it (nil for deleted). JS persists them in the mutation's + /// commit; Swift runs the mutation again at launch, before any query + /// registers the aggregates it moves, and puts these back. + var aggregateWrites: [JSKey: JSONValue?] = [:] } /// What a client group keeps: the last server snapshot and the mutations @@ -138,6 +143,8 @@ enum StorageOp: Sendable { group: String, changes: [(String, JSONValue?)], cleared: Bool, cookie: JSONValue, lastMutationIDs: [JSKey: Double]) case addMutation(group: String, StoredMutation) + /// What a rebase of a pending mutation wrote to synced aggregate rows. + case setAggregateWrites(group: String, clientID: String, id: Double, [JSKey: JSONValue?]) /// Drops the mutations the IDs confirm, keeping the snapshot. case deleteConfirmedMutations(group: String, lastMutationIDs: [JSKey: Double]) } @@ -446,7 +453,7 @@ final class ReplicaDatabase { deletedClients = pairs case .setProfileID(let id): profileID = id - case .updateSnapshot, .addMutation, .deleteConfirmedMutations: + case .updateSnapshot, .addMutation, .setAggregateWrites, .deleteConfirmedMutations: break } } @@ -469,6 +476,13 @@ final class ReplicaDatabase { memoryGroups![group] = g case .addMutation(let group, let m): memoryGroups![group, default: StoredGroup()].mutations.append(m) + case .setAggregateWrites(let group, let clientID, let id, let writes): + guard + let i = memoryGroups![group]?.mutations.firstIndex(where: { + $0.clientID == clientID && $0.id == id + }) + else { break } + memoryGroups![group]!.mutations[i].aggregateWrites = writes case .deleteConfirmedMutations(let group, let lmids): memoryGroups![group]?.mutations.removeAll { $0.id <= lmids[JSKey($0.clientID)] ?? 0 } case .putClient, .deleteClients, .setDeletedClients, .setProfileID: @@ -751,6 +765,14 @@ final class SQLiteStore: @unchecked Sendable { timestamp REAL NOT NULL ); """) + // Added for synced aggregates; a database from before them lacks it. + var hasAggregateWrites = false + try db.query("SELECT 1 FROM pragma_table_info('mutations') WHERE name = 'aggregate_writes'") { + _ in hasAggregateWrites = true + } + if !hasAggregateWrites { + try db.execute("ALTER TABLE mutations ADD COLUMN aggregate_writes TEXT NOT NULL DEFAULT '[]'") + } try db.run( "INSERT INTO meta (key, value) VALUES ('name', ?) ON CONFLICT (key) DO NOTHING", [.text(name)]) @@ -1048,13 +1070,17 @@ final class SQLiteStore: @unchecked Sendable { case .addMutation(let group, let m): try db.run( """ - INSERT INTO mutations (client_group_id, client_id, id, name, args, timestamp) - VALUES (?, ?, ?, ?, ?, ?) + INSERT INTO mutations (client_group_id, client_id, id, name, args, timestamp, aggregate_writes) + VALUES (?, ?, ?, ?, ?, ?, ?) """, [ .text(group), .text(m.clientID), .real(m.id), .text(m.name), json(m.args), - .real(m.timestamp), + .real(m.timestamp), json(Self.encode(m.aggregateWrites)), ]) + case .setAggregateWrites(let group, let clientID, let id, let writes): + try db.run( + "UPDATE mutations SET aggregate_writes = ? WHERE client_group_id = ? AND client_id = ? AND id = ?", + [json(Self.encode(writes)), .text(group), .text(clientID), .real(id)]) } } @@ -1073,18 +1099,44 @@ final class SQLiteStore: @unchecked Sendable { } try db.query( """ - SELECT client_id, id, name, args, timestamp FROM mutations + SELECT client_id, id, name, args, timestamp, aggregate_writes FROM mutations WHERE client_group_id = ? ORDER BY seq """, [.text(id)] ) { row in g.mutations.append( StoredMutation( clientID: row.text(0), id: row.real(1), name: row.text(2), - args: try JSONParser.parse(row.bytes(3)), timestamp: row.real(4))) + args: try JSONParser.parse(row.bytes(3)), timestamp: row.real(4), + aggregateWrites: try decode(JSONParser.parse(row.bytes(5))))) } return g } + /// A mutation's aggregate writes as `[[key, value or null], ...]`, by key. + static func encode(_ writes: [JSKey: JSONValue?]) -> JSONValue { + .array( + writes.sorted { StringCompare.utf16Less($0.key.string, $1.key.string) }.map { + .array([.string($0.key.string), $0.value ?? .null]) + }) + } + + static func decode(_ json: JSONValue) throws -> [JSKey: JSONValue?] { + var writes: [JSKey: JSONValue?] = [:] + for pair in json.arrayValue ?? [] { + guard let key = pair[0]?.stringValue, let value = pair[1] else { + throw ReplicaDatabase.CorruptData(description: "Bad aggregate writes: \(json)") + } + // A row is an object; null marks a deleted one. (Not a ternary: its + // `nil` would be `JSONValue.null`.) + if value == .null { + writes[JSKey(key)] = .some(nil) + } else { + writes[JSKey(key)] = .some(value) + } + } + return writes + } + /// The profile ID of every database in `directory`, made the first time /// (JS keeps one per browser profile). static func profileID(in directory: String) throws -> String { diff --git a/swift/Tests/ConformanceTests/BugHuntTests.swift b/swift/Tests/ConformanceTests/BugHuntTests.swift index 23ed696d11..0e21175d3e 100644 --- a/swift/Tests/ConformanceTests/BugHuntTests.swift +++ b/swift/Tests/ConformanceTests/BugHuntTests.swift @@ -4,12 +4,25 @@ import ZeroTesting @testable import Zero -/// The aggregate bug hunt (`packages/zero-conformance/src/ivm/bughunt.test.ts`): -/// JS-generated aggregate, distinct and groupBy cases over datasets with the -/// values a port most likely gets wrong. Each checked-in case is its own test. +/// The aggregate bug hunt (`packages/zero-conformance/src/client/bughunt.test.ts` +/// and `src/ivm/bughunt.test.ts`): JS-generated aggregate, distinct and +/// groupBy cases over the values and client histories (restarts, pending +/// mutations) a port most likely gets wrong. Each checked-in case is its own +/// test. @Suite(.enabled(if: Vectors.available)) @MainActor struct BugHuntTests { + /// The random client scenarios, all of them: reports the first mismatches. + @Test(.enabled(if: Vectors.generatedAvailable)) func clientFuzzOnMemory() throws { + try Self.runFuzz(storage: .memory) + } + + @Test(.enabled(if: Vectors.generatedAvailable)) func clientFuzzOnSQLite() throws { + let directory = NSTemporaryDirectory() + "zero-bughunt-" + UUID().uuidString + defer { try? FileManager.default.removeItem(atPath: directory) } + try Self.runFuzz(storage: .sqlite(directory: directory)) + } + nonisolated static let ivmNames: [String] = ((try? Vectors.file("bughunt-ivm"))?["cases"]?.arrayValue ?? []) .compactMap { $0["name"]?.stringValue } @@ -25,4 +38,52 @@ struct BugHuntTests { Issue.record(Comment(rawValue: "\(name)\n\(mismatch)")) } } + + nonisolated static let clientNames: [String] = + ((try? Vectors.file("bughunt-client"))?["cases"]?.arrayValue ?? []) + .compactMap { $0["name"]?.stringValue } + + /// One targeted client scenario (`vectors/bughunt-client.json`). + @Test(arguments: clientNames) func clientOnMemory(_ name: String) throws { + try Self.runClient(name, storage: .memory) + } + + @Test(arguments: clientNames) func clientOnSQLite(_ name: String) throws { + let directory = NSTemporaryDirectory() + "zero-bughunt-" + UUID().uuidString + defer { try? FileManager.default.removeItem(atPath: directory) } + try Self.runClient(name, storage: .sqlite(directory: directory)) + } + + static func runClient(_ name: String, storage: ZeroStorage) throws { + let file = try Vectors.file("bughunt-client") + let startTime = file["shared"]?["startTime"]?.numberValue ?? 0 + let scenario = try #require( + file["cases"]?.arrayValue?.first { $0["name"]?.stringValue == name }) + let runner = try ScenarioRunner(scenario, startTime: startTime, storage: storage) + if let mismatch = ClientConformanceTests.firstMismatch( + scenario, scenario["expect"]?.arrayValue ?? [], runner.run()) + { + Issue.record(Comment(rawValue: "\(name)\n\(mismatch)")) + } + } + + static func runFuzz(storage: ZeroStorage) throws { + let file = try Vectors.generatedFile("client-aggregates-fuzz") + let startTime = file["shared"]?["startTime"]?.numberValue ?? 0 + var failed: [String] = [] + for scenario in file["cases"]?.arrayValue ?? [] { + let name = scenario["name"]?.stringValue ?? "?" + let runner = try ScenarioRunner(scenario, startTime: startTime, storage: storage) + let actual = runner.run() + if let mismatch = ClientConformanceTests.firstMismatch( + scenario, scenario["expect"]?.arrayValue ?? [], actual) + { + if failed.count < 5 { Issue.record(Comment(rawValue: "\(name)\n\(mismatch)")) } + failed.append(name) + } + } + print( + "[aggregate fuzz on \(storage)] \(failed.count) failed: \(failed.joined(separator: ", "))") + #expect(failed.isEmpty, "\(failed.count) scenarios failed") + } } diff --git a/swift/Tests/ConformanceTests/ClientApp.swift b/swift/Tests/ConformanceTests/ClientApp.swift index 158b49044b..2442302593 100644 --- a/swift/Tests/ConformanceTests/ClientApp.swift +++ b/swift/Tests/ConformanceTests/ClientApp.swift @@ -88,6 +88,31 @@ enum ClientApp { "aggregates.bugLabelCounts": { _ in zql("issue").related("labels") { $0.where("name", "bug").count() }.orderBy("id", .asc) }, + // More aggregates, for the aggregate bug hunt (`bughunt.test.ts`). + "bughunt.allComments": { _ in zql("comment").orderBy("id", .asc) }, + "bughunt.allLabels": { _ in zql("label").orderBy("id", .asc) }, + "bughunt.maxCommentText": { _ in zql("comment").max("text") }, + "bughunt.minIssueTitle": { _ in zql("issue").min("title") }, + "bughunt.pointsSum": { _ in zql("user").sum(json: "metadata", "points") }, + "bughunt.ownerIssueCounts": { _ in + zql("issue").related("owner") { $0.related("issues") { $0.count() } }.orderBy("id", .asc) + }, + "bughunt.commentAvgWhere": { _ in + zql("issue") + .related("comments") { $0.where("createdAt", .gt, 3).avg("createdAt") } + .orderBy("id", .asc) + }, + "bughunt.commentsByAuthorAndIssue": { _ in + zql("comment").groupBy("authorId", "issueId").count() + }, + "bughunt.avgTimeByIssueWhere": { _ in + zql("comment").where("authorId", .ne, "u3").groupBy("issueId").avg("createdAt") + }, + "bughunt.commentCountsLimited": { _ in + zql("issue").related("comments") { $0.count() }.orderBy("createdAt", .desc).limit(3) + }, + "bughunt.ownerCount": { _ in zql("issue").distinct("ownerId").count() }, + "bughunt.sumTimeByOwner": { _ in zql("issue").groupBy("ownerId").sum("createdAt") }, "issueLabels.all": { _ in zql("issueLabel").orderBy("issueId", .asc).orderBy("labelId", .asc) },