@gaganref/confect-core 10.3.1-fork.74 → 10.3.1-fork.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Component.d.ts +59 -2
- package/dist/Component.d.ts.map +1 -1
- package/dist/Component.js +19 -11
- package/dist/Component.js.map +1 -1
- package/dist/Table.d.ts +48 -9
- package/dist/Table.d.ts.map +1 -1
- package/dist/Table.js +41 -13
- package/dist/Table.js.map +1 -1
- package/package.json +1 -1
- package/src/Component.ts +139 -6
- package/src/Table.ts +157 -23
package/dist/Component.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ import * as Ref from "./Ref.js";
|
|
|
8
8
|
import type * as Refs from "./Refs.js";
|
|
9
9
|
import type * as RuntimeAndFunctionType from "./RuntimeAndFunctionType.js";
|
|
10
10
|
import * as Spec from "./Spec.js";
|
|
11
|
+
import type * as Table_ from "./Table.js";
|
|
11
12
|
declare const EmptyComponentScopeError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
12
13
|
readonly _tag: "EmptyComponentScopeError";
|
|
13
14
|
} & Readonly<A>;
|
|
@@ -56,14 +57,60 @@ export type Api<Spec_ extends Spec.AnyWithProps, Name extends string | undefined
|
|
|
56
57
|
interface Tree {
|
|
57
58
|
readonly [key: string]: Tree | Ref.Any;
|
|
58
59
|
}
|
|
59
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Each grouped table's name, mapped to its id field and that id's table.
|
|
62
|
+
*/
|
|
63
|
+
export interface GroupMap {
|
|
64
|
+
readonly [table: string]: {
|
|
65
|
+
readonly key: string;
|
|
66
|
+
readonly table: string;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
export interface Component<Spec_ extends Spec.AnyWithProps, Scope extends IdScope.IdScope, Tables extends string = string, Groups_ extends GroupMap = GroupMap> {
|
|
60
70
|
readonly [TypeId]: {
|
|
61
71
|
readonly refs: Tree;
|
|
62
72
|
readonly scope: Scope;
|
|
63
73
|
readonly tables: ReadonlyArray<Tables>;
|
|
74
|
+
readonly groups: Groups_;
|
|
64
75
|
};
|
|
65
76
|
readonly "~Spec": Spec_;
|
|
66
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* A component's tables as `contract` takes them: a table, or the name of a
|
|
80
|
+
* system table.
|
|
81
|
+
*/
|
|
82
|
+
export type TableEntry = string | Table_.AnyWithProps;
|
|
83
|
+
type EntryName<Entry extends TableEntry> = Entry extends string ? Entry : Entry extends Table_.AnyWithProps ? Table_.Name<Entry> : never;
|
|
84
|
+
type Many<A, All = A> = string extends A ? true : number extends A ? true : A extends unknown ? [All] extends [A] ? never : true : never;
|
|
85
|
+
type Loose<Entries extends ReadonlyArray<TableEntry>> = true extends Many<Entries> | Many<Entries["length"]> | {
|
|
86
|
+
[Index in keyof Entries]: Many<Entries[Index]>;
|
|
87
|
+
}[number] ? "pass one table or one name per entry; a union may be absent at runtime" : never;
|
|
88
|
+
type StrayGroup<Entries extends ReadonlyArray<TableEntry>, Scope extends IdScope.IdScope> = [Loose<Entries>] extends [never] ? {
|
|
89
|
+
[Index in keyof Entries]: Entries[Index] extends {
|
|
90
|
+
readonly tableName: infer Name extends string;
|
|
91
|
+
readonly group: Table_.Group<infer Key, infer Target, infer GroupScope>;
|
|
92
|
+
} ? [Target, GroupScope] extends [EntryName<Entries[number]>, Scope] ? never : `${Name}.${Key} is not an id of a table of this component` : never;
|
|
93
|
+
}[number] : Loose<Entries>;
|
|
94
|
+
/**
|
|
95
|
+
* The group map `contract` publishes for these table entries.
|
|
96
|
+
*/
|
|
97
|
+
export type Groups<Entries extends ReadonlyArray<TableEntry>> = {
|
|
98
|
+
readonly [Entry in Extract<Entries[number], {
|
|
99
|
+
readonly tableName: string;
|
|
100
|
+
readonly group: Table_.Group;
|
|
101
|
+
}> as Entry["tableName"]]: {
|
|
102
|
+
readonly key: Entry["group"]["key"];
|
|
103
|
+
readonly table: Entry["group"]["table"];
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* `unknown` when every entry is one table or name and every group's id names a
|
|
108
|
+
* table of this component in its scope, otherwise an object type naming the
|
|
109
|
+
* refused entry.
|
|
110
|
+
*/
|
|
111
|
+
export type CheckGroups<Entries extends ReadonlyArray<TableEntry>, Scope extends IdScope.IdScope> = [StrayGroup<Entries, Scope>] extends [never] ? unknown : {
|
|
112
|
+
readonly "~StrayGroup": StrayGroup<Entries, Scope>;
|
|
113
|
+
};
|
|
67
114
|
/**
|
|
68
115
|
* An opaque identity: its string representation is not part of the API.
|
|
69
116
|
*/
|
|
@@ -87,8 +134,18 @@ export type Bound<Spec_ extends Spec.AnyWithProps, From extends IdScope.IdScope,
|
|
|
87
134
|
};
|
|
88
135
|
/**
|
|
89
136
|
* Build a publishable contract containing only exported functions and codecs.
|
|
137
|
+
* `tables` lists the component's tables, each a table or a system table's name.
|
|
138
|
+
* A table grouped by an id must group by an id of one of these tables.
|
|
139
|
+
*/
|
|
140
|
+
export declare function contract<Spec_ extends Spec.AnyWithProps, const Scope extends IdScope.IdScope, const Entries extends ReadonlyArray<TableEntry>>(spec: Spec_, scope: Scope, tables: Entries & CheckGroups<Entries, Scope>): Component<Spec_, Scope, EntryName<Entries[number]>, Groups<Entries>>;
|
|
141
|
+
/**
|
|
142
|
+
* Table names alone, as in an explicit third type argument, carry no groups.
|
|
143
|
+
*/
|
|
144
|
+
export declare function contract<Spec_ extends Spec.AnyWithProps, const Scope extends IdScope.IdScope, const Tables extends string>(spec: Spec_, scope: Scope, tables: ReadonlyArray<Tables>): Component<Spec_, Scope, Tables, {}>;
|
|
145
|
+
/**
|
|
146
|
+
* Each grouped table's id field and the table that id names.
|
|
90
147
|
*/
|
|
91
|
-
export declare const
|
|
148
|
+
export declare const groups: <Groups_ extends GroupMap>(component: Component<Spec.AnyWithProps, IdScope.IdScope, string, Groups_>) => Groups_;
|
|
92
149
|
/**
|
|
93
150
|
* Bind the published contract to an actual installed component reference.
|
|
94
151
|
*/
|
package/dist/Component.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Component.d.ts","sourceRoot":"","sources":["../src/Component.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAQ5E,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,KAAK,YAAY,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAC5C,OAAO,KAAK,KAAK,SAAS,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AAGxC,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,KAAK,IAAI,MAAM,WAAW,CAAC;AACvC,OAAO,KAAK,KAAK,sBAAsB,MAAM,6BAA6B,CAAC;AAC3E,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;;;;
|
|
1
|
+
{"version":3,"file":"Component.d.ts","sourceRoot":"","sources":["../src/Component.ts"],"names":[],"mappings":"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"}
|
package/dist/Component.js
CHANGED
|
@@ -3,7 +3,7 @@ import { defineProperty } from "./Lazy.js";
|
|
|
3
3
|
import { app, instance } from "./IdScope.js";
|
|
4
4
|
import { GenericId, rebase } from "./GenericId.js";
|
|
5
5
|
import { fromProvenance, isRef, make as make$1 } from "./Ref.js";
|
|
6
|
-
import { groups } from "./Spec.js";
|
|
6
|
+
import { groups as groups$1 } from "./Spec.js";
|
|
7
7
|
import * as Schema from "effect/Schema";
|
|
8
8
|
import * as Data from "effect/Data";
|
|
9
9
|
import { getFunctionAddress } from "convex/server";
|
|
@@ -19,6 +19,7 @@ var Component_exports = /* @__PURE__ */ __exportAll({
|
|
|
19
19
|
UninstalledComponentReferenceError: () => UninstalledComponentReferenceError,
|
|
20
20
|
bind: () => bind,
|
|
21
21
|
contract: () => contract,
|
|
22
|
+
groups: () => groups,
|
|
22
23
|
id: () => id,
|
|
23
24
|
make: () => make,
|
|
24
25
|
schema: () => schema
|
|
@@ -53,11 +54,8 @@ const validateNames = (groups, prefix = "") => {
|
|
|
53
54
|
const validateContract = (scope, groups) => scope === "" ? Result.fail(new EmptyComponentScopeError({ definitionScope: scope })) : validateNames(groups);
|
|
54
55
|
const TypeId = "~@confect/core/Component";
|
|
55
56
|
const BoundTypeId = "~@confect/core/BoundComponent";
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
*/
|
|
59
|
-
const contract = (spec, scope, tables) => {
|
|
60
|
-
const specGroups = groups(spec);
|
|
57
|
+
function contract(spec, scope, tables) {
|
|
58
|
+
const specGroups = groups$1(spec);
|
|
61
59
|
Result.getOrThrow(validateContract(scope, specGroups));
|
|
62
60
|
const collect = (groups, prefix = "") => pipe(groups, Record.map((group, name) => {
|
|
63
61
|
const path = prefix === "" ? name : `${prefix}/${name}`;
|
|
@@ -69,12 +67,22 @@ const contract = (spec, scope, tables) => {
|
|
|
69
67
|
...functions
|
|
70
68
|
};
|
|
71
69
|
}), Record.filter((children) => !Record.isEmptyRecord(children)));
|
|
72
|
-
|
|
70
|
+
const grouped = pipe(tables, Array.flatMap((entry) => typeof entry !== "string" && entry.group !== void 0 ? [[entry.tableName, entry.group]] : []), Record.fromEntries);
|
|
71
|
+
const published = {
|
|
73
72
|
refs: collect(specGroups),
|
|
74
73
|
scope,
|
|
75
|
-
tables
|
|
76
|
-
|
|
77
|
-
};
|
|
74
|
+
tables: Array.map(tables, (entry) => typeof entry === "string" ? entry : entry.tableName),
|
|
75
|
+
groups: grouped
|
|
76
|
+
};
|
|
77
|
+
return { [TypeId]: published };
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Each grouped table's id field and the table that id names.
|
|
81
|
+
*/
|
|
82
|
+
const groups = (component) => Record.map(component[TypeId].groups, ({ key, table }) => ({
|
|
83
|
+
key,
|
|
84
|
+
table
|
|
85
|
+
}));
|
|
78
86
|
/**
|
|
79
87
|
* Bind the published contract to an actual installed component reference.
|
|
80
88
|
*/
|
|
@@ -159,6 +167,6 @@ const make = (name, options) => ({
|
|
|
159
167
|
name
|
|
160
168
|
});
|
|
161
169
|
//#endregion
|
|
162
|
-
export { ComponentNameCollisionError, Component_exports, EmptyComponentScopeError, UninstalledComponentReferenceError, bind, contract, id, make, schema };
|
|
170
|
+
export { ComponentNameCollisionError, Component_exports, EmptyComponentScopeError, UninstalledComponentReferenceError, bind, contract, groups, id, make, schema };
|
|
163
171
|
|
|
164
172
|
//# sourceMappingURL=Component.js.map
|
package/dist/Component.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Component.js","names":["Spec.groups","Ref.make","IdScope.instance","IdScope.app","rebase","GenericId.rebase","Ref.isRef","Ref.fromProvenance","GenericId.GenericId"],"sources":["../src/Component.ts"],"sourcesContent":["import type { DefaultFunctionArgs, FunctionReference } from \"convex/server\";\nimport { getFunctionAddress } from \"convex/server\";\nimport * as Array from \"effect/Array\";\nimport * as Data from \"effect/Data\";\nimport * as Result from \"effect/Result\";\nimport { memoize, pipe } from \"effect/Function\";\nimport * as Match from \"effect/Match\";\nimport * as Record from \"effect/Record\";\nimport * as Schema from \"effect/Schema\";\nimport type * as FunctionProvenance from \"./FunctionProvenance.js\";\nimport type * as FunctionSpec from \"./FunctionSpec.js\";\nimport * as GenericId from \"./GenericId.js\";\nimport type * as GroupSpec from \"./GroupSpec.js\";\nimport * as IdScope from \"./IdScope.js\";\nimport * as Lazy from \"./Lazy.js\";\nimport type * as MiddlewareSpec from \"./MiddlewareSpec.js\";\nimport * as Ref from \"./Ref.js\";\nimport type * as Refs from \"./Refs.js\";\nimport type * as RuntimeAndFunctionType from \"./RuntimeAndFunctionType.js\";\nimport * as Spec from \"./Spec.js\";\n\nexport class EmptyComponentScopeError extends Data.TaggedError(\n \"EmptyComponentScopeError\",\n)<{\n readonly definitionScope: IdScope.IdScope;\n}> {\n override get message(): string {\n return \"A component contract requires a nonempty definition scope.\";\n }\n}\n\nexport class ComponentNameCollisionError extends Data.TaggedError(\n \"ComponentNameCollisionError\",\n)<{\n readonly groupPath: string;\n readonly functionName: string;\n}> {\n override get message(): string {\n return `Group and function at same level have same name ('${this.groupPath}:${this.functionName}')`;\n }\n}\n\nexport class UninstalledComponentReferenceError extends Data.TaggedError(\n \"UninstalledComponentReferenceError\",\n)<{\n readonly definitionScope: IdScope.IdScope;\n}> {\n override get message(): string {\n return \"Component.bind expects an installed component from the generated components registry.\";\n }\n}\n\nconst validateNames = (\n groups: Readonly<Record<string, GroupSpec.AnyWithProps>>,\n prefix = \"\",\n): Result.Result<void, ComponentNameCollisionError> => {\n for (const [name, group] of Record.toEntries(groups)) {\n const path = prefix === \"\" ? name : `${prefix}/${name}`;\n for (const functionSpec of Record.values(group.functions)) {\n if (Record.has(group.groups, functionSpec.name)) {\n return Result.fail(\n new ComponentNameCollisionError({\n groupPath: path,\n functionName: functionSpec.name,\n }),\n );\n }\n }\n const nested = validateNames(group.groups, path);\n if (Result.isFailure(nested)) return nested;\n }\n return Result.succeed(undefined);\n};\n\nconst validateContract = (\n scope: IdScope.IdScope,\n groups: Readonly<Record<string, GroupSpec.AnyWithProps>>,\n): Result.Result<\n void,\n EmptyComponentScopeError | ComponentNameCollisionError\n> =>\n scope === \"\"\n ? Result.fail(new EmptyComponentScopeError({ definitionScope: scope }))\n : validateNames(groups);\n\nconst TypeId = \"~@confect/core/Component\";\nconst BoundTypeId = \"~@confect/core/BoundComponent\";\n\n/**\n * Convex's generated ComponentApi erases database ID brands at the boundary.\n */\ntype Wire<A> = A extends { readonly __tableName: string }\n ? string\n : A extends\n | string\n | number\n | bigint\n | boolean\n | null\n | undefined\n | ArrayBuffer\n ? A\n : { [K in keyof A]: Wire<A[K]> };\n\ntype OmitEmpty<A> = {\n [K in keyof A as keyof A[K] extends never ? never : K]: A[K];\n};\ntype ApiGroups<\n GroupSpec_ extends GroupSpec.AnyWithProps,\n Name extends string | undefined,\n> = OmitEmpty<{\n [GroupName in GroupSpec.Name<GroupSpec_>]: ApiGroup<\n GroupSpec.WithName<GroupSpec_, GroupName>,\n Name\n >;\n}>;\ntype ApiGroup<\n GroupSpec_ extends GroupSpec.AnyWithProps,\n Name extends string | undefined,\n> = ApiGroups<GroupSpec.Groups<GroupSpec_>, Name> & {\n [\n FunctionSpec_ in GroupSpec.Functions<GroupSpec_> as FunctionSpec.GetFunctionVisibility<FunctionSpec_> extends \"public\"\n ? FunctionSpec.Name<FunctionSpec_>\n : never\n ]: FunctionReference<\n RuntimeAndFunctionType.GetFunctionType<\n FunctionSpec_[\"runtimeAndFunctionType\"]\n >,\n \"internal\",\n Extract<Wire<FunctionSpec.EncodedArgs<FunctionSpec_>>, DefaultFunctionArgs>,\n Wire<FunctionSpec.EncodedReturns<FunctionSpec_>>,\n Name\n >;\n};\n\nexport type Api<\n Spec_ extends Spec.AnyWithProps,\n Name extends string | undefined = string | undefined,\n> = ApiGroups<Spec.Groups<Spec_>, Name>;\n\ninterface Tree {\n readonly [key: string]: Tree | Ref.Any;\n}\n\nexport interface Component<\n Spec_ extends Spec.AnyWithProps,\n Scope extends IdScope.IdScope,\n Tables extends string = string,\n> {\n readonly [TypeId]: {\n readonly refs: Tree;\n readonly scope: Scope;\n readonly tables: ReadonlyArray<Tables>;\n };\n readonly \"~Spec\": Spec_;\n}\n\n/**\n * An opaque identity: its string representation is not part of the API.\n */\nexport type MountScope<\n Parent extends IdScope.IdScope,\n Name extends string | undefined,\n> = IdScope.Mount<Parent, Name>;\n\ntype MountName<ComponentApi> =\n ComponentApi extends FunctionReference<any, any, any, any, infer Name>\n ? Name\n : ComponentApi extends object\n ? {\n [Key in keyof ComponentApi]: MountName<ComponentApi[Key]>;\n }[keyof ComponentApi]\n : never;\n\ntype BindRefs<\n RefTree,\n From extends IdScope.IdScope,\n To extends IdScope.IdScope,\n> = RefTree extends Ref.Any\n ? RefTree extends { readonly _tag: \"Convex\" }\n ? Ref.ConvexRef<\n Ref.GetRuntimeAndFunctionType<RefTree>,\n \"internal\",\n Extract<Wire<Ref.Args<RefTree>>, DefaultFunctionArgs>,\n Wire<Ref.Returns<RefTree>>\n >\n : Extract<\n Ref.Ref<\n Ref.GetRuntimeAndFunctionType<RefTree>,\n \"internal\",\n Extract<\n GenericId.Rebase<Ref.Args<RefTree>, From, To>,\n DefaultFunctionArgs\n >,\n GenericId.Rebase<Ref.Returns<RefTree>, From, To>,\n GenericId.Rebase<Ref.Error<RefTree>, From, To>\n >,\n { readonly _tag: RefTree[\"_tag\"] }\n >\n : { [Key in keyof RefTree]: BindRefs<RefTree[Key], From, To> };\n\nexport type Bound<\n Spec_ extends Spec.AnyWithProps,\n From extends IdScope.IdScope,\n To extends IdScope.IdScope,\n Tables extends string,\n> = BindRefs<Refs.Refs<Spec_, Ref.AnyPublic>, From, To> & {\n readonly [BoundTypeId]: {\n readonly from: From;\n readonly scope: To;\n readonly tables: ReadonlyArray<Tables>;\n };\n};\n\n/**\n * Build a publishable contract containing only exported functions and codecs.\n */\nexport const contract = <\n Spec_ extends Spec.AnyWithProps,\n const Scope extends IdScope.IdScope,\n const Tables extends string,\n>(\n spec: Spec_,\n scope: Scope,\n tables: ReadonlyArray<Tables>,\n): Component<Spec_, Scope, Tables> => {\n const specGroups = Spec.groups(spec);\n Result.getOrThrow(validateContract(scope, specGroups));\n const collect = (\n groups: Readonly<Record<string, GroupSpec.AnyWithProps>>,\n prefix = \"\",\n ): Tree =>\n pipe(\n groups,\n Record.map((group, name) => {\n const path = prefix === \"\" ? name : `${prefix}/${name}`;\n const functions = pipe(\n group.functions,\n Record.filter((functionSpec) => {\n return Match.value(functionSpec.functionVisibility).pipe(\n Match.when(\"public\", () => true),\n Match.when(\"internal\", () => false),\n Match.exhaustive,\n );\n }),\n Record.map((functionSpec) =>\n Ref.make(path, functionSpec, group.middlewareAttachments),\n ),\n );\n return { ...collect(group.groups, path), ...functions };\n }),\n Record.filter((children) => !Record.isEmptyRecord(children)),\n );\n return {\n [TypeId]: { refs: collect(specGroups), scope, tables },\n } as Component<Spec_, Scope, Tables>;\n};\n\n/**\n * Bind the published contract to an actual installed component reference.\n */\nexport const bind = <\n Spec_ extends Spec.AnyWithProps,\n From extends IdScope.IdScope,\n Tables extends string,\n Native extends Api<NoInfer<Spec_>>,\n const Parent extends IdScope.IdScope = IdScope.App,\n>(\n component: Component<Spec_, From, Tables>,\n native: Native,\n options?: { readonly parentScope: Parent },\n): Bound<\n Spec_,\n From,\n MountScope<Parent, Extract<MountName<Native>, string | undefined>>,\n Tables\n> => {\n const published = component[TypeId];\n const address = getFunctionAddress(native);\n const installedReference = Result.getOrThrow(\n Result.fromNullishOr(\n address.reference,\n () =>\n new UninstalledComponentReferenceError({\n definitionScope: published.scope,\n }),\n ),\n );\n // Preserve the opaque address as an identity only. Calls retain the native\n // references; no component address is constructed or parsed for routing.\n const scope = IdScope.instance(\n options?.parentScope ?? IdScope.app,\n installedReference,\n );\n const rebase = (schema: Schema.ConstraintCodec<any, any, never, never>) =>\n GenericId.rebase(schema, published.scope, scope);\n const rebaseMiddleware = memoize(\n (middleware: MiddlewareSpec.AnyMiddlewareSpec) => {\n if (!(\"error\" in middleware)) return middleware;\n const boundMiddleware = Object.create(\n middleware,\n ) as MiddlewareSpec.AnyMiddlewareSpec;\n Lazy.defineProperty(boundMiddleware, \"error\", () => {\n const error = middleware.error;\n return error === undefined ? undefined : rebase(error);\n });\n return boundMiddleware;\n },\n );\n const visit = (tree: Tree, references: unknown): Tree =>\n Record.map(tree, (child, key) => {\n const reference = (references as Record<string, unknown>)[key];\n if (Ref.isRef(child)) {\n const nativeRef = reference as FunctionReference<any, any>;\n return Match.value(child).pipe(\n Match.tag(\"Convex\", (ref) => ({\n ...ref,\n functionReference: nativeRef,\n })),\n Match.tag(\"Confect\", (ref) => {\n const provenance = {\n _tag: \"Confect\" as const,\n kind: Match.value(ref.kind).pipe(\n Match.tag(\"Standard\", (kind) => kind),\n Match.tag(\"Paginated\", (kind) => {\n const boundKind = { _tag: \"Paginated\" as const };\n Lazy.defineProperty(boundKind, \"userArgs\", () =>\n Schema.Struct(Record.map(kind.userArgs.fields, rebase)),\n );\n Lazy.defineProperty(boundKind, \"item\", () =>\n rebase(kind.item),\n );\n Lazy.defineProperty(boundKind, \"page\", () =>\n rebase(kind.page),\n );\n return boundKind as FunctionProvenance.Paginated;\n }),\n Match.exhaustive,\n ),\n };\n Lazy.defineProperty(provenance, \"args\", () =>\n Schema.Struct(Record.map(ref.args.fields, rebase)),\n );\n Lazy.defineProperty(provenance, \"returns\", () =>\n rebase(ref.returns),\n );\n if (\"error\" in ref) {\n Lazy.defineProperty(provenance, \"error\", () => {\n const error = ref.error;\n return error === undefined ? undefined : rebase(error);\n });\n }\n return Ref.fromProvenance(\n ref.convexFunctionName,\n provenance as FunctionProvenance.AnyConfect,\n Array.map(ref.middlewareAttachments, (attachment) => ({\n ...attachment,\n spec: rebaseMiddleware(attachment.spec),\n })),\n nativeRef,\n ref.functionType,\n ref.reservedArgument,\n );\n }),\n Match.exhaustive,\n );\n } else {\n return visit(child, reference);\n }\n });\n const refs = visit(published.refs, native);\n Object.defineProperty(refs, BoundTypeId, {\n value: { from: published.scope, scope, tables: published.tables },\n });\n return refs as Bound<\n Spec_,\n From,\n MountScope<Parent, Extract<MountName<Native>, string | undefined>>,\n Tables\n >;\n};\n\n/**\n * Reference an installed component's table ID in host schemas.\n */\nexport const id = <\n From extends IdScope.IdScope,\n To extends IdScope.IdScope,\n Tables extends string,\n const Table extends Tables,\n>(\n component: {\n readonly [BoundTypeId]: {\n readonly from: From;\n readonly scope: To;\n readonly tables: ReadonlyArray<Tables>;\n };\n },\n table: Table,\n) => GenericId.GenericId(table, component[BoundTypeId].scope);\n\n/**\n * Reuse a component's codec in a host function or table without losing its\n * scope.\n */\nexport const schema = <\n From extends IdScope.IdScope,\n To extends IdScope.IdScope,\n Schema_ extends Schema.Codec<any, any>,\n>(\n component: {\n readonly [BoundTypeId]: { readonly from: From; readonly scope: To };\n },\n codec: Schema_,\n) =>\n GenericId.rebase(\n codec,\n component[BoundTypeId].from,\n component[BoundTypeId].scope,\n );\n\n/**\n * A component's `init`: an internal Confect mutation whose args are the install\n * args each mount passes.\n */\nexport type Init = Ref.AnyConfect & {\n readonly \"~RuntimeAndFunctionType\": RuntimeAndFunctionType.ConvexMutation;\n readonly \"~FunctionVisibility\": \"internal\";\n};\n\nexport interface DescriptorOptions {\n readonly init?: Init;\n /**\n * The component's `_generated/component` contract. A mount of a descriptor\n * with one rebases a callback slot's args with `callbackArgs`.\n */\n readonly contract?: Component<Spec.AnyWithProps, IdScope.IdScope, string>;\n readonly env?: Readonly<Record<string, Schema.Top>>;\n /**\n * Builds the component's client from its native mount, then the mount's\n * `options` when the client takes any.\n */\n readonly client: (...args: never) => unknown;\n}\n\nexport type Descriptor<\n Name extends string = string,\n Options extends DescriptorOptions = DescriptorOptions,\n> = Options & { readonly name: Name };\n\n/**\n * Describe a Convex component for `Mount.make`, as `defineComponent` does for\n * Convex. A component with `init` takes install `args` at each mount, and one\n * with `env` takes `env`. Export it from the package's `./client` entry.\n *\n * ```ts\n * export default Component.make(\"email\", {\n * init: refs.internal.install.init,\n * env: { RESEND_API_KEY: Schema.String },\n * client: Client.make,\n * });\n * ```\n */\nexport const make = <\n const Name extends string,\n const Options extends DescriptorOptions,\n>(\n name: Name,\n options: Options,\n): Descriptor<Name, Options> => ({ ...options, name });\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Component.js","names":["Spec.groups","Ref.make","IdScope.instance","IdScope.app","rebase","GenericId.rebase","Ref.isRef","Ref.fromProvenance","GenericId.GenericId"],"sources":["../src/Component.ts"],"sourcesContent":["import type { DefaultFunctionArgs, FunctionReference } from \"convex/server\";\nimport { getFunctionAddress } from \"convex/server\";\nimport * as Array from \"effect/Array\";\nimport * as Data from \"effect/Data\";\nimport * as Result from \"effect/Result\";\nimport { memoize, pipe } from \"effect/Function\";\nimport * as Match from \"effect/Match\";\nimport * as Record from \"effect/Record\";\nimport * as Schema from \"effect/Schema\";\nimport type * as FunctionProvenance from \"./FunctionProvenance.js\";\nimport type * as FunctionSpec from \"./FunctionSpec.js\";\nimport * as GenericId from \"./GenericId.js\";\nimport type * as GroupSpec from \"./GroupSpec.js\";\nimport * as IdScope from \"./IdScope.js\";\nimport * as Lazy from \"./Lazy.js\";\nimport type * as MiddlewareSpec from \"./MiddlewareSpec.js\";\nimport * as Ref from \"./Ref.js\";\nimport type * as Refs from \"./Refs.js\";\nimport type * as RuntimeAndFunctionType from \"./RuntimeAndFunctionType.js\";\nimport * as Spec from \"./Spec.js\";\nimport type * as Table_ from \"./Table.js\";\n\nexport class EmptyComponentScopeError extends Data.TaggedError(\n \"EmptyComponentScopeError\",\n)<{\n readonly definitionScope: IdScope.IdScope;\n}> {\n override get message(): string {\n return \"A component contract requires a nonempty definition scope.\";\n }\n}\n\nexport class ComponentNameCollisionError extends Data.TaggedError(\n \"ComponentNameCollisionError\",\n)<{\n readonly groupPath: string;\n readonly functionName: string;\n}> {\n override get message(): string {\n return `Group and function at same level have same name ('${this.groupPath}:${this.functionName}')`;\n }\n}\n\nexport class UninstalledComponentReferenceError extends Data.TaggedError(\n \"UninstalledComponentReferenceError\",\n)<{\n readonly definitionScope: IdScope.IdScope;\n}> {\n override get message(): string {\n return \"Component.bind expects an installed component from the generated components registry.\";\n }\n}\n\nconst validateNames = (\n groups: Readonly<Record<string, GroupSpec.AnyWithProps>>,\n prefix = \"\",\n): Result.Result<void, ComponentNameCollisionError> => {\n for (const [name, group] of Record.toEntries(groups)) {\n const path = prefix === \"\" ? name : `${prefix}/${name}`;\n for (const functionSpec of Record.values(group.functions)) {\n if (Record.has(group.groups, functionSpec.name)) {\n return Result.fail(\n new ComponentNameCollisionError({\n groupPath: path,\n functionName: functionSpec.name,\n }),\n );\n }\n }\n const nested = validateNames(group.groups, path);\n if (Result.isFailure(nested)) return nested;\n }\n return Result.succeed(undefined);\n};\n\nconst validateContract = (\n scope: IdScope.IdScope,\n groups: Readonly<Record<string, GroupSpec.AnyWithProps>>,\n): Result.Result<\n void,\n EmptyComponentScopeError | ComponentNameCollisionError\n> =>\n scope === \"\"\n ? Result.fail(new EmptyComponentScopeError({ definitionScope: scope }))\n : validateNames(groups);\n\nconst TypeId = \"~@confect/core/Component\";\nconst BoundTypeId = \"~@confect/core/BoundComponent\";\n\n/**\n * Convex's generated ComponentApi erases database ID brands at the boundary.\n */\ntype Wire<A> = A extends { readonly __tableName: string }\n ? string\n : A extends\n | string\n | number\n | bigint\n | boolean\n | null\n | undefined\n | ArrayBuffer\n ? A\n : { [K in keyof A]: Wire<A[K]> };\n\ntype OmitEmpty<A> = {\n [K in keyof A as keyof A[K] extends never ? never : K]: A[K];\n};\ntype ApiGroups<\n GroupSpec_ extends GroupSpec.AnyWithProps,\n Name extends string | undefined,\n> = OmitEmpty<{\n [GroupName in GroupSpec.Name<GroupSpec_>]: ApiGroup<\n GroupSpec.WithName<GroupSpec_, GroupName>,\n Name\n >;\n}>;\ntype ApiGroup<\n GroupSpec_ extends GroupSpec.AnyWithProps,\n Name extends string | undefined,\n> = ApiGroups<GroupSpec.Groups<GroupSpec_>, Name> & {\n [\n FunctionSpec_ in GroupSpec.Functions<GroupSpec_> as FunctionSpec.GetFunctionVisibility<FunctionSpec_> extends \"public\"\n ? FunctionSpec.Name<FunctionSpec_>\n : never\n ]: FunctionReference<\n RuntimeAndFunctionType.GetFunctionType<\n FunctionSpec_[\"runtimeAndFunctionType\"]\n >,\n \"internal\",\n Extract<Wire<FunctionSpec.EncodedArgs<FunctionSpec_>>, DefaultFunctionArgs>,\n Wire<FunctionSpec.EncodedReturns<FunctionSpec_>>,\n Name\n >;\n};\n\nexport type Api<\n Spec_ extends Spec.AnyWithProps,\n Name extends string | undefined = string | undefined,\n> = ApiGroups<Spec.Groups<Spec_>, Name>;\n\ninterface Tree {\n readonly [key: string]: Tree | Ref.Any;\n}\n\n/**\n * Each grouped table's name, mapped to its id field and that id's table.\n */\nexport interface GroupMap {\n readonly [table: string]: { readonly key: string; readonly table: string };\n}\n\nexport interface Component<\n Spec_ extends Spec.AnyWithProps,\n Scope extends IdScope.IdScope,\n Tables extends string = string,\n Groups_ extends GroupMap = GroupMap,\n> {\n readonly [TypeId]: {\n readonly refs: Tree;\n readonly scope: Scope;\n readonly tables: ReadonlyArray<Tables>;\n readonly groups: Groups_;\n };\n readonly \"~Spec\": Spec_;\n}\n\n/**\n * A component's tables as `contract` takes them: a table, or the name of a\n * system table.\n */\nexport type TableEntry = string | Table_.AnyWithProps;\n\ntype EntryName<Entry extends TableEntry> = Entry extends string\n ? Entry\n : Entry extends Table_.AnyWithProps\n ? Table_.Name<Entry>\n : never;\n\ntype Many<A, All = A> = string extends A\n ? true\n : number extends A\n ? true\n : A extends unknown\n ? [All] extends [A]\n ? never\n : true\n : never;\n\ntype Loose<Entries extends ReadonlyArray<TableEntry>> = true extends\n | Many<Entries>\n | Many<Entries[\"length\"]>\n | { [Index in keyof Entries]: Many<Entries[Index]> }[number]\n ? \"pass one table or one name per entry; a union may be absent at runtime\"\n : never;\n\ntype StrayGroup<\n Entries extends ReadonlyArray<TableEntry>,\n Scope extends IdScope.IdScope,\n> = [Loose<Entries>] extends [never]\n ? {\n [Index in keyof Entries]: Entries[Index] extends {\n readonly tableName: infer Name extends string;\n readonly group: Table_.Group<infer Key, infer Target, infer GroupScope>;\n }\n ? [Target, GroupScope] extends [EntryName<Entries[number]>, Scope]\n ? never\n : `${Name}.${Key} is not an id of a table of this component`\n : never;\n }[number]\n : Loose<Entries>;\n\n/**\n * The group map `contract` publishes for these table entries.\n */\nexport type Groups<Entries extends ReadonlyArray<TableEntry>> = {\n readonly [\n Entry in Extract<\n Entries[number],\n { readonly tableName: string; readonly group: Table_.Group }\n > as Entry[\"tableName\"]\n ]: {\n readonly key: Entry[\"group\"][\"key\"];\n readonly table: Entry[\"group\"][\"table\"];\n };\n};\n\n/**\n * `unknown` when every entry is one table or name and every group's id names a\n * table of this component in its scope, otherwise an object type naming the\n * refused entry.\n */\nexport type CheckGroups<\n Entries extends ReadonlyArray<TableEntry>,\n Scope extends IdScope.IdScope,\n> = [StrayGroup<Entries, Scope>] extends [never]\n ? unknown\n : { readonly \"~StrayGroup\": StrayGroup<Entries, Scope> };\n\n/**\n * An opaque identity: its string representation is not part of the API.\n */\nexport type MountScope<\n Parent extends IdScope.IdScope,\n Name extends string | undefined,\n> = IdScope.Mount<Parent, Name>;\n\ntype MountName<ComponentApi> =\n ComponentApi extends FunctionReference<any, any, any, any, infer Name>\n ? Name\n : ComponentApi extends object\n ? {\n [Key in keyof ComponentApi]: MountName<ComponentApi[Key]>;\n }[keyof ComponentApi]\n : never;\n\ntype BindRefs<\n RefTree,\n From extends IdScope.IdScope,\n To extends IdScope.IdScope,\n> = RefTree extends Ref.Any\n ? RefTree extends { readonly _tag: \"Convex\" }\n ? Ref.ConvexRef<\n Ref.GetRuntimeAndFunctionType<RefTree>,\n \"internal\",\n Extract<Wire<Ref.Args<RefTree>>, DefaultFunctionArgs>,\n Wire<Ref.Returns<RefTree>>\n >\n : Extract<\n Ref.Ref<\n Ref.GetRuntimeAndFunctionType<RefTree>,\n \"internal\",\n Extract<\n GenericId.Rebase<Ref.Args<RefTree>, From, To>,\n DefaultFunctionArgs\n >,\n GenericId.Rebase<Ref.Returns<RefTree>, From, To>,\n GenericId.Rebase<Ref.Error<RefTree>, From, To>\n >,\n { readonly _tag: RefTree[\"_tag\"] }\n >\n : { [Key in keyof RefTree]: BindRefs<RefTree[Key], From, To> };\n\nexport type Bound<\n Spec_ extends Spec.AnyWithProps,\n From extends IdScope.IdScope,\n To extends IdScope.IdScope,\n Tables extends string,\n> = BindRefs<Refs.Refs<Spec_, Ref.AnyPublic>, From, To> & {\n readonly [BoundTypeId]: {\n readonly from: From;\n readonly scope: To;\n readonly tables: ReadonlyArray<Tables>;\n };\n};\n\n/**\n * Build a publishable contract containing only exported functions and codecs.\n * `tables` lists the component's tables, each a table or a system table's name.\n * A table grouped by an id must group by an id of one of these tables.\n */\nexport function contract<\n Spec_ extends Spec.AnyWithProps,\n const Scope extends IdScope.IdScope,\n const Entries extends ReadonlyArray<TableEntry>,\n>(\n spec: Spec_,\n scope: Scope,\n tables: Entries & CheckGroups<Entries, Scope>,\n): Component<Spec_, Scope, EntryName<Entries[number]>, Groups<Entries>>;\n/**\n * Table names alone, as in an explicit third type argument, carry no groups.\n */\nexport function contract<\n Spec_ extends Spec.AnyWithProps,\n const Scope extends IdScope.IdScope,\n const Tables extends string,\n>(\n spec: Spec_,\n scope: Scope,\n tables: ReadonlyArray<Tables>,\n): Component<Spec_, Scope, Tables, {}>;\nexport function contract(\n spec: Spec.AnyWithProps,\n scope: IdScope.IdScope,\n tables: ReadonlyArray<TableEntry>,\n): Component<Spec.AnyWithProps, IdScope.IdScope> {\n const specGroups = Spec.groups(spec);\n Result.getOrThrow(validateContract(scope, specGroups));\n const collect = (\n groups: Readonly<Record<string, GroupSpec.AnyWithProps>>,\n prefix = \"\",\n ): Tree =>\n pipe(\n groups,\n Record.map((group, name) => {\n const path = prefix === \"\" ? name : `${prefix}/${name}`;\n const functions = pipe(\n group.functions,\n Record.filter((functionSpec) => {\n return Match.value(functionSpec.functionVisibility).pipe(\n Match.when(\"public\", () => true),\n Match.when(\"internal\", () => false),\n Match.exhaustive,\n );\n }),\n Record.map((functionSpec) =>\n Ref.make(path, functionSpec, group.middlewareAttachments),\n ),\n );\n return { ...collect(group.groups, path), ...functions };\n }),\n Record.filter((children) => !Record.isEmptyRecord(children)),\n );\n const grouped: GroupMap = pipe(\n tables,\n Array.flatMap((entry) =>\n typeof entry !== \"string\" && entry.group !== undefined\n ? [[entry.tableName, entry.group] as const]\n : [],\n ),\n Record.fromEntries,\n );\n const published: Component<\n Spec.AnyWithProps,\n IdScope.IdScope\n >[typeof TypeId] = {\n refs: collect(specGroups),\n scope,\n tables: Array.map(tables, (entry) =>\n typeof entry === \"string\" ? entry : entry.tableName,\n ),\n groups: grouped,\n };\n return { [TypeId]: published } as Component<\n Spec.AnyWithProps,\n IdScope.IdScope\n >;\n}\n\n/**\n * Each grouped table's id field and the table that id names.\n */\nexport const groups = <Groups_ extends GroupMap>(\n component: Component<Spec.AnyWithProps, IdScope.IdScope, string, Groups_>,\n): Groups_ =>\n Record.map(component[TypeId].groups, ({ key, table }) => ({\n key,\n table,\n })) as Groups_;\n\n/**\n * Bind the published contract to an actual installed component reference.\n */\nexport const bind = <\n Spec_ extends Spec.AnyWithProps,\n From extends IdScope.IdScope,\n Tables extends string,\n Native extends Api<NoInfer<Spec_>>,\n const Parent extends IdScope.IdScope = IdScope.App,\n>(\n component: Component<Spec_, From, Tables>,\n native: Native,\n options?: { readonly parentScope: Parent },\n): Bound<\n Spec_,\n From,\n MountScope<Parent, Extract<MountName<Native>, string | undefined>>,\n Tables\n> => {\n const published = component[TypeId];\n const address = getFunctionAddress(native);\n const installedReference = Result.getOrThrow(\n Result.fromNullishOr(\n address.reference,\n () =>\n new UninstalledComponentReferenceError({\n definitionScope: published.scope,\n }),\n ),\n );\n // Preserve the opaque address as an identity only. Calls retain the native\n // references; no component address is constructed or parsed for routing.\n const scope = IdScope.instance(\n options?.parentScope ?? IdScope.app,\n installedReference,\n );\n const rebase = (schema: Schema.ConstraintCodec<any, any, never, never>) =>\n GenericId.rebase(schema, published.scope, scope);\n const rebaseMiddleware = memoize(\n (middleware: MiddlewareSpec.AnyMiddlewareSpec) => {\n if (!(\"error\" in middleware)) return middleware;\n const boundMiddleware = Object.create(\n middleware,\n ) as MiddlewareSpec.AnyMiddlewareSpec;\n Lazy.defineProperty(boundMiddleware, \"error\", () => {\n const error = middleware.error;\n return error === undefined ? undefined : rebase(error);\n });\n return boundMiddleware;\n },\n );\n const visit = (tree: Tree, references: unknown): Tree =>\n Record.map(tree, (child, key) => {\n const reference = (references as Record<string, unknown>)[key];\n if (Ref.isRef(child)) {\n const nativeRef = reference as FunctionReference<any, any>;\n return Match.value(child).pipe(\n Match.tag(\"Convex\", (ref) => ({\n ...ref,\n functionReference: nativeRef,\n })),\n Match.tag(\"Confect\", (ref) => {\n const provenance = {\n _tag: \"Confect\" as const,\n kind: Match.value(ref.kind).pipe(\n Match.tag(\"Standard\", (kind) => kind),\n Match.tag(\"Paginated\", (kind) => {\n const boundKind = { _tag: \"Paginated\" as const };\n Lazy.defineProperty(boundKind, \"userArgs\", () =>\n Schema.Struct(Record.map(kind.userArgs.fields, rebase)),\n );\n Lazy.defineProperty(boundKind, \"item\", () =>\n rebase(kind.item),\n );\n Lazy.defineProperty(boundKind, \"page\", () =>\n rebase(kind.page),\n );\n return boundKind as FunctionProvenance.Paginated;\n }),\n Match.exhaustive,\n ),\n };\n Lazy.defineProperty(provenance, \"args\", () =>\n Schema.Struct(Record.map(ref.args.fields, rebase)),\n );\n Lazy.defineProperty(provenance, \"returns\", () =>\n rebase(ref.returns),\n );\n if (\"error\" in ref) {\n Lazy.defineProperty(provenance, \"error\", () => {\n const error = ref.error;\n return error === undefined ? undefined : rebase(error);\n });\n }\n return Ref.fromProvenance(\n ref.convexFunctionName,\n provenance as FunctionProvenance.AnyConfect,\n Array.map(ref.middlewareAttachments, (attachment) => ({\n ...attachment,\n spec: rebaseMiddleware(attachment.spec),\n })),\n nativeRef,\n ref.functionType,\n ref.reservedArgument,\n );\n }),\n Match.exhaustive,\n );\n } else {\n return visit(child, reference);\n }\n });\n const refs = visit(published.refs, native);\n Object.defineProperty(refs, BoundTypeId, {\n value: { from: published.scope, scope, tables: published.tables },\n });\n return refs as Bound<\n Spec_,\n From,\n MountScope<Parent, Extract<MountName<Native>, string | undefined>>,\n Tables\n >;\n};\n\n/**\n * Reference an installed component's table ID in host schemas.\n */\nexport const id = <\n From extends IdScope.IdScope,\n To extends IdScope.IdScope,\n Tables extends string,\n const Table extends Tables,\n>(\n component: {\n readonly [BoundTypeId]: {\n readonly from: From;\n readonly scope: To;\n readonly tables: ReadonlyArray<Tables>;\n };\n },\n table: Table,\n) => GenericId.GenericId(table, component[BoundTypeId].scope);\n\n/**\n * Reuse a component's codec in a host function or table without losing its\n * scope.\n */\nexport const schema = <\n From extends IdScope.IdScope,\n To extends IdScope.IdScope,\n Schema_ extends Schema.Codec<any, any>,\n>(\n component: {\n readonly [BoundTypeId]: { readonly from: From; readonly scope: To };\n },\n codec: Schema_,\n) =>\n GenericId.rebase(\n codec,\n component[BoundTypeId].from,\n component[BoundTypeId].scope,\n );\n\n/**\n * A component's `init`: an internal Confect mutation whose args are the install\n * args each mount passes.\n */\nexport type Init = Ref.AnyConfect & {\n readonly \"~RuntimeAndFunctionType\": RuntimeAndFunctionType.ConvexMutation;\n readonly \"~FunctionVisibility\": \"internal\";\n};\n\nexport interface DescriptorOptions {\n readonly init?: Init;\n /**\n * The component's `_generated/component` contract. A mount of a descriptor\n * with one rebases a callback slot's args with `callbackArgs`.\n */\n readonly contract?: Component<Spec.AnyWithProps, IdScope.IdScope, string>;\n readonly env?: Readonly<Record<string, Schema.Top>>;\n /**\n * Builds the component's client from its native mount, then the mount's\n * `options` when the client takes any.\n */\n readonly client: (...args: never) => unknown;\n}\n\nexport type Descriptor<\n Name extends string = string,\n Options extends DescriptorOptions = DescriptorOptions,\n> = Options & { readonly name: Name };\n\n/**\n * Describe a Convex component for `Mount.make`, as `defineComponent` does for\n * Convex. A component with `init` takes install `args` at each mount, and one\n * with `env` takes `env`. Export it from the package's `./client` entry.\n *\n * ```ts\n * export default Component.make(\"email\", {\n * init: refs.internal.install.init,\n * env: { RESEND_API_KEY: Schema.String },\n * client: Client.make,\n * });\n * ```\n */\nexport const make = <\n const Name extends string,\n const Options extends DescriptorOptions,\n>(\n name: Name,\n options: Options,\n): Descriptor<Name, Options> => ({ ...options, name });\n"],"mappings":"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"}
|
package/dist/Table.d.ts
CHANGED
|
@@ -2,16 +2,50 @@ import * as IdScope from "./IdScope.js";
|
|
|
2
2
|
import * as SystemFields from "./SystemFields.js";
|
|
3
3
|
import type { TableSchemaToTableValidator } from "./SchemaToValidator.js";
|
|
4
4
|
import type { SystemFields as ConvexSystemFields, Expand, GenericTableIndexes, GenericTableSearchIndexes, GenericTableVectorIndexes, IndexTiebreakerField, SearchIndexConfig, VectorIndexConfig } from "convex/server";
|
|
5
|
-
import type { GenericValidator, Validator } from "convex/values";
|
|
5
|
+
import type { GenericId as ConvexGenericId, GenericValidator, Validator } from "convex/values";
|
|
6
6
|
import type * as Schema from "effect/Schema";
|
|
7
7
|
export declare const TypeId = "~@confect/core/Table";
|
|
8
8
|
export type TypeId = typeof TypeId;
|
|
9
9
|
export declare const isTable: (u: unknown) => u is Any;
|
|
10
10
|
export declare const isUnnamedTable: (u: unknown) => u is UnnamedAny;
|
|
11
|
-
export interface
|
|
11
|
+
export interface Group<Key extends string = string, Table_ extends string = string, Scope_ extends IdScope.IdScope = IdScope.IdScope> {
|
|
12
|
+
readonly key: Key;
|
|
13
|
+
readonly table: Table_;
|
|
14
|
+
readonly scope: Scope_;
|
|
15
|
+
}
|
|
16
|
+
declare const GroupFieldError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
17
|
+
readonly _tag: "GroupFieldError";
|
|
18
|
+
} & Readonly<A>;
|
|
19
|
+
export declare class GroupFieldError extends GroupFieldError_base<{
|
|
20
|
+
readonly tableName: string;
|
|
21
|
+
readonly key: string;
|
|
22
|
+
}> {
|
|
23
|
+
get message(): string;
|
|
24
|
+
}
|
|
25
|
+
type FieldsOf<TableSchema_> = TableSchema_ extends {
|
|
26
|
+
readonly fields: infer StructFields extends Schema.Struct.Fields;
|
|
27
|
+
} ? StructFields : never;
|
|
28
|
+
type GroupKeys<TableSchema_> = {
|
|
29
|
+
[Key in keyof FieldsOf<TableSchema_> & string]: FieldsOf<TableSchema_>[Key] extends {
|
|
30
|
+
readonly Type: ConvexGenericId<string>;
|
|
31
|
+
} ? [FieldsOf<TableSchema_>[Key]["~type.optionality"]] extends ["optional"] ? never : Key : never;
|
|
32
|
+
}[keyof FieldsOf<TableSchema_> & string];
|
|
33
|
+
type IdTableName<Id> = Id extends {
|
|
34
|
+
readonly "~@confect/core/ScopedId": {
|
|
35
|
+
readonly table: infer TableName extends string;
|
|
36
|
+
};
|
|
37
|
+
} ? TableName : Id extends ConvexGenericId<infer TableName> ? TableName : never;
|
|
38
|
+
type IdScopeOf<Id> = Id extends {
|
|
39
|
+
readonly "~@confect/core/ScopedId": {
|
|
40
|
+
readonly scope: infer Scope_ extends IdScope.IdScope;
|
|
41
|
+
};
|
|
42
|
+
} ? Scope_ : IdScope.App;
|
|
43
|
+
type GroupOf<TableSchema_, Key extends string> = Group<Key, IdTableName<FieldsOf<TableSchema_>[Key & keyof FieldsOf<TableSchema_>]["Type"]>, IdScopeOf<FieldsOf<TableSchema_>[Key & keyof FieldsOf<TableSchema_>]["Type"]>>;
|
|
44
|
+
export interface Table<Name_ extends string, TableSchema_ extends Schema.Codec<any, any>, TableValidator_ extends GenericValidator = TableSchemaToTableValidator<TableSchema_>, Indexes_ extends GenericTableIndexes = {}, SearchIndexes_ extends GenericTableSearchIndexes = {}, VectorIndexes_ extends GenericTableVectorIndexes = {}, Scope_ extends IdScope.IdScope = IdScope.App, Group_ extends Group | undefined = undefined> {
|
|
12
45
|
readonly [TypeId]: TypeId;
|
|
13
46
|
readonly tableName: Name_;
|
|
14
47
|
readonly scope: Scope_;
|
|
48
|
+
readonly group: Group_;
|
|
15
49
|
readonly Fields: TableSchema_;
|
|
16
50
|
readonly Doc: SystemFields.ExtendWithSystemFields<Name_, TableSchema_, Scope_>;
|
|
17
51
|
readonly indexes: Indexes_;
|
|
@@ -23,9 +57,9 @@ export interface Any {
|
|
|
23
57
|
readonly [TypeId]: TypeId;
|
|
24
58
|
readonly tableName: string;
|
|
25
59
|
}
|
|
26
|
-
export type AnyWithProps = Table<any, Schema.Codec<any, any>, GenericValidator, GenericTableIndexes, GenericTableSearchIndexes, GenericTableVectorIndexes, IdScope.IdScope>;
|
|
27
|
-
export interface UnnamedTable<TableSchema_ extends Schema.Codec<any, any>, TableValidator_ extends GenericValidator = TableSchemaToTableValidator<TableSchema_>, Indexes_ extends GenericTableIndexes = {}, SearchIndexes_ extends GenericTableSearchIndexes = {}, VectorIndexes_ extends GenericTableVectorIndexes = {}> {
|
|
28
|
-
<const Name_ extends string, const Scope_ extends IdScope.IdScope = IdScope.App>(tableName: Name_, scope?: Scope_): Table<Name_, TableSchema_, TableValidator_, Indexes_, SearchIndexes_, VectorIndexes_, Scope_>;
|
|
60
|
+
export type AnyWithProps = Table<any, Schema.Codec<any, any>, GenericValidator, GenericTableIndexes, GenericTableSearchIndexes, GenericTableVectorIndexes, IdScope.IdScope, Group | undefined>;
|
|
61
|
+
export interface UnnamedTable<TableSchema_ extends Schema.Codec<any, any>, TableValidator_ extends GenericValidator = TableSchemaToTableValidator<TableSchema_>, Indexes_ extends GenericTableIndexes = {}, SearchIndexes_ extends GenericTableSearchIndexes = {}, VectorIndexes_ extends GenericTableVectorIndexes = {}, Group_ extends Group | undefined = undefined> {
|
|
62
|
+
<const Name_ extends string, const Scope_ extends IdScope.IdScope = IdScope.App>(tableName: Name_, scope?: Scope_): Table<Name_, TableSchema_, TableValidator_, Indexes_, SearchIndexes_, VectorIndexes_, Scope_, Group_>;
|
|
29
63
|
readonly [TypeId]: TypeId;
|
|
30
64
|
readonly indexes: Indexes_;
|
|
31
65
|
readonly searchIndexes: SearchIndexes_;
|
|
@@ -35,21 +69,26 @@ export interface UnnamedTable<TableSchema_ extends Schema.Codec<any, any>, Table
|
|
|
35
69
|
FirstFieldPath,
|
|
36
70
|
...RestFieldPaths,
|
|
37
71
|
IndexTiebreakerField
|
|
38
|
-
]>>, SearchIndexes_, VectorIndexes_>;
|
|
72
|
+
]>>, SearchIndexes_, VectorIndexes_, Group_>;
|
|
39
73
|
searchIndex<IndexName extends string, SearchField extends ExtractFieldPaths<TableValidator_>, FilterFields extends ExtractFieldPaths<TableValidator_> = never>(name: IndexName, indexConfig: Expand<SearchIndexConfig<SearchField, FilterFields>>): UnnamedTable<TableSchema_, TableValidator_, Indexes_, Expand<SearchIndexes_ & Record<IndexName, {
|
|
40
74
|
searchField: SearchField;
|
|
41
75
|
filterFields: FilterFields;
|
|
42
|
-
}>>, VectorIndexes_>;
|
|
76
|
+
}>>, VectorIndexes_, Group_>;
|
|
43
77
|
vectorIndex<IndexName extends string, VectorField extends ExtractFieldPaths<TableValidator_>, FilterFields extends ExtractFieldPaths<TableValidator_> = never>(name: IndexName, indexConfig: Expand<VectorIndexConfig<VectorField, FilterFields>>): UnnamedTable<TableSchema_, TableValidator_, Indexes_, SearchIndexes_, Expand<VectorIndexes_ & Record<IndexName, {
|
|
44
78
|
vectorField: VectorField;
|
|
45
79
|
dimensions: number;
|
|
46
80
|
filterFields: FilterFields;
|
|
47
|
-
}
|
|
81
|
+
}>>, Group_>;
|
|
82
|
+
/**
|
|
83
|
+
* Name the required id field that groups this table's rows. The field's table
|
|
84
|
+
* is the one whose rows own these rows.
|
|
85
|
+
*/
|
|
86
|
+
group<const Key extends GroupKeys<TableSchema_>>(key: Key): UnnamedTable<TableSchema_, TableValidator_, Indexes_, SearchIndexes_, VectorIndexes_, GroupOf<TableSchema_, Key>>;
|
|
48
87
|
}
|
|
49
88
|
export interface UnnamedAny {
|
|
50
89
|
readonly [TypeId]: TypeId;
|
|
51
90
|
}
|
|
52
|
-
export type UnnamedAnyWithProps = UnnamedTable<Schema.Codec<any, any>, GenericValidator, GenericTableIndexes, GenericTableSearchIndexes, GenericTableVectorIndexes>;
|
|
91
|
+
export type UnnamedAnyWithProps = UnnamedTable<Schema.Codec<any, any>, GenericValidator, GenericTableIndexes, GenericTableSearchIndexes, GenericTableVectorIndexes, Group | undefined>;
|
|
53
92
|
export type Name<TableDef extends AnyWithProps> = TableDef["tableName"] & string;
|
|
54
93
|
export type TableSchema<TableDef extends AnyWithProps> = TableDef["Fields"];
|
|
55
94
|
export type TableValidator<TableDef extends AnyWithProps> = TableDef["~TableValidator"];
|
package/dist/Table.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Table.d.ts","sourceRoot":"","sources":["../src/Table.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Table.d.ts","sourceRoot":"","sources":["../src/Table.ts"],"names":[],"mappings":"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"}
|
package/dist/Table.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { __exportAll } from "./_virtual/_rolldown/runtime.js";
|
|
2
2
|
import { defineProperty } from "./Lazy.js";
|
|
3
3
|
import { app } from "./IdScope.js";
|
|
4
|
+
import { scope, tableName } from "./GenericId.js";
|
|
4
5
|
import { extendWithSystemFields } from "./SystemFields.js";
|
|
5
6
|
import * as Predicate from "effect/Predicate";
|
|
7
|
+
import * as Data from "effect/Data";
|
|
8
|
+
import * as Option from "effect/Option";
|
|
6
9
|
//#region src/Table.ts
|
|
7
10
|
var Table_exports = /* @__PURE__ */ __exportAll({
|
|
11
|
+
GroupFieldError: () => GroupFieldError,
|
|
8
12
|
TypeId: () => TypeId,
|
|
9
13
|
isTable: () => isTable,
|
|
10
14
|
isUnnamedTable: () => isUnnamedTable,
|
|
@@ -13,11 +17,35 @@ var Table_exports = /* @__PURE__ */ __exportAll({
|
|
|
13
17
|
const TypeId = "~@confect/core/Table";
|
|
14
18
|
const isTable = (u) => Predicate.hasProperty(u, "~@confect/core/Table") && Predicate.hasProperty(u, "tableName");
|
|
15
19
|
const isUnnamedTable = (u) => Predicate.hasProperty(u, "~@confect/core/Table") && !Predicate.hasProperty(u, "tableName");
|
|
20
|
+
var GroupFieldError = class extends Data.TaggedError("GroupFieldError") {
|
|
21
|
+
get message() {
|
|
22
|
+
return `Table '${this.tableName}' cannot be grouped by '${this.key}': it is not a field holding an id.`;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const makeGroup = (tableName$1, key, fields) => {
|
|
26
|
+
const idField = () => {
|
|
27
|
+
const ast = fields().fields?.[key]?.ast;
|
|
28
|
+
const table = ast === void 0 ? Option.none() : tableName(ast);
|
|
29
|
+
if (ast === void 0 || Option.isNone(table)) throw new GroupFieldError({
|
|
30
|
+
tableName: tableName$1,
|
|
31
|
+
key
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
table: table.value,
|
|
35
|
+
scope: scope(ast)
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
const group = { key };
|
|
39
|
+
defineProperty(group, "table", () => idField().table);
|
|
40
|
+
defineProperty(group, "scope", () => idField().scope);
|
|
41
|
+
return group;
|
|
42
|
+
};
|
|
16
43
|
const makeBound = (tableName, state, scope) => {
|
|
17
44
|
const bound = {
|
|
18
45
|
[TypeId]: TypeId,
|
|
19
46
|
tableName,
|
|
20
47
|
scope,
|
|
48
|
+
group: state.groupKey === void 0 ? void 0 : makeGroup(tableName, state.groupKey, () => bound.Fields),
|
|
21
49
|
indexes: state.indexes,
|
|
22
50
|
searchIndexes: state.searchIndexes,
|
|
23
51
|
vectorIndexes: state.vectorIndexes
|
|
@@ -29,32 +57,30 @@ const makeBound = (tableName, state, scope) => {
|
|
|
29
57
|
const makeUnnamed = (state) => {
|
|
30
58
|
const bind = (tableName, scope) => makeBound(tableName, state, scope ?? app);
|
|
31
59
|
const index = (name, fields) => makeUnnamed({
|
|
32
|
-
|
|
60
|
+
...state,
|
|
33
61
|
indexes: {
|
|
34
62
|
...state.indexes,
|
|
35
63
|
[name]: fields
|
|
36
|
-
}
|
|
37
|
-
searchIndexes: state.searchIndexes,
|
|
38
|
-
vectorIndexes: state.vectorIndexes
|
|
64
|
+
}
|
|
39
65
|
});
|
|
40
66
|
const searchIndex = (name, indexConfig) => makeUnnamed({
|
|
41
|
-
|
|
42
|
-
indexes: state.indexes,
|
|
67
|
+
...state,
|
|
43
68
|
searchIndexes: {
|
|
44
69
|
...state.searchIndexes,
|
|
45
70
|
[name]: indexConfig
|
|
46
|
-
}
|
|
47
|
-
vectorIndexes: state.vectorIndexes
|
|
71
|
+
}
|
|
48
72
|
});
|
|
49
73
|
const vectorIndex = (name, indexConfig) => makeUnnamed({
|
|
50
|
-
|
|
51
|
-
indexes: state.indexes,
|
|
52
|
-
searchIndexes: state.searchIndexes,
|
|
74
|
+
...state,
|
|
53
75
|
vectorIndexes: {
|
|
54
76
|
...state.vectorIndexes,
|
|
55
77
|
[name]: indexConfig
|
|
56
78
|
}
|
|
57
79
|
});
|
|
80
|
+
const group = (key) => makeUnnamed({
|
|
81
|
+
...state,
|
|
82
|
+
groupKey: key
|
|
83
|
+
});
|
|
58
84
|
return Object.assign(bind, {
|
|
59
85
|
[TypeId]: TypeId,
|
|
60
86
|
indexes: state.indexes,
|
|
@@ -62,18 +88,20 @@ const makeUnnamed = (state) => {
|
|
|
62
88
|
vectorIndexes: state.vectorIndexes,
|
|
63
89
|
index,
|
|
64
90
|
searchIndex,
|
|
65
|
-
vectorIndex
|
|
91
|
+
vectorIndex,
|
|
92
|
+
group
|
|
66
93
|
});
|
|
67
94
|
};
|
|
68
95
|
const make = (lazyFields) => {
|
|
69
96
|
return makeUnnamed({
|
|
70
97
|
lazyFields,
|
|
98
|
+
groupKey: void 0,
|
|
71
99
|
indexes: {},
|
|
72
100
|
searchIndexes: {},
|
|
73
101
|
vectorIndexes: {}
|
|
74
102
|
});
|
|
75
103
|
};
|
|
76
104
|
//#endregion
|
|
77
|
-
export { Table_exports, TypeId, isTable, isUnnamedTable, make };
|
|
105
|
+
export { GroupFieldError, Table_exports, TypeId, isTable, isUnnamedTable, make };
|
|
78
106
|
|
|
79
107
|
//# sourceMappingURL=Table.js.map
|
package/dist/Table.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Table.js","names":["SystemFields.extendWithSystemFields","IdScope.app"],"sources":["../src/Table.ts"],"sourcesContent":["import * as IdScope from \"./IdScope.js\";\nimport * as Lazy from \"./Lazy.js\";\nimport * as SystemFields from \"./SystemFields.js\";\nimport type { TableSchemaToTableValidator } from \"./SchemaToValidator.js\";\nimport type {\n SystemFields as ConvexSystemFields,\n Expand,\n GenericTableIndexes,\n GenericTableSearchIndexes,\n GenericTableVectorIndexes,\n IndexTiebreakerField,\n SearchIndexConfig,\n VectorIndexConfig,\n} from \"convex/server\";\nimport type { GenericValidator, Validator } from \"convex/values\";\nimport * as Predicate from \"effect/Predicate\";\nimport type * as Schema from \"effect/Schema\";\n\nexport const TypeId = \"~@confect/core/Table\";\nexport type TypeId = typeof TypeId;\n\n// -----------------------------------------------------------------------------\n// Predicates\n// -----------------------------------------------------------------------------\n//\n// Both bound `Table`s and `UnnamedTable` callables share the same `[TypeId]`\n// brand. They disambiguate by whether a `tableName` property is set: bound\n// tables have one, unnamed callables do not.\n//\n// The discriminator is `tableName` (not `name`) so it does not collide with\n// the built-in `Function.prototype.name` that every JS function carries.\n\nexport const isTable = (u: unknown): u is Any =>\n Predicate.hasProperty(u, TypeId) && Predicate.hasProperty(u, \"tableName\");\n\nexport const isUnnamedTable = (u: unknown): u is UnnamedAny =>\n Predicate.hasProperty(u, TypeId) && !Predicate.hasProperty(u, \"tableName\");\n\n// -----------------------------------------------------------------------------\n// Bound Table\n// -----------------------------------------------------------------------------\n//\n// A bound `Table` is the client-safe document schema: `Fields`, `Doc`, and\n// the index metadata records. The Convex deploy `tableDefinition` (which\n// value-imports `convex/server`) is produced separately by\n// `@confect/server/Table.tableDefinition`.\n\nexport interface Table<\n Name_ extends string,\n TableSchema_ extends Schema.Codec<any, any>,\n TableValidator_ extends GenericValidator =\n TableSchemaToTableValidator<TableSchema_>,\n Indexes_ extends GenericTableIndexes = {},\n SearchIndexes_ extends GenericTableSearchIndexes = {},\n VectorIndexes_ extends GenericTableVectorIndexes = {},\n Scope_ extends IdScope.IdScope = IdScope.App,\n> {\n readonly [TypeId]: TypeId;\n readonly tableName: Name_;\n readonly scope: Scope_;\n readonly Fields: TableSchema_;\n readonly Doc: SystemFields.ExtendWithSystemFields<\n Name_,\n TableSchema_,\n Scope_\n >;\n readonly indexes: Indexes_;\n readonly searchIndexes: SearchIndexes_;\n readonly vectorIndexes: VectorIndexes_;\n readonly \"~TableValidator\": TableValidator_;\n}\n\nexport interface Any {\n readonly [TypeId]: TypeId;\n readonly tableName: string;\n}\n\nexport type AnyWithProps = Table<\n any,\n Schema.Codec<any, any>,\n GenericValidator,\n GenericTableIndexes,\n GenericTableSearchIndexes,\n GenericTableVectorIndexes,\n IdScope.IdScope\n>;\n\n// -----------------------------------------------------------------------------\n// UnnamedTable (callable)\n// -----------------------------------------------------------------------------\n//\n// `Table.make(lazyFields)` returns an `UnnamedTable`: a callable that\n// produces a fully bound `Table` when invoked with a name. Chaining methods\n// (`.index`, `.searchIndex`, `.vectorIndex`) live here and return new\n// `UnnamedTable`s, accumulating plain index metadata records. The\n// user-supplied `lazyFields` callback is just carried through until first\n// access of `Fields`/`Doc` on a bound table. The codegen pipeline emits a\n// wrapper file per user-authored table that simply invokes the unnamed\n// callable with the filename basename.\n\nexport interface UnnamedTable<\n TableSchema_ extends Schema.Codec<any, any>,\n TableValidator_ extends GenericValidator =\n TableSchemaToTableValidator<TableSchema_>,\n Indexes_ extends GenericTableIndexes = {},\n SearchIndexes_ extends GenericTableSearchIndexes = {},\n VectorIndexes_ extends GenericTableVectorIndexes = {},\n> {\n <\n const Name_ extends string,\n const Scope_ extends IdScope.IdScope = IdScope.App,\n >(\n tableName: Name_,\n scope?: Scope_,\n ): Table<\n Name_,\n TableSchema_,\n TableValidator_,\n Indexes_,\n SearchIndexes_,\n VectorIndexes_,\n Scope_\n >;\n\n readonly [TypeId]: TypeId;\n readonly indexes: Indexes_;\n readonly searchIndexes: SearchIndexes_;\n readonly vectorIndexes: VectorIndexes_;\n readonly \"~TableValidator\": TableValidator_;\n\n index<\n IndexName extends string,\n FirstFieldPath extends ExtractFieldPaths<TableValidator_>,\n RestFieldPaths extends ExtractFieldPaths<TableValidator_>[],\n >(\n name: IndexName,\n fields: [FirstFieldPath, ...RestFieldPaths],\n ): UnnamedTable<\n TableSchema_,\n TableValidator_,\n Expand<\n Indexes_ &\n Record<\n IndexName,\n [FirstFieldPath, ...RestFieldPaths, IndexTiebreakerField]\n >\n >,\n SearchIndexes_,\n VectorIndexes_\n >;\n\n searchIndex<\n IndexName extends string,\n SearchField extends ExtractFieldPaths<TableValidator_>,\n FilterFields extends ExtractFieldPaths<TableValidator_> = never,\n >(\n name: IndexName,\n indexConfig: Expand<SearchIndexConfig<SearchField, FilterFields>>,\n ): UnnamedTable<\n TableSchema_,\n TableValidator_,\n Indexes_,\n Expand<\n SearchIndexes_ &\n Record<\n IndexName,\n {\n searchField: SearchField;\n filterFields: FilterFields;\n }\n >\n >,\n VectorIndexes_\n >;\n\n vectorIndex<\n IndexName extends string,\n VectorField extends ExtractFieldPaths<TableValidator_>,\n FilterFields extends ExtractFieldPaths<TableValidator_> = never,\n >(\n name: IndexName,\n indexConfig: Expand<VectorIndexConfig<VectorField, FilterFields>>,\n ): UnnamedTable<\n TableSchema_,\n TableValidator_,\n Indexes_,\n SearchIndexes_,\n Expand<\n VectorIndexes_ &\n Record<\n IndexName,\n {\n vectorField: VectorField;\n dimensions: number;\n filterFields: FilterFields;\n }\n >\n >\n >;\n}\n\nexport interface UnnamedAny {\n readonly [TypeId]: TypeId;\n}\n\nexport type UnnamedAnyWithProps = UnnamedTable<\n Schema.Codec<any, any>,\n GenericValidator,\n GenericTableIndexes,\n GenericTableSearchIndexes,\n GenericTableVectorIndexes\n>;\n\n// -----------------------------------------------------------------------------\n// Type extractors\n// -----------------------------------------------------------------------------\n\nexport type Name<TableDef extends AnyWithProps> = TableDef[\"tableName\"] &\n string;\n\nexport type TableSchema<TableDef extends AnyWithProps> = TableDef[\"Fields\"];\n\nexport type TableValidator<TableDef extends AnyWithProps> =\n TableDef[\"~TableValidator\"];\n\nexport type Indexes<TableDef extends AnyWithProps> = TableDef[\"indexes\"];\n\nexport type SearchIndexes<TableDef extends AnyWithProps> =\n TableDef[\"searchIndexes\"];\n\nexport type VectorIndexes<TableDef extends AnyWithProps> =\n TableDef[\"vectorIndexes\"];\n\nexport type Doc<TableDef extends AnyWithProps> = TableDef[\"Doc\"];\n\nexport type Fields<TableDef extends AnyWithProps> = TableDef[\"Fields\"];\nexport type Scope<TableDef extends AnyWithProps> = TableDef[\"scope\"];\n\nexport type WithName<\n TableDef extends AnyWithProps,\n Name_ extends string,\n> = TableDef extends { readonly tableName: Name_ } ? TableDef : never;\n\nexport type TablesRecord<Tables extends AnyWithProps> = {\n readonly [TableName_ in Name<Tables>]: WithName<Tables, TableName_>;\n};\n\n// -----------------------------------------------------------------------------\n// Construction\n// -----------------------------------------------------------------------------\n//\n// `make` only stores the user-supplied `lazyFields` callback alongside any\n// chained index metadata. Neither `Fields` nor `Doc` is constructed until\n// first access on a bound `Table`. Each chain step is O(1) (plain object\n// spread of the metadata records) and never invokes the callback. Binding\n// via `unnamed(tableName)` installs lazy memoised getters for `Fields` and\n// `Doc` via `Lazy.defineProperty`, so the first access materialises the\n// value and replaces the getter with a plain data property—second-and-\n// subsequent accesses are observably indistinguishable from a plain\n// property and avoid all function-call overhead.\n\ninterface UnnamedState<\n TableSchema_ extends Schema.Codec<any, any>,\n Indexes_ extends GenericTableIndexes,\n SearchIndexes_ extends GenericTableSearchIndexes,\n VectorIndexes_ extends GenericTableVectorIndexes,\n> {\n readonly lazyFields: () => TableSchema_;\n readonly indexes: Indexes_;\n readonly searchIndexes: SearchIndexes_;\n readonly vectorIndexes: VectorIndexes_;\n}\n\nconst makeBound = <\n Name_ extends string,\n TableSchema_ extends Schema.Codec<any, any>,\n TableValidator_ extends Validator<any, any, any>,\n Indexes_ extends GenericTableIndexes,\n SearchIndexes_ extends GenericTableSearchIndexes,\n VectorIndexes_ extends GenericTableVectorIndexes,\n Scope_ extends IdScope.IdScope,\n>(\n tableName: Name_,\n state: UnnamedState<TableSchema_, Indexes_, SearchIndexes_, VectorIndexes_>,\n scope: Scope_,\n): Table<\n Name_,\n TableSchema_,\n TableValidator_,\n Indexes_,\n SearchIndexes_,\n VectorIndexes_,\n Scope_\n> => {\n const bound = {\n [TypeId]: TypeId as TypeId,\n tableName,\n scope,\n indexes: state.indexes,\n searchIndexes: state.searchIndexes,\n vectorIndexes: state.vectorIndexes,\n } as Table<\n Name_,\n TableSchema_,\n TableValidator_,\n Indexes_,\n SearchIndexes_,\n VectorIndexes_,\n Scope_\n >;\n\n Lazy.defineProperty(bound, \"Fields\", () => state.lazyFields());\n\n Lazy.defineProperty(bound, \"Doc\", () =>\n SystemFields.extendWithSystemFields(\n tableName,\n (bound as { Fields: TableSchema_ }).Fields,\n scope,\n ),\n );\n\n return bound;\n};\n\nconst makeUnnamed = <\n TableSchema_ extends Schema.Codec<any, any>,\n TableValidator_ extends Validator<any, any, any>,\n Indexes_ extends GenericTableIndexes,\n SearchIndexes_ extends GenericTableSearchIndexes,\n VectorIndexes_ extends GenericTableVectorIndexes,\n>(\n state: UnnamedState<TableSchema_, Indexes_, SearchIndexes_, VectorIndexes_>,\n): UnnamedTable<\n TableSchema_,\n TableValidator_,\n Indexes_,\n SearchIndexes_,\n VectorIndexes_\n> => {\n type UnnamedTable_ = UnnamedTable<\n TableSchema_,\n TableValidator_,\n Indexes_,\n SearchIndexes_,\n VectorIndexes_\n >;\n\n type UnnamedTableFunction<FunctionName extends keyof UnnamedTable_> =\n UnnamedTable_[FunctionName];\n\n const bind = <\n const Name_ extends string,\n const Scope_ extends IdScope.IdScope = IdScope.App,\n >(\n tableName: Name_,\n scope?: Scope_,\n ): Table<\n Name_,\n TableSchema_,\n TableValidator_,\n Indexes_,\n SearchIndexes_,\n VectorIndexes_,\n Scope_\n > =>\n makeBound<\n Name_,\n TableSchema_,\n TableValidator_,\n Indexes_,\n SearchIndexes_,\n VectorIndexes_,\n Scope_\n >(tableName, state, (scope ?? IdScope.app) as Scope_);\n\n const index: UnnamedTableFunction<\"index\"> = (name, fields) =>\n makeUnnamed({\n lazyFields: state.lazyFields,\n indexes: {\n ...state.indexes,\n [name]: fields,\n } as any,\n searchIndexes: state.searchIndexes,\n vectorIndexes: state.vectorIndexes,\n });\n\n const searchIndex: UnnamedTableFunction<\"searchIndex\"> = (\n name,\n indexConfig,\n ) =>\n makeUnnamed({\n lazyFields: state.lazyFields,\n indexes: state.indexes,\n searchIndexes: {\n ...state.searchIndexes,\n [name]: indexConfig,\n } as any,\n vectorIndexes: state.vectorIndexes,\n });\n\n const vectorIndex: UnnamedTableFunction<\"vectorIndex\"> = (\n name,\n indexConfig,\n ) =>\n makeUnnamed({\n lazyFields: state.lazyFields,\n indexes: state.indexes,\n searchIndexes: state.searchIndexes,\n vectorIndexes: {\n ...state.vectorIndexes,\n [name]: indexConfig,\n } as any,\n });\n\n return Object.assign(bind, {\n [TypeId]: TypeId as TypeId,\n indexes: state.indexes,\n searchIndexes: state.searchIndexes,\n vectorIndexes: state.vectorIndexes,\n index,\n searchIndex,\n vectorIndex,\n }) as UnnamedTable_;\n};\n\nexport const make = <const TableSchema_ extends Schema.Codec<any, any>>(\n lazyFields: () => TableSchema_,\n): UnnamedTable<TableSchema_, TableSchemaToTableValidator<TableSchema_>> => {\n type TableValidator_ = TableSchemaToTableValidator<TableSchema_>;\n type UnnamedTable_ = UnnamedTable<TableSchema_, TableValidator_>;\n\n return makeUnnamed<TableSchema_, TableValidator_, {}, {}, {}>({\n lazyFields,\n indexes: {},\n searchIndexes: {},\n vectorIndexes: {},\n }) as UnnamedTable_;\n};\n\n// Vendored types from convex-js, partially modified. Ideally we could use these directly. See https://github.com/get-convex/convex-js/pull/14\n\n/**\n * Extract all of the index field paths within a Convex `Validator`.\n *\n * This is used when declaring table indexes.\n *\n * @public\n */\ntype ExtractFieldPaths<TableValidator_ extends Validator<any, any, any>> =\n // Add in the system fields available in index definitions.\n // This should be everything except for `_id` because thats added to indexes\n // automatically.\n TableValidator_[\"fieldPaths\"] | keyof ConvexSystemFields;\n"],"mappings":";;;;;;;;;;;;AAkBA,MAAa,SAAS;AActB,MAAa,WAAW,MACtB,UAAU,YAAY,GAAA,sBAAS,KAAK,UAAU,YAAY,GAAG,WAAW;AAE1E,MAAa,kBAAkB,MAC7B,UAAU,YAAY,GAAA,sBAAS,KAAK,CAAC,UAAU,YAAY,GAAG,WAAW;AA6O3E,MAAM,aASJ,WACA,OACA,UASG;CACH,MAAM,QAAQ;GACX,SAAS;EACV;EACA;EACA,SAAS,MAAM;EACf,eAAe,MAAM;EACrB,eAAe,MAAM;CACvB;CAUA,eAAoB,OAAO,gBAAgB,MAAM,WAAW,CAAC;CAE7D,eAAoB,OAAO,aACzBA,uBACE,WACC,MAAmC,QACpC,KACF,CACF;CAEA,OAAO;AACT;AAEA,MAAM,eAOJ,UAOG;CAYH,MAAM,QAIJ,WACA,UAUA,UAQE,WAAW,OAAQ,SAASC,GAAsB;CAEtD,MAAM,SAAwC,MAAM,WAClD,YAAY;EACV,YAAY,MAAM;EAClB,SAAS;GACP,GAAG,MAAM;IACR,OAAO;EACV;EACA,eAAe,MAAM;EACrB,eAAe,MAAM;CACvB,CAAC;CAEH,MAAM,eACJ,MACA,gBAEA,YAAY;EACV,YAAY,MAAM;EAClB,SAAS,MAAM;EACf,eAAe;GACb,GAAG,MAAM;IACR,OAAO;EACV;EACA,eAAe,MAAM;CACvB,CAAC;CAEH,MAAM,eACJ,MACA,gBAEA,YAAY;EACV,YAAY,MAAM;EAClB,SAAS,MAAM;EACf,eAAe,MAAM;EACrB,eAAe;GACb,GAAG,MAAM;IACR,OAAO;EACV;CACF,CAAC;CAEH,OAAO,OAAO,OAAO,MAAM;GACxB,SAAS;EACV,SAAS,MAAM;EACf,eAAe,MAAM;EACrB,eAAe,MAAM;EACrB;EACA;EACA;CACF,CAAC;AACH;AAEA,MAAa,QACX,eAC0E;CAI1E,OAAO,YAAuD;EAC5D;EACA,SAAS,CAAC;EACV,eAAe,CAAC;EAChB,eAAe,CAAC;CAClB,CAAC;AACH"}
|
|
1
|
+
{"version":3,"file":"Table.js","names":["GenericId.tableName","GenericId.scope","SystemFields.extendWithSystemFields","IdScope.app"],"sources":["../src/Table.ts"],"sourcesContent":["import * as GenericId from \"./GenericId.js\";\nimport * as IdScope from \"./IdScope.js\";\nimport * as Lazy from \"./Lazy.js\";\nimport * as SystemFields from \"./SystemFields.js\";\nimport type { TableSchemaToTableValidator } from \"./SchemaToValidator.js\";\nimport type {\n SystemFields as ConvexSystemFields,\n Expand,\n GenericTableIndexes,\n GenericTableSearchIndexes,\n GenericTableVectorIndexes,\n IndexTiebreakerField,\n SearchIndexConfig,\n VectorIndexConfig,\n} from \"convex/server\";\nimport type {\n GenericId as ConvexGenericId,\n GenericValidator,\n Validator,\n} from \"convex/values\";\nimport * as Data from \"effect/Data\";\nimport * as Option from \"effect/Option\";\nimport * as Predicate from \"effect/Predicate\";\nimport type * as Schema from \"effect/Schema\";\n\nexport const TypeId = \"~@confect/core/Table\";\nexport type TypeId = typeof TypeId;\n\n// -----------------------------------------------------------------------------\n// Predicates\n// -----------------------------------------------------------------------------\n//\n// Both bound `Table`s and `UnnamedTable` callables share the same `[TypeId]`\n// brand. They disambiguate by whether a `tableName` property is set: bound\n// tables have one, unnamed callables do not.\n//\n// The discriminator is `tableName` (not `name`) so it does not collide with\n// the built-in `Function.prototype.name` that every JS function carries.\n\nexport const isTable = (u: unknown): u is Any =>\n Predicate.hasProperty(u, TypeId) && Predicate.hasProperty(u, \"tableName\");\n\nexport const isUnnamedTable = (u: unknown): u is UnnamedAny =>\n Predicate.hasProperty(u, TypeId) && !Predicate.hasProperty(u, \"tableName\");\n\n// -----------------------------------------------------------------------------\n// Group\n// -----------------------------------------------------------------------------\n//\n// A table is grouped by one of its required id fields, and the id's table owns\n// its rows. `table` and `scope` come from the id's schema on first read, so\n// binding a table never builds its `Fields`.\n\nexport interface Group<\n Key extends string = string,\n Table_ extends string = string,\n Scope_ extends IdScope.IdScope = IdScope.IdScope,\n> {\n readonly key: Key;\n readonly table: Table_;\n readonly scope: Scope_;\n}\n\nexport class GroupFieldError extends Data.TaggedError(\"GroupFieldError\")<{\n readonly tableName: string;\n readonly key: string;\n}> {\n override get message(): string {\n return `Table '${this.tableName}' cannot be grouped by '${this.key}': it is not a field holding an id.`;\n }\n}\n\ntype FieldsOf<TableSchema_> = TableSchema_ extends {\n readonly fields: infer StructFields extends Schema.Struct.Fields;\n}\n ? StructFields\n : never;\n\ntype GroupKeys<TableSchema_> = {\n [\n Key in keyof FieldsOf<TableSchema_> & string\n ]: FieldsOf<TableSchema_>[Key] extends {\n readonly Type: ConvexGenericId<string>;\n }\n ? [FieldsOf<TableSchema_>[Key][\"~type.optionality\"]] extends [\"optional\"]\n ? never\n : Key\n : never;\n}[keyof FieldsOf<TableSchema_> & string];\n\ntype IdTableName<Id> = Id extends {\n readonly \"~@confect/core/ScopedId\": {\n readonly table: infer TableName extends string;\n };\n}\n ? TableName\n : Id extends ConvexGenericId<infer TableName>\n ? TableName\n : never;\n\ntype IdScopeOf<Id> = Id extends {\n readonly \"~@confect/core/ScopedId\": {\n readonly scope: infer Scope_ extends IdScope.IdScope;\n };\n}\n ? Scope_\n : IdScope.App;\n\ntype GroupOf<TableSchema_, Key extends string> = Group<\n Key,\n IdTableName<\n FieldsOf<TableSchema_>[Key & keyof FieldsOf<TableSchema_>][\"Type\"]\n >,\n IdScopeOf<FieldsOf<TableSchema_>[Key & keyof FieldsOf<TableSchema_>][\"Type\"]>\n>;\n\nconst makeGroup = (\n tableName: string,\n key: string,\n fields: () => Schema.Codec<any, any>,\n): Group => {\n const idField = () => {\n const ast = (fields() as { readonly fields?: Schema.Struct.Fields })\n .fields?.[key]?.ast;\n const table =\n ast === undefined ? Option.none() : GenericId.tableName<string>(ast);\n if (ast === undefined || Option.isNone(table))\n throw new GroupFieldError({ tableName, key });\n return { table: table.value, scope: GenericId.scope(ast) };\n };\n const group = { key };\n Lazy.defineProperty(group, \"table\", () => idField().table);\n Lazy.defineProperty(group, \"scope\", () => idField().scope);\n return group as Group;\n};\n\n// -----------------------------------------------------------------------------\n// Bound Table\n// -----------------------------------------------------------------------------\n//\n// A bound `Table` is the client-safe document schema: `Fields`, `Doc`, and\n// the index metadata records. The Convex deploy `tableDefinition` (which\n// value-imports `convex/server`) is produced separately by\n// `@confect/server/Table.tableDefinition`.\n\nexport interface Table<\n Name_ extends string,\n TableSchema_ extends Schema.Codec<any, any>,\n TableValidator_ extends GenericValidator =\n TableSchemaToTableValidator<TableSchema_>,\n Indexes_ extends GenericTableIndexes = {},\n SearchIndexes_ extends GenericTableSearchIndexes = {},\n VectorIndexes_ extends GenericTableVectorIndexes = {},\n Scope_ extends IdScope.IdScope = IdScope.App,\n Group_ extends Group | undefined = undefined,\n> {\n readonly [TypeId]: TypeId;\n readonly tableName: Name_;\n readonly scope: Scope_;\n readonly group: Group_;\n readonly Fields: TableSchema_;\n readonly Doc: SystemFields.ExtendWithSystemFields<\n Name_,\n TableSchema_,\n Scope_\n >;\n readonly indexes: Indexes_;\n readonly searchIndexes: SearchIndexes_;\n readonly vectorIndexes: VectorIndexes_;\n readonly \"~TableValidator\": TableValidator_;\n}\n\nexport interface Any {\n readonly [TypeId]: TypeId;\n readonly tableName: string;\n}\n\nexport type AnyWithProps = Table<\n any,\n Schema.Codec<any, any>,\n GenericValidator,\n GenericTableIndexes,\n GenericTableSearchIndexes,\n GenericTableVectorIndexes,\n IdScope.IdScope,\n Group | undefined\n>;\n\n// -----------------------------------------------------------------------------\n// UnnamedTable (callable)\n// -----------------------------------------------------------------------------\n//\n// `Table.make(lazyFields)` returns an `UnnamedTable`: a callable that\n// produces a fully bound `Table` when invoked with a name. Chaining methods\n// (`.index`, `.searchIndex`, `.vectorIndex`) live here and return new\n// `UnnamedTable`s, accumulating plain index metadata records. The\n// user-supplied `lazyFields` callback is just carried through until first\n// access of `Fields`/`Doc` on a bound table. The codegen pipeline emits a\n// wrapper file per user-authored table that simply invokes the unnamed\n// callable with the filename basename.\n\nexport interface UnnamedTable<\n TableSchema_ extends Schema.Codec<any, any>,\n TableValidator_ extends GenericValidator =\n TableSchemaToTableValidator<TableSchema_>,\n Indexes_ extends GenericTableIndexes = {},\n SearchIndexes_ extends GenericTableSearchIndexes = {},\n VectorIndexes_ extends GenericTableVectorIndexes = {},\n Group_ extends Group | undefined = undefined,\n> {\n <\n const Name_ extends string,\n const Scope_ extends IdScope.IdScope = IdScope.App,\n >(\n tableName: Name_,\n scope?: Scope_,\n ): Table<\n Name_,\n TableSchema_,\n TableValidator_,\n Indexes_,\n SearchIndexes_,\n VectorIndexes_,\n Scope_,\n Group_\n >;\n\n readonly [TypeId]: TypeId;\n readonly indexes: Indexes_;\n readonly searchIndexes: SearchIndexes_;\n readonly vectorIndexes: VectorIndexes_;\n readonly \"~TableValidator\": TableValidator_;\n\n index<\n IndexName extends string,\n FirstFieldPath extends ExtractFieldPaths<TableValidator_>,\n RestFieldPaths extends ExtractFieldPaths<TableValidator_>[],\n >(\n name: IndexName,\n fields: [FirstFieldPath, ...RestFieldPaths],\n ): UnnamedTable<\n TableSchema_,\n TableValidator_,\n Expand<\n Indexes_ &\n Record<\n IndexName,\n [FirstFieldPath, ...RestFieldPaths, IndexTiebreakerField]\n >\n >,\n SearchIndexes_,\n VectorIndexes_,\n Group_\n >;\n\n searchIndex<\n IndexName extends string,\n SearchField extends ExtractFieldPaths<TableValidator_>,\n FilterFields extends ExtractFieldPaths<TableValidator_> = never,\n >(\n name: IndexName,\n indexConfig: Expand<SearchIndexConfig<SearchField, FilterFields>>,\n ): UnnamedTable<\n TableSchema_,\n TableValidator_,\n Indexes_,\n Expand<\n SearchIndexes_ &\n Record<\n IndexName,\n {\n searchField: SearchField;\n filterFields: FilterFields;\n }\n >\n >,\n VectorIndexes_,\n Group_\n >;\n\n vectorIndex<\n IndexName extends string,\n VectorField extends ExtractFieldPaths<TableValidator_>,\n FilterFields extends ExtractFieldPaths<TableValidator_> = never,\n >(\n name: IndexName,\n indexConfig: Expand<VectorIndexConfig<VectorField, FilterFields>>,\n ): UnnamedTable<\n TableSchema_,\n TableValidator_,\n Indexes_,\n SearchIndexes_,\n Expand<\n VectorIndexes_ &\n Record<\n IndexName,\n {\n vectorField: VectorField;\n dimensions: number;\n filterFields: FilterFields;\n }\n >\n >,\n Group_\n >;\n\n /**\n * Name the required id field that groups this table's rows. The field's table\n * is the one whose rows own these rows.\n */\n group<const Key extends GroupKeys<TableSchema_>>(\n key: Key,\n ): UnnamedTable<\n TableSchema_,\n TableValidator_,\n Indexes_,\n SearchIndexes_,\n VectorIndexes_,\n GroupOf<TableSchema_, Key>\n >;\n}\n\nexport interface UnnamedAny {\n readonly [TypeId]: TypeId;\n}\n\nexport type UnnamedAnyWithProps = UnnamedTable<\n Schema.Codec<any, any>,\n GenericValidator,\n GenericTableIndexes,\n GenericTableSearchIndexes,\n GenericTableVectorIndexes,\n Group | undefined\n>;\n\n// -----------------------------------------------------------------------------\n// Type extractors\n// -----------------------------------------------------------------------------\n\nexport type Name<TableDef extends AnyWithProps> = TableDef[\"tableName\"] &\n string;\n\nexport type TableSchema<TableDef extends AnyWithProps> = TableDef[\"Fields\"];\n\nexport type TableValidator<TableDef extends AnyWithProps> =\n TableDef[\"~TableValidator\"];\n\nexport type Indexes<TableDef extends AnyWithProps> = TableDef[\"indexes\"];\n\nexport type SearchIndexes<TableDef extends AnyWithProps> =\n TableDef[\"searchIndexes\"];\n\nexport type VectorIndexes<TableDef extends AnyWithProps> =\n TableDef[\"vectorIndexes\"];\n\nexport type Doc<TableDef extends AnyWithProps> = TableDef[\"Doc\"];\n\nexport type Fields<TableDef extends AnyWithProps> = TableDef[\"Fields\"];\nexport type Scope<TableDef extends AnyWithProps> = TableDef[\"scope\"];\n\nexport type WithName<\n TableDef extends AnyWithProps,\n Name_ extends string,\n> = TableDef extends { readonly tableName: Name_ } ? TableDef : never;\n\nexport type TablesRecord<Tables extends AnyWithProps> = {\n readonly [TableName_ in Name<Tables>]: WithName<Tables, TableName_>;\n};\n\n// -----------------------------------------------------------------------------\n// Construction\n// -----------------------------------------------------------------------------\n//\n// `make` only stores the user-supplied `lazyFields` callback alongside any\n// chained index metadata. Neither `Fields` nor `Doc` is constructed until\n// first access on a bound `Table`. Each chain step is O(1) (plain object\n// spread of the metadata records) and never invokes the callback. Binding\n// via `unnamed(tableName)` installs lazy memoised getters for `Fields` and\n// `Doc` via `Lazy.defineProperty`, so the first access materialises the\n// value and replaces the getter with a plain data property—second-and-\n// subsequent accesses are observably indistinguishable from a plain\n// property and avoid all function-call overhead.\n\ninterface UnnamedState<\n TableSchema_ extends Schema.Codec<any, any>,\n Indexes_ extends GenericTableIndexes,\n SearchIndexes_ extends GenericTableSearchIndexes,\n VectorIndexes_ extends GenericTableVectorIndexes,\n> {\n readonly lazyFields: () => TableSchema_;\n readonly groupKey: string | undefined;\n readonly indexes: Indexes_;\n readonly searchIndexes: SearchIndexes_;\n readonly vectorIndexes: VectorIndexes_;\n}\n\nconst makeBound = <\n Name_ extends string,\n TableSchema_ extends Schema.Codec<any, any>,\n TableValidator_ extends Validator<any, any, any>,\n Indexes_ extends GenericTableIndexes,\n SearchIndexes_ extends GenericTableSearchIndexes,\n VectorIndexes_ extends GenericTableVectorIndexes,\n Scope_ extends IdScope.IdScope,\n Group_ extends Group | undefined,\n>(\n tableName: Name_,\n state: UnnamedState<TableSchema_, Indexes_, SearchIndexes_, VectorIndexes_>,\n scope: Scope_,\n): Table<\n Name_,\n TableSchema_,\n TableValidator_,\n Indexes_,\n SearchIndexes_,\n VectorIndexes_,\n Scope_,\n Group_\n> => {\n const bound = {\n [TypeId]: TypeId as TypeId,\n tableName,\n scope,\n group:\n state.groupKey === undefined\n ? undefined\n : makeGroup(tableName, state.groupKey, () => bound.Fields),\n indexes: state.indexes,\n searchIndexes: state.searchIndexes,\n vectorIndexes: state.vectorIndexes,\n } as Table<\n Name_,\n TableSchema_,\n TableValidator_,\n Indexes_,\n SearchIndexes_,\n VectorIndexes_,\n Scope_,\n Group_\n >;\n\n Lazy.defineProperty(bound, \"Fields\", () => state.lazyFields());\n\n Lazy.defineProperty(bound, \"Doc\", () =>\n SystemFields.extendWithSystemFields(\n tableName,\n (bound as { Fields: TableSchema_ }).Fields,\n scope,\n ),\n );\n\n return bound;\n};\n\nconst makeUnnamed = <\n TableSchema_ extends Schema.Codec<any, any>,\n TableValidator_ extends Validator<any, any, any>,\n Indexes_ extends GenericTableIndexes,\n SearchIndexes_ extends GenericTableSearchIndexes,\n VectorIndexes_ extends GenericTableVectorIndexes,\n Group_ extends Group | undefined,\n>(\n state: UnnamedState<TableSchema_, Indexes_, SearchIndexes_, VectorIndexes_>,\n): UnnamedTable<\n TableSchema_,\n TableValidator_,\n Indexes_,\n SearchIndexes_,\n VectorIndexes_,\n Group_\n> => {\n type UnnamedTable_ = UnnamedTable<\n TableSchema_,\n TableValidator_,\n Indexes_,\n SearchIndexes_,\n VectorIndexes_,\n Group_\n >;\n\n type UnnamedTableFunction<FunctionName extends keyof UnnamedTable_> =\n UnnamedTable_[FunctionName];\n\n const bind = <\n const Name_ extends string,\n const Scope_ extends IdScope.IdScope = IdScope.App,\n >(\n tableName: Name_,\n scope?: Scope_,\n ): Table<\n Name_,\n TableSchema_,\n TableValidator_,\n Indexes_,\n SearchIndexes_,\n VectorIndexes_,\n Scope_,\n Group_\n > =>\n makeBound<\n Name_,\n TableSchema_,\n TableValidator_,\n Indexes_,\n SearchIndexes_,\n VectorIndexes_,\n Scope_,\n Group_\n >(tableName, state, (scope ?? IdScope.app) as Scope_);\n\n const index: UnnamedTableFunction<\"index\"> = (name, fields) =>\n makeUnnamed({\n ...state,\n indexes: {\n ...state.indexes,\n [name]: fields,\n } as any,\n });\n\n const searchIndex: UnnamedTableFunction<\"searchIndex\"> = (\n name,\n indexConfig,\n ) =>\n makeUnnamed({\n ...state,\n searchIndexes: {\n ...state.searchIndexes,\n [name]: indexConfig,\n } as any,\n });\n\n const vectorIndex: UnnamedTableFunction<\"vectorIndex\"> = (\n name,\n indexConfig,\n ) =>\n makeUnnamed({\n ...state,\n vectorIndexes: {\n ...state.vectorIndexes,\n [name]: indexConfig,\n } as any,\n });\n\n const group: UnnamedTableFunction<\"group\"> = (key) =>\n makeUnnamed({ ...state, groupKey: key });\n\n return Object.assign(bind, {\n [TypeId]: TypeId as TypeId,\n indexes: state.indexes,\n searchIndexes: state.searchIndexes,\n vectorIndexes: state.vectorIndexes,\n index,\n searchIndex,\n vectorIndex,\n group,\n }) as UnnamedTable_;\n};\n\nexport const make = <const TableSchema_ extends Schema.Codec<any, any>>(\n lazyFields: () => TableSchema_,\n): UnnamedTable<TableSchema_, TableSchemaToTableValidator<TableSchema_>> => {\n type TableValidator_ = TableSchemaToTableValidator<TableSchema_>;\n type UnnamedTable_ = UnnamedTable<TableSchema_, TableValidator_>;\n\n return makeUnnamed<TableSchema_, TableValidator_, {}, {}, {}, undefined>({\n lazyFields,\n groupKey: undefined,\n indexes: {},\n searchIndexes: {},\n vectorIndexes: {},\n }) as UnnamedTable_;\n};\n\n// Vendored types from convex-js, partially modified. Ideally we could use these directly. See https://github.com/get-convex/convex-js/pull/14\n\n/**\n * Extract all of the index field paths within a Convex `Validator`.\n *\n * This is used when declaring table indexes.\n *\n * @public\n */\ntype ExtractFieldPaths<TableValidator_ extends Validator<any, any, any>> =\n // Add in the system fields available in index definitions.\n // This should be everything except for `_id` because thats added to indexes\n // automatically.\n TableValidator_[\"fieldPaths\"] | keyof ConvexSystemFields;\n"],"mappings":";;;;;;;;;;;;;;;;AAyBA,MAAa,SAAS;AActB,MAAa,WAAW,MACtB,UAAU,YAAY,GAAA,sBAAS,KAAK,UAAU,YAAY,GAAG,WAAW;AAE1E,MAAa,kBAAkB,MAC7B,UAAU,YAAY,GAAA,sBAAS,KAAK,CAAC,UAAU,YAAY,GAAG,WAAW;AAoB3E,IAAa,kBAAb,cAAqC,KAAK,YAAY,iBAAiB,CAAC,CAGrE;CACD,IAAa,UAAkB;EAC7B,OAAO,UAAU,KAAK,UAAU,0BAA0B,KAAK,IAAI;CACrE;AACF;AA8CA,MAAM,aACJ,aACA,KACA,WACU;CACV,MAAM,gBAAgB;EACpB,MAAM,MAAO,OAAO,CAAC,CAClB,SAAS,IAAI,EAAE;EAClB,MAAM,QACJ,QAAQ,KAAA,IAAY,OAAO,KAAK,IAAIA,UAA4B,GAAG;EACrE,IAAI,QAAQ,KAAA,KAAa,OAAO,OAAO,KAAK,GAC1C,MAAM,IAAI,gBAAgB;GAAE,WAAA;GAAW;EAAI,CAAC;EAC9C,OAAO;GAAE,OAAO,MAAM;GAAO,OAAOC,MAAgB,GAAG;EAAE;CAC3D;CACA,MAAM,QAAQ,EAAE,IAAI;CACpB,eAAoB,OAAO,eAAe,QAAQ,CAAC,CAAC,KAAK;CACzD,eAAoB,OAAO,eAAe,QAAQ,CAAC,CAAC,KAAK;CACzD,OAAO;AACT;AAsQA,MAAM,aAUJ,WACA,OACA,UAUG;CACH,MAAM,QAAQ;GACX,SAAS;EACV;EACA;EACA,OACE,MAAM,aAAa,KAAA,IACf,KAAA,IACA,UAAU,WAAW,MAAM,gBAAgB,MAAM,MAAM;EAC7D,SAAS,MAAM;EACf,eAAe,MAAM;EACrB,eAAe,MAAM;CACvB;CAWA,eAAoB,OAAO,gBAAgB,MAAM,WAAW,CAAC;CAE7D,eAAoB,OAAO,aACzBC,uBACE,WACC,MAAmC,QACpC,KACF,CACF;CAEA,OAAO;AACT;AAEA,MAAM,eAQJ,UAQG;CAaH,MAAM,QAIJ,WACA,UAWA,UASE,WAAW,OAAQ,SAASC,GAAsB;CAEtD,MAAM,SAAwC,MAAM,WAClD,YAAY;EACV,GAAG;EACH,SAAS;GACP,GAAG,MAAM;IACR,OAAO;EACV;CACF,CAAC;CAEH,MAAM,eACJ,MACA,gBAEA,YAAY;EACV,GAAG;EACH,eAAe;GACb,GAAG,MAAM;IACR,OAAO;EACV;CACF,CAAC;CAEH,MAAM,eACJ,MACA,gBAEA,YAAY;EACV,GAAG;EACH,eAAe;GACb,GAAG,MAAM;IACR,OAAO;EACV;CACF,CAAC;CAEH,MAAM,SAAwC,QAC5C,YAAY;EAAE,GAAG;EAAO,UAAU;CAAI,CAAC;CAEzC,OAAO,OAAO,OAAO,MAAM;GACxB,SAAS;EACV,SAAS,MAAM;EACf,eAAe,MAAM;EACrB,eAAe,MAAM;EACrB;EACA;EACA;EACA;CACF,CAAC;AACH;AAEA,MAAa,QACX,eAC0E;CAI1E,OAAO,YAAkE;EACvE;EACA,UAAU,KAAA;EACV,SAAS,CAAC;EACV,eAAe,CAAC;EAChB,eAAe,CAAC;CAClB,CAAC;AACH"}
|
package/package.json
CHANGED
package/src/Component.ts
CHANGED
|
@@ -18,6 +18,7 @@ import * as Ref from "./Ref.js";
|
|
|
18
18
|
import type * as Refs from "./Refs.js";
|
|
19
19
|
import type * as RuntimeAndFunctionType from "./RuntimeAndFunctionType.js";
|
|
20
20
|
import * as Spec from "./Spec.js";
|
|
21
|
+
import type * as Table_ from "./Table.js";
|
|
21
22
|
|
|
22
23
|
export class EmptyComponentScopeError extends Data.TaggedError(
|
|
23
24
|
"EmptyComponentScopeError",
|
|
@@ -142,19 +143,100 @@ interface Tree {
|
|
|
142
143
|
readonly [key: string]: Tree | Ref.Any;
|
|
143
144
|
}
|
|
144
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Each grouped table's name, mapped to its id field and that id's table.
|
|
148
|
+
*/
|
|
149
|
+
export interface GroupMap {
|
|
150
|
+
readonly [table: string]: { readonly key: string; readonly table: string };
|
|
151
|
+
}
|
|
152
|
+
|
|
145
153
|
export interface Component<
|
|
146
154
|
Spec_ extends Spec.AnyWithProps,
|
|
147
155
|
Scope extends IdScope.IdScope,
|
|
148
156
|
Tables extends string = string,
|
|
157
|
+
Groups_ extends GroupMap = GroupMap,
|
|
149
158
|
> {
|
|
150
159
|
readonly [TypeId]: {
|
|
151
160
|
readonly refs: Tree;
|
|
152
161
|
readonly scope: Scope;
|
|
153
162
|
readonly tables: ReadonlyArray<Tables>;
|
|
163
|
+
readonly groups: Groups_;
|
|
154
164
|
};
|
|
155
165
|
readonly "~Spec": Spec_;
|
|
156
166
|
}
|
|
157
167
|
|
|
168
|
+
/**
|
|
169
|
+
* A component's tables as `contract` takes them: a table, or the name of a
|
|
170
|
+
* system table.
|
|
171
|
+
*/
|
|
172
|
+
export type TableEntry = string | Table_.AnyWithProps;
|
|
173
|
+
|
|
174
|
+
type EntryName<Entry extends TableEntry> = Entry extends string
|
|
175
|
+
? Entry
|
|
176
|
+
: Entry extends Table_.AnyWithProps
|
|
177
|
+
? Table_.Name<Entry>
|
|
178
|
+
: never;
|
|
179
|
+
|
|
180
|
+
type Many<A, All = A> = string extends A
|
|
181
|
+
? true
|
|
182
|
+
: number extends A
|
|
183
|
+
? true
|
|
184
|
+
: A extends unknown
|
|
185
|
+
? [All] extends [A]
|
|
186
|
+
? never
|
|
187
|
+
: true
|
|
188
|
+
: never;
|
|
189
|
+
|
|
190
|
+
type Loose<Entries extends ReadonlyArray<TableEntry>> = true extends
|
|
191
|
+
| Many<Entries>
|
|
192
|
+
| Many<Entries["length"]>
|
|
193
|
+
| { [Index in keyof Entries]: Many<Entries[Index]> }[number]
|
|
194
|
+
? "pass one table or one name per entry; a union may be absent at runtime"
|
|
195
|
+
: never;
|
|
196
|
+
|
|
197
|
+
type StrayGroup<
|
|
198
|
+
Entries extends ReadonlyArray<TableEntry>,
|
|
199
|
+
Scope extends IdScope.IdScope,
|
|
200
|
+
> = [Loose<Entries>] extends [never]
|
|
201
|
+
? {
|
|
202
|
+
[Index in keyof Entries]: Entries[Index] extends {
|
|
203
|
+
readonly tableName: infer Name extends string;
|
|
204
|
+
readonly group: Table_.Group<infer Key, infer Target, infer GroupScope>;
|
|
205
|
+
}
|
|
206
|
+
? [Target, GroupScope] extends [EntryName<Entries[number]>, Scope]
|
|
207
|
+
? never
|
|
208
|
+
: `${Name}.${Key} is not an id of a table of this component`
|
|
209
|
+
: never;
|
|
210
|
+
}[number]
|
|
211
|
+
: Loose<Entries>;
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* The group map `contract` publishes for these table entries.
|
|
215
|
+
*/
|
|
216
|
+
export type Groups<Entries extends ReadonlyArray<TableEntry>> = {
|
|
217
|
+
readonly [
|
|
218
|
+
Entry in Extract<
|
|
219
|
+
Entries[number],
|
|
220
|
+
{ readonly tableName: string; readonly group: Table_.Group }
|
|
221
|
+
> as Entry["tableName"]
|
|
222
|
+
]: {
|
|
223
|
+
readonly key: Entry["group"]["key"];
|
|
224
|
+
readonly table: Entry["group"]["table"];
|
|
225
|
+
};
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* `unknown` when every entry is one table or name and every group's id names a
|
|
230
|
+
* table of this component in its scope, otherwise an object type naming the
|
|
231
|
+
* refused entry.
|
|
232
|
+
*/
|
|
233
|
+
export type CheckGroups<
|
|
234
|
+
Entries extends ReadonlyArray<TableEntry>,
|
|
235
|
+
Scope extends IdScope.IdScope,
|
|
236
|
+
> = [StrayGroup<Entries, Scope>] extends [never]
|
|
237
|
+
? unknown
|
|
238
|
+
: { readonly "~StrayGroup": StrayGroup<Entries, Scope> };
|
|
239
|
+
|
|
158
240
|
/**
|
|
159
241
|
* An opaque identity: its string representation is not part of the API.
|
|
160
242
|
*/
|
|
@@ -214,8 +296,22 @@ export type Bound<
|
|
|
214
296
|
|
|
215
297
|
/**
|
|
216
298
|
* Build a publishable contract containing only exported functions and codecs.
|
|
299
|
+
* `tables` lists the component's tables, each a table or a system table's name.
|
|
300
|
+
* A table grouped by an id must group by an id of one of these tables.
|
|
301
|
+
*/
|
|
302
|
+
export function contract<
|
|
303
|
+
Spec_ extends Spec.AnyWithProps,
|
|
304
|
+
const Scope extends IdScope.IdScope,
|
|
305
|
+
const Entries extends ReadonlyArray<TableEntry>,
|
|
306
|
+
>(
|
|
307
|
+
spec: Spec_,
|
|
308
|
+
scope: Scope,
|
|
309
|
+
tables: Entries & CheckGroups<Entries, Scope>,
|
|
310
|
+
): Component<Spec_, Scope, EntryName<Entries[number]>, Groups<Entries>>;
|
|
311
|
+
/**
|
|
312
|
+
* Table names alone, as in an explicit third type argument, carry no groups.
|
|
217
313
|
*/
|
|
218
|
-
export
|
|
314
|
+
export function contract<
|
|
219
315
|
Spec_ extends Spec.AnyWithProps,
|
|
220
316
|
const Scope extends IdScope.IdScope,
|
|
221
317
|
const Tables extends string,
|
|
@@ -223,7 +319,12 @@ export const contract = <
|
|
|
223
319
|
spec: Spec_,
|
|
224
320
|
scope: Scope,
|
|
225
321
|
tables: ReadonlyArray<Tables>,
|
|
226
|
-
): Component<Spec_, Scope, Tables
|
|
322
|
+
): Component<Spec_, Scope, Tables, {}>;
|
|
323
|
+
export function contract(
|
|
324
|
+
spec: Spec.AnyWithProps,
|
|
325
|
+
scope: IdScope.IdScope,
|
|
326
|
+
tables: ReadonlyArray<TableEntry>,
|
|
327
|
+
): Component<Spec.AnyWithProps, IdScope.IdScope> {
|
|
227
328
|
const specGroups = Spec.groups(spec);
|
|
228
329
|
Result.getOrThrow(validateContract(scope, specGroups));
|
|
229
330
|
const collect = (
|
|
@@ -251,10 +352,42 @@ export const contract = <
|
|
|
251
352
|
}),
|
|
252
353
|
Record.filter((children) => !Record.isEmptyRecord(children)),
|
|
253
354
|
);
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
355
|
+
const grouped: GroupMap = pipe(
|
|
356
|
+
tables,
|
|
357
|
+
Array.flatMap((entry) =>
|
|
358
|
+
typeof entry !== "string" && entry.group !== undefined
|
|
359
|
+
? [[entry.tableName, entry.group] as const]
|
|
360
|
+
: [],
|
|
361
|
+
),
|
|
362
|
+
Record.fromEntries,
|
|
363
|
+
);
|
|
364
|
+
const published: Component<
|
|
365
|
+
Spec.AnyWithProps,
|
|
366
|
+
IdScope.IdScope
|
|
367
|
+
>[typeof TypeId] = {
|
|
368
|
+
refs: collect(specGroups),
|
|
369
|
+
scope,
|
|
370
|
+
tables: Array.map(tables, (entry) =>
|
|
371
|
+
typeof entry === "string" ? entry : entry.tableName,
|
|
372
|
+
),
|
|
373
|
+
groups: grouped,
|
|
374
|
+
};
|
|
375
|
+
return { [TypeId]: published } as Component<
|
|
376
|
+
Spec.AnyWithProps,
|
|
377
|
+
IdScope.IdScope
|
|
378
|
+
>;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Each grouped table's id field and the table that id names.
|
|
383
|
+
*/
|
|
384
|
+
export const groups = <Groups_ extends GroupMap>(
|
|
385
|
+
component: Component<Spec.AnyWithProps, IdScope.IdScope, string, Groups_>,
|
|
386
|
+
): Groups_ =>
|
|
387
|
+
Record.map(component[TypeId].groups, ({ key, table }) => ({
|
|
388
|
+
key,
|
|
389
|
+
table,
|
|
390
|
+
})) as Groups_;
|
|
258
391
|
|
|
259
392
|
/**
|
|
260
393
|
* Bind the published contract to an actual installed component reference.
|
package/src/Table.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as GenericId from "./GenericId.js";
|
|
1
2
|
import * as IdScope from "./IdScope.js";
|
|
2
3
|
import * as Lazy from "./Lazy.js";
|
|
3
4
|
import * as SystemFields from "./SystemFields.js";
|
|
@@ -12,7 +13,13 @@ import type {
|
|
|
12
13
|
SearchIndexConfig,
|
|
13
14
|
VectorIndexConfig,
|
|
14
15
|
} from "convex/server";
|
|
15
|
-
import type {
|
|
16
|
+
import type {
|
|
17
|
+
GenericId as ConvexGenericId,
|
|
18
|
+
GenericValidator,
|
|
19
|
+
Validator,
|
|
20
|
+
} from "convex/values";
|
|
21
|
+
import * as Data from "effect/Data";
|
|
22
|
+
import * as Option from "effect/Option";
|
|
16
23
|
import * as Predicate from "effect/Predicate";
|
|
17
24
|
import type * as Schema from "effect/Schema";
|
|
18
25
|
|
|
@@ -36,6 +43,97 @@ export const isTable = (u: unknown): u is Any =>
|
|
|
36
43
|
export const isUnnamedTable = (u: unknown): u is UnnamedAny =>
|
|
37
44
|
Predicate.hasProperty(u, TypeId) && !Predicate.hasProperty(u, "tableName");
|
|
38
45
|
|
|
46
|
+
// -----------------------------------------------------------------------------
|
|
47
|
+
// Group
|
|
48
|
+
// -----------------------------------------------------------------------------
|
|
49
|
+
//
|
|
50
|
+
// A table is grouped by one of its required id fields, and the id's table owns
|
|
51
|
+
// its rows. `table` and `scope` come from the id's schema on first read, so
|
|
52
|
+
// binding a table never builds its `Fields`.
|
|
53
|
+
|
|
54
|
+
export interface Group<
|
|
55
|
+
Key extends string = string,
|
|
56
|
+
Table_ extends string = string,
|
|
57
|
+
Scope_ extends IdScope.IdScope = IdScope.IdScope,
|
|
58
|
+
> {
|
|
59
|
+
readonly key: Key;
|
|
60
|
+
readonly table: Table_;
|
|
61
|
+
readonly scope: Scope_;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export class GroupFieldError extends Data.TaggedError("GroupFieldError")<{
|
|
65
|
+
readonly tableName: string;
|
|
66
|
+
readonly key: string;
|
|
67
|
+
}> {
|
|
68
|
+
override get message(): string {
|
|
69
|
+
return `Table '${this.tableName}' cannot be grouped by '${this.key}': it is not a field holding an id.`;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
type FieldsOf<TableSchema_> = TableSchema_ extends {
|
|
74
|
+
readonly fields: infer StructFields extends Schema.Struct.Fields;
|
|
75
|
+
}
|
|
76
|
+
? StructFields
|
|
77
|
+
: never;
|
|
78
|
+
|
|
79
|
+
type GroupKeys<TableSchema_> = {
|
|
80
|
+
[
|
|
81
|
+
Key in keyof FieldsOf<TableSchema_> & string
|
|
82
|
+
]: FieldsOf<TableSchema_>[Key] extends {
|
|
83
|
+
readonly Type: ConvexGenericId<string>;
|
|
84
|
+
}
|
|
85
|
+
? [FieldsOf<TableSchema_>[Key]["~type.optionality"]] extends ["optional"]
|
|
86
|
+
? never
|
|
87
|
+
: Key
|
|
88
|
+
: never;
|
|
89
|
+
}[keyof FieldsOf<TableSchema_> & string];
|
|
90
|
+
|
|
91
|
+
type IdTableName<Id> = Id extends {
|
|
92
|
+
readonly "~@confect/core/ScopedId": {
|
|
93
|
+
readonly table: infer TableName extends string;
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
? TableName
|
|
97
|
+
: Id extends ConvexGenericId<infer TableName>
|
|
98
|
+
? TableName
|
|
99
|
+
: never;
|
|
100
|
+
|
|
101
|
+
type IdScopeOf<Id> = Id extends {
|
|
102
|
+
readonly "~@confect/core/ScopedId": {
|
|
103
|
+
readonly scope: infer Scope_ extends IdScope.IdScope;
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
? Scope_
|
|
107
|
+
: IdScope.App;
|
|
108
|
+
|
|
109
|
+
type GroupOf<TableSchema_, Key extends string> = Group<
|
|
110
|
+
Key,
|
|
111
|
+
IdTableName<
|
|
112
|
+
FieldsOf<TableSchema_>[Key & keyof FieldsOf<TableSchema_>]["Type"]
|
|
113
|
+
>,
|
|
114
|
+
IdScopeOf<FieldsOf<TableSchema_>[Key & keyof FieldsOf<TableSchema_>]["Type"]>
|
|
115
|
+
>;
|
|
116
|
+
|
|
117
|
+
const makeGroup = (
|
|
118
|
+
tableName: string,
|
|
119
|
+
key: string,
|
|
120
|
+
fields: () => Schema.Codec<any, any>,
|
|
121
|
+
): Group => {
|
|
122
|
+
const idField = () => {
|
|
123
|
+
const ast = (fields() as { readonly fields?: Schema.Struct.Fields })
|
|
124
|
+
.fields?.[key]?.ast;
|
|
125
|
+
const table =
|
|
126
|
+
ast === undefined ? Option.none() : GenericId.tableName<string>(ast);
|
|
127
|
+
if (ast === undefined || Option.isNone(table))
|
|
128
|
+
throw new GroupFieldError({ tableName, key });
|
|
129
|
+
return { table: table.value, scope: GenericId.scope(ast) };
|
|
130
|
+
};
|
|
131
|
+
const group = { key };
|
|
132
|
+
Lazy.defineProperty(group, "table", () => idField().table);
|
|
133
|
+
Lazy.defineProperty(group, "scope", () => idField().scope);
|
|
134
|
+
return group as Group;
|
|
135
|
+
};
|
|
136
|
+
|
|
39
137
|
// -----------------------------------------------------------------------------
|
|
40
138
|
// Bound Table
|
|
41
139
|
// -----------------------------------------------------------------------------
|
|
@@ -54,10 +152,12 @@ export interface Table<
|
|
|
54
152
|
SearchIndexes_ extends GenericTableSearchIndexes = {},
|
|
55
153
|
VectorIndexes_ extends GenericTableVectorIndexes = {},
|
|
56
154
|
Scope_ extends IdScope.IdScope = IdScope.App,
|
|
155
|
+
Group_ extends Group | undefined = undefined,
|
|
57
156
|
> {
|
|
58
157
|
readonly [TypeId]: TypeId;
|
|
59
158
|
readonly tableName: Name_;
|
|
60
159
|
readonly scope: Scope_;
|
|
160
|
+
readonly group: Group_;
|
|
61
161
|
readonly Fields: TableSchema_;
|
|
62
162
|
readonly Doc: SystemFields.ExtendWithSystemFields<
|
|
63
163
|
Name_,
|
|
@@ -82,7 +182,8 @@ export type AnyWithProps = Table<
|
|
|
82
182
|
GenericTableIndexes,
|
|
83
183
|
GenericTableSearchIndexes,
|
|
84
184
|
GenericTableVectorIndexes,
|
|
85
|
-
IdScope.IdScope
|
|
185
|
+
IdScope.IdScope,
|
|
186
|
+
Group | undefined
|
|
86
187
|
>;
|
|
87
188
|
|
|
88
189
|
// -----------------------------------------------------------------------------
|
|
@@ -105,6 +206,7 @@ export interface UnnamedTable<
|
|
|
105
206
|
Indexes_ extends GenericTableIndexes = {},
|
|
106
207
|
SearchIndexes_ extends GenericTableSearchIndexes = {},
|
|
107
208
|
VectorIndexes_ extends GenericTableVectorIndexes = {},
|
|
209
|
+
Group_ extends Group | undefined = undefined,
|
|
108
210
|
> {
|
|
109
211
|
<
|
|
110
212
|
const Name_ extends string,
|
|
@@ -119,7 +221,8 @@ export interface UnnamedTable<
|
|
|
119
221
|
Indexes_,
|
|
120
222
|
SearchIndexes_,
|
|
121
223
|
VectorIndexes_,
|
|
122
|
-
Scope_
|
|
224
|
+
Scope_,
|
|
225
|
+
Group_
|
|
123
226
|
>;
|
|
124
227
|
|
|
125
228
|
readonly [TypeId]: TypeId;
|
|
@@ -146,7 +249,8 @@ export interface UnnamedTable<
|
|
|
146
249
|
>
|
|
147
250
|
>,
|
|
148
251
|
SearchIndexes_,
|
|
149
|
-
VectorIndexes_
|
|
252
|
+
VectorIndexes_,
|
|
253
|
+
Group_
|
|
150
254
|
>;
|
|
151
255
|
|
|
152
256
|
searchIndex<
|
|
@@ -170,7 +274,8 @@ export interface UnnamedTable<
|
|
|
170
274
|
}
|
|
171
275
|
>
|
|
172
276
|
>,
|
|
173
|
-
VectorIndexes_
|
|
277
|
+
VectorIndexes_,
|
|
278
|
+
Group_
|
|
174
279
|
>;
|
|
175
280
|
|
|
176
281
|
vectorIndex<
|
|
@@ -195,7 +300,23 @@ export interface UnnamedTable<
|
|
|
195
300
|
filterFields: FilterFields;
|
|
196
301
|
}
|
|
197
302
|
>
|
|
198
|
-
|
|
303
|
+
>,
|
|
304
|
+
Group_
|
|
305
|
+
>;
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Name the required id field that groups this table's rows. The field's table
|
|
309
|
+
* is the one whose rows own these rows.
|
|
310
|
+
*/
|
|
311
|
+
group<const Key extends GroupKeys<TableSchema_>>(
|
|
312
|
+
key: Key,
|
|
313
|
+
): UnnamedTable<
|
|
314
|
+
TableSchema_,
|
|
315
|
+
TableValidator_,
|
|
316
|
+
Indexes_,
|
|
317
|
+
SearchIndexes_,
|
|
318
|
+
VectorIndexes_,
|
|
319
|
+
GroupOf<TableSchema_, Key>
|
|
199
320
|
>;
|
|
200
321
|
}
|
|
201
322
|
|
|
@@ -208,7 +329,8 @@ export type UnnamedAnyWithProps = UnnamedTable<
|
|
|
208
329
|
GenericValidator,
|
|
209
330
|
GenericTableIndexes,
|
|
210
331
|
GenericTableSearchIndexes,
|
|
211
|
-
GenericTableVectorIndexes
|
|
332
|
+
GenericTableVectorIndexes,
|
|
333
|
+
Group | undefined
|
|
212
334
|
>;
|
|
213
335
|
|
|
214
336
|
// -----------------------------------------------------------------------------
|
|
@@ -266,6 +388,7 @@ interface UnnamedState<
|
|
|
266
388
|
VectorIndexes_ extends GenericTableVectorIndexes,
|
|
267
389
|
> {
|
|
268
390
|
readonly lazyFields: () => TableSchema_;
|
|
391
|
+
readonly groupKey: string | undefined;
|
|
269
392
|
readonly indexes: Indexes_;
|
|
270
393
|
readonly searchIndexes: SearchIndexes_;
|
|
271
394
|
readonly vectorIndexes: VectorIndexes_;
|
|
@@ -279,6 +402,7 @@ const makeBound = <
|
|
|
279
402
|
SearchIndexes_ extends GenericTableSearchIndexes,
|
|
280
403
|
VectorIndexes_ extends GenericTableVectorIndexes,
|
|
281
404
|
Scope_ extends IdScope.IdScope,
|
|
405
|
+
Group_ extends Group | undefined,
|
|
282
406
|
>(
|
|
283
407
|
tableName: Name_,
|
|
284
408
|
state: UnnamedState<TableSchema_, Indexes_, SearchIndexes_, VectorIndexes_>,
|
|
@@ -290,12 +414,17 @@ const makeBound = <
|
|
|
290
414
|
Indexes_,
|
|
291
415
|
SearchIndexes_,
|
|
292
416
|
VectorIndexes_,
|
|
293
|
-
Scope_
|
|
417
|
+
Scope_,
|
|
418
|
+
Group_
|
|
294
419
|
> => {
|
|
295
420
|
const bound = {
|
|
296
421
|
[TypeId]: TypeId as TypeId,
|
|
297
422
|
tableName,
|
|
298
423
|
scope,
|
|
424
|
+
group:
|
|
425
|
+
state.groupKey === undefined
|
|
426
|
+
? undefined
|
|
427
|
+
: makeGroup(tableName, state.groupKey, () => bound.Fields),
|
|
299
428
|
indexes: state.indexes,
|
|
300
429
|
searchIndexes: state.searchIndexes,
|
|
301
430
|
vectorIndexes: state.vectorIndexes,
|
|
@@ -306,7 +435,8 @@ const makeBound = <
|
|
|
306
435
|
Indexes_,
|
|
307
436
|
SearchIndexes_,
|
|
308
437
|
VectorIndexes_,
|
|
309
|
-
Scope_
|
|
438
|
+
Scope_,
|
|
439
|
+
Group_
|
|
310
440
|
>;
|
|
311
441
|
|
|
312
442
|
Lazy.defineProperty(bound, "Fields", () => state.lazyFields());
|
|
@@ -328,6 +458,7 @@ const makeUnnamed = <
|
|
|
328
458
|
Indexes_ extends GenericTableIndexes,
|
|
329
459
|
SearchIndexes_ extends GenericTableSearchIndexes,
|
|
330
460
|
VectorIndexes_ extends GenericTableVectorIndexes,
|
|
461
|
+
Group_ extends Group | undefined,
|
|
331
462
|
>(
|
|
332
463
|
state: UnnamedState<TableSchema_, Indexes_, SearchIndexes_, VectorIndexes_>,
|
|
333
464
|
): UnnamedTable<
|
|
@@ -335,14 +466,16 @@ const makeUnnamed = <
|
|
|
335
466
|
TableValidator_,
|
|
336
467
|
Indexes_,
|
|
337
468
|
SearchIndexes_,
|
|
338
|
-
VectorIndexes_
|
|
469
|
+
VectorIndexes_,
|
|
470
|
+
Group_
|
|
339
471
|
> => {
|
|
340
472
|
type UnnamedTable_ = UnnamedTable<
|
|
341
473
|
TableSchema_,
|
|
342
474
|
TableValidator_,
|
|
343
475
|
Indexes_,
|
|
344
476
|
SearchIndexes_,
|
|
345
|
-
VectorIndexes_
|
|
477
|
+
VectorIndexes_,
|
|
478
|
+
Group_
|
|
346
479
|
>;
|
|
347
480
|
|
|
348
481
|
type UnnamedTableFunction<FunctionName extends keyof UnnamedTable_> =
|
|
@@ -361,7 +494,8 @@ const makeUnnamed = <
|
|
|
361
494
|
Indexes_,
|
|
362
495
|
SearchIndexes_,
|
|
363
496
|
VectorIndexes_,
|
|
364
|
-
Scope_
|
|
497
|
+
Scope_,
|
|
498
|
+
Group_
|
|
365
499
|
> =>
|
|
366
500
|
makeBound<
|
|
367
501
|
Name_,
|
|
@@ -370,18 +504,17 @@ const makeUnnamed = <
|
|
|
370
504
|
Indexes_,
|
|
371
505
|
SearchIndexes_,
|
|
372
506
|
VectorIndexes_,
|
|
373
|
-
Scope_
|
|
507
|
+
Scope_,
|
|
508
|
+
Group_
|
|
374
509
|
>(tableName, state, (scope ?? IdScope.app) as Scope_);
|
|
375
510
|
|
|
376
511
|
const index: UnnamedTableFunction<"index"> = (name, fields) =>
|
|
377
512
|
makeUnnamed({
|
|
378
|
-
|
|
513
|
+
...state,
|
|
379
514
|
indexes: {
|
|
380
515
|
...state.indexes,
|
|
381
516
|
[name]: fields,
|
|
382
517
|
} as any,
|
|
383
|
-
searchIndexes: state.searchIndexes,
|
|
384
|
-
vectorIndexes: state.vectorIndexes,
|
|
385
518
|
});
|
|
386
519
|
|
|
387
520
|
const searchIndex: UnnamedTableFunction<"searchIndex"> = (
|
|
@@ -389,13 +522,11 @@ const makeUnnamed = <
|
|
|
389
522
|
indexConfig,
|
|
390
523
|
) =>
|
|
391
524
|
makeUnnamed({
|
|
392
|
-
|
|
393
|
-
indexes: state.indexes,
|
|
525
|
+
...state,
|
|
394
526
|
searchIndexes: {
|
|
395
527
|
...state.searchIndexes,
|
|
396
528
|
[name]: indexConfig,
|
|
397
529
|
} as any,
|
|
398
|
-
vectorIndexes: state.vectorIndexes,
|
|
399
530
|
});
|
|
400
531
|
|
|
401
532
|
const vectorIndex: UnnamedTableFunction<"vectorIndex"> = (
|
|
@@ -403,15 +534,16 @@ const makeUnnamed = <
|
|
|
403
534
|
indexConfig,
|
|
404
535
|
) =>
|
|
405
536
|
makeUnnamed({
|
|
406
|
-
|
|
407
|
-
indexes: state.indexes,
|
|
408
|
-
searchIndexes: state.searchIndexes,
|
|
537
|
+
...state,
|
|
409
538
|
vectorIndexes: {
|
|
410
539
|
...state.vectorIndexes,
|
|
411
540
|
[name]: indexConfig,
|
|
412
541
|
} as any,
|
|
413
542
|
});
|
|
414
543
|
|
|
544
|
+
const group: UnnamedTableFunction<"group"> = (key) =>
|
|
545
|
+
makeUnnamed({ ...state, groupKey: key });
|
|
546
|
+
|
|
415
547
|
return Object.assign(bind, {
|
|
416
548
|
[TypeId]: TypeId as TypeId,
|
|
417
549
|
indexes: state.indexes,
|
|
@@ -420,6 +552,7 @@ const makeUnnamed = <
|
|
|
420
552
|
index,
|
|
421
553
|
searchIndex,
|
|
422
554
|
vectorIndex,
|
|
555
|
+
group,
|
|
423
556
|
}) as UnnamedTable_;
|
|
424
557
|
};
|
|
425
558
|
|
|
@@ -429,8 +562,9 @@ export const make = <const TableSchema_ extends Schema.Codec<any, any>>(
|
|
|
429
562
|
type TableValidator_ = TableSchemaToTableValidator<TableSchema_>;
|
|
430
563
|
type UnnamedTable_ = UnnamedTable<TableSchema_, TableValidator_>;
|
|
431
564
|
|
|
432
|
-
return makeUnnamed<TableSchema_, TableValidator_, {}, {}, {}>({
|
|
565
|
+
return makeUnnamed<TableSchema_, TableValidator_, {}, {}, {}, undefined>({
|
|
433
566
|
lazyFields,
|
|
567
|
+
groupKey: undefined,
|
|
434
568
|
indexes: {},
|
|
435
569
|
searchIndexes: {},
|
|
436
570
|
vectorIndexes: {},
|