Add explicit CRDT edit contracts and structured query values

This commit is contained in:
Timothy J. Aveni
2026-09-19 22:33:20 -07:00
parent 0555c929b1
commit 4c0c404a39
27 changed files with 3272 additions and 2745 deletions
+6 -4
View File
@@ -16,7 +16,7 @@ export type ValueTypeExpression =
| Extract<ValueType, { kind: "builtin" | "scalar" | "message" }>
| { kind: "parameter"; parameterId: string }
| { kind: "record"; fields: Record<string, ValueTypeExpression> }
| { kind: "list" | "optional"; value: ValueTypeExpression }
| { kind: "list" | "optional" | "change"; value: ValueTypeExpression }
| { kind: "object-ref"; expectation: ObjectTypeExpression }
| { kind: "alias"; definitionId: string; arguments: TypeArgumentExpression[] };
@@ -184,10 +184,10 @@ export const isStorableType = (
case "list":
case "optional":
return visit(value.value, depth + 1);
// Records currently have RPC codecs, not ordinary-state persistence codecs.
// A generic bound must not promise storage that the installed model rejects.
case "record":
case "change":
return false;
case "record":
return Object.values(value.fields).every((field) => visit(field, depth + 1));
}
};
return visit(type, 0);
@@ -216,6 +216,7 @@ export const canonicalTypeArgument = (argument: ClosedTypeArgument): string => {
return ["message", value.descriptorId];
case "object-ref":
return ["object-ref", target(value.expectation)];
case "change":
case "list":
case "optional":
return [value.kind, type(value.value, depth + 1)];
@@ -323,6 +324,7 @@ export class TypeSubstitution {
return { kind: "scalar", name: expression.name };
case "message":
return { kind: "message", descriptorId: expression.descriptorId };
case "change":
case "list":
case "optional":
return { kind: expression.kind, value: this.value(expression.value, `${path}.${expression.kind}`, depth + 1) };