fix: align bound query keys with invalidation prefixes
This commit is contained in:
@@ -20,7 +20,11 @@ import {
|
||||
type QueryInvalidationCoordinator,
|
||||
} from "../../src/contracts/query-invalidation.ts";
|
||||
import { createFailure } from "../../src/contracts/errors.ts";
|
||||
import { createRuntimeIdentityRegistry } from "../../src/contracts/query-keys.ts";
|
||||
import {
|
||||
createQueryInvalidationPrefix,
|
||||
createRuntimeIdentityRegistry,
|
||||
defineQueryNamespaceIdentity,
|
||||
} from "../../src/contracts/query-keys.ts";
|
||||
import {
|
||||
bindQuery,
|
||||
type QueryResultMeasure,
|
||||
@@ -216,6 +220,38 @@ describe("application query inbound bridge", () => {
|
||||
});
|
||||
|
||||
describe("scope-bound query commit fence", () => {
|
||||
it("binds the namespace-first V2 query key", () => {
|
||||
const scope = scopeSnapshot();
|
||||
const definition = {
|
||||
definitionId: "reference-detail-v1",
|
||||
definitionVersion: 1,
|
||||
owner: "platform-test",
|
||||
namespace: "reference-resource",
|
||||
namespaceVersion: 1,
|
||||
operationId: "GET_REFERENCE_RESOURCE",
|
||||
profileId: "DETAIL_STANDARD" as const,
|
||||
measureResult: measureOne,
|
||||
execute: async () => ({ ok: true as const, value: "value" }),
|
||||
};
|
||||
|
||||
const bound = bindQuery(definition, "resource-1", scope);
|
||||
|
||||
expect(bound.queryKey).toEqual([
|
||||
"query",
|
||||
2,
|
||||
"reference-resource",
|
||||
1,
|
||||
"scope-fingerprint-0001",
|
||||
1,
|
||||
"scope-identity-token-0001",
|
||||
]);
|
||||
expect(bound.queryKey.slice(0, 4)).toEqual(
|
||||
createQueryInvalidationPrefix(
|
||||
defineQueryNamespaceIdentity("reference-resource", 1),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it("discards a successful result whose scope was fenced during execution", async () => {
|
||||
const client = queryClient();
|
||||
const scope = scopeSnapshot();
|
||||
|
||||
@@ -1,6 +1,80 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { indexInvalidationRegistry } from "../../src/contracts/query-invalidation.ts";
|
||||
import {
|
||||
createBoundQueryKey,
|
||||
createQueryInvalidationPrefix,
|
||||
defineQueryNamespaceIdentity,
|
||||
queryNamespaceIdentityKey,
|
||||
} from "../../src/contracts/query-keys.ts";
|
||||
|
||||
describe("query namespace identity", () => {
|
||||
it("uses a canonical JSON tuple as the namespace identity key", () => {
|
||||
const namespace = defineQueryNamespaceIdentity("reference-resource", 1);
|
||||
|
||||
expect(queryNamespaceIdentityKey(namespace)).toBe(
|
||||
'["reference-resource",1]',
|
||||
);
|
||||
});
|
||||
|
||||
it("creates one namespace-first prefix for invalidation and bound keys", () => {
|
||||
const namespace = defineQueryNamespaceIdentity("reference-resource", 1);
|
||||
const prefix = createQueryInvalidationPrefix(namespace);
|
||||
const key = createBoundQueryKey(
|
||||
namespace,
|
||||
"scope-fingerprint-0001",
|
||||
3,
|
||||
"identity-token-0001",
|
||||
);
|
||||
|
||||
expect(prefix).toEqual(["query", 2, "reference-resource", 1]);
|
||||
expect(key).toEqual([
|
||||
"query",
|
||||
2,
|
||||
"reference-resource",
|
||||
1,
|
||||
"scope-fingerprint-0001",
|
||||
3,
|
||||
"identity-token-0001",
|
||||
]);
|
||||
expect(key.slice(0, 4)).toEqual(prefix);
|
||||
expect(Object.isFrozen(prefix)).toBe(true);
|
||||
expect(Object.isFrozen(key)).toBe(true);
|
||||
});
|
||||
|
||||
it.each([
|
||||
["empty", ""],
|
||||
["C0 control", "orders\u0000private"],
|
||||
["DEL control", "orders\u007fprivate"],
|
||||
["81 UTF-8 bytes", "가".repeat(27)],
|
||||
])("rejects a $0 namespace ID", (_label, namespaceId) => {
|
||||
expect(() => defineQueryNamespaceIdentity(namespaceId, 1)).toThrow(
|
||||
/namespace identity is invalid/u,
|
||||
);
|
||||
});
|
||||
|
||||
it.each([0, -1, 1.5, Number.MAX_SAFE_INTEGER + 1])(
|
||||
"rejects the non-positive-safe namespace version %s",
|
||||
(namespaceVersion) => {
|
||||
expect(() =>
|
||||
defineQueryNamespaceIdentity("reference-resource", namespaceVersion),
|
||||
).toThrow(/namespace identity is invalid/u);
|
||||
},
|
||||
);
|
||||
|
||||
it("rejects a non-positive definition version before creating a bound key", () => {
|
||||
const namespace = defineQueryNamespaceIdentity("reference-resource", 1);
|
||||
|
||||
expect(() =>
|
||||
createBoundQueryKey(
|
||||
namespace,
|
||||
"scope-fingerprint-0001",
|
||||
0,
|
||||
"identity-token-0001",
|
||||
),
|
||||
).toThrow(/definition version is invalid/u);
|
||||
});
|
||||
});
|
||||
|
||||
describe("query invalidation registry", () => {
|
||||
it.each([
|
||||
|
||||
Reference in New Issue
Block a user