content-query 0.4.0 → 0.5.1
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/README.md +49 -27
- package/dist/{build-DL1GzmRy.d.mts → build-Aoi7Unm0.d.mts} +10 -5
- package/dist/{build-CcqIpkes.mjs → build-CIw4yWs9.mjs} +139 -51
- package/dist/build.d.mts +1 -1
- package/dist/build.mjs +1 -1
- package/dist/cli.mjs +2 -2
- package/dist/{content-BXrgP7nL.mjs → collection-Cb5eWGnv.mjs} +871 -407
- package/dist/collection-types-DhIxnCSM.d.mts +119 -0
- package/dist/computed.d.mts +1 -1
- package/dist/index.d.mts +18 -3
- package/dist/internal.d.mts +48 -8
- package/dist/internal.mjs +398 -17
- package/dist/next.d.mts +3 -2
- package/dist/next.mjs +66 -13
- package/dist/{operators-Cwy8Kx4o.mjs → operators-D-w1-gDg.mjs} +134 -2
- package/dist/query-style-C2FcT1f9.d.mts +23 -0
- package/dist/query.d.mts +2 -2
- package/dist/query.mjs +1 -1
- package/dist/{relational-types-C8xJtLG5.d.mts → relational-types-PtrzENt0.d.mts} +141 -23
- package/dist/revision-aqGUf6YV.d.mts +56 -0
- package/dist/runtime.d.mts +3 -3
- package/dist/{types-DbFfF6JE.d.mts → types-WOsFmNnN.d.mts} +52 -2
- package/dist/vite.d.mts +1 -1
- package/dist/vite.mjs +76 -34
- package/package.json +1 -1
- package/dist/content-CwTKqRs9.d.mts +0 -134
- package/dist/query-style-eXENQJ0O.d.mts +0 -22
|
@@ -1,5 +1,134 @@
|
|
|
1
1
|
import { a as invalidQuery } from "./errors-Bfd0R4_P.mjs";
|
|
2
2
|
import { c as isScalar, i as detach } from "./values-BbTV4QT-.mjs";
|
|
3
|
+
//#region src/collection/names.ts
|
|
4
|
+
/** Words that cannot name a `const` binding in an ES module, or that read as module syntax. */
|
|
5
|
+
const reservedWords = new Set("arguments await break case catch class const continue debugger default delete do else enum eval export extends false finally for function if implements import in instanceof interface let new null package private protected public return static super switch this throw true try typeof var void while with yield".split(" "));
|
|
6
|
+
/** Names Windows reserves for devices, in any letter case, which cannot name a directory. */
|
|
7
|
+
const deviceName = /^(?:con|prn|aux|nul|com[0-9]|lpt[0-9])$/i;
|
|
8
|
+
const identifier = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
9
|
+
/** Uppercases the first character, keeping the rest of a camelCase name. */
|
|
10
|
+
function capitalize(value) {
|
|
11
|
+
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Converts a collection name into the identifier its entry exports and its import path uses.
|
|
15
|
+
* Characters that cannot appear in an identifier separate camelCase words, a leading digit gets
|
|
16
|
+
* an `_` prefix, and reserved words and Windows device names get a `Collection` suffix.
|
|
17
|
+
*
|
|
18
|
+
* @param name - The collection's key in the `collections` registry.
|
|
19
|
+
* @returns The export name, such as `blogPosts` for `blog-posts`.
|
|
20
|
+
*/
|
|
21
|
+
function exportNameOf(name) {
|
|
22
|
+
let converted = name.split(/[^A-Za-z0-9_$]+/).filter(Boolean).map((word, index) => index === 0 ? word : capitalize(word)).join("");
|
|
23
|
+
if (!converted) converted = "collection";
|
|
24
|
+
else if (/^[0-9]/.test(converted)) converted = `_${converted}`;
|
|
25
|
+
return reservedWords.has(converted) || deviceName.test(converted) ? `${converted}Collection` : converted;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Derives the singular word for generated type names by dropping one trailing `s`. Names ending
|
|
29
|
+
* in `ss`, such as `address`, keep it. Irregular plurals use the collection's `typeName`.
|
|
30
|
+
*
|
|
31
|
+
* @param exportName - The collection's export name.
|
|
32
|
+
* @returns The singular form, such as `blogPost` for `blogPosts`.
|
|
33
|
+
*/
|
|
34
|
+
function singularOf(exportName) {
|
|
35
|
+
return exportName.length > 1 && exportName.endsWith("s") && !exportName.endsWith("ss") ? exportName.slice(0, -1) : exportName;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Computes every collection's generated names and rejects names that would collide.
|
|
39
|
+
*
|
|
40
|
+
* @param registry - Collection keys with each collection's optional `typeName` override.
|
|
41
|
+
* @returns The names of each collection's entry, keyed by collection name.
|
|
42
|
+
* @throws An `Error` naming the conflict when two collections share an export or type name, or
|
|
43
|
+
* when a `typeName` is not an identifier.
|
|
44
|
+
*/
|
|
45
|
+
function collectionNames(registry) {
|
|
46
|
+
const names = /* @__PURE__ */ new Map();
|
|
47
|
+
const exports = /* @__PURE__ */ new Map();
|
|
48
|
+
const types = /* @__PURE__ */ new Map();
|
|
49
|
+
for (const [name, definition] of Object.entries(registry)) {
|
|
50
|
+
const declared = definition?.typeName;
|
|
51
|
+
if (declared !== void 0 && (typeof declared !== "string" || !identifier.test(declared))) throw new Error(`Collection "${name}" typeName must be an identifier such as "Category"; received ${JSON.stringify(declared)}.`);
|
|
52
|
+
const exportName = exportNameOf(name);
|
|
53
|
+
const typeName = `Content${capitalize(declared ?? singularOf(exportName))}`;
|
|
54
|
+
const exported = exports.get(exportName.toLowerCase());
|
|
55
|
+
if (exported !== void 0) throw new Error(`Collections "${exported}" and "${name}" both export "${exportName}" (ignoring letter case), which their #content-query entries cannot share. Rename one of them.`);
|
|
56
|
+
const payloadTypeName = `${typeName}Payload`;
|
|
57
|
+
for (const generated of [typeName, payloadTypeName]) {
|
|
58
|
+
const typed = types.get(generated);
|
|
59
|
+
if (typed !== void 0) throw new Error(`Collections "${typed}" and "${name}" both generate the type "${generated}". Set typeName on one of them.`);
|
|
60
|
+
types.set(generated, name);
|
|
61
|
+
}
|
|
62
|
+
exports.set(exportName.toLowerCase(), name);
|
|
63
|
+
names.set(name, {
|
|
64
|
+
exportName,
|
|
65
|
+
typeName,
|
|
66
|
+
payloadTypeName
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return names;
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
//#region src/query/plan.ts
|
|
73
|
+
/**
|
|
74
|
+
* Rejects a declared relationship whose target collection this query scope has not loaded,
|
|
75
|
+
* naming the collection to pass to `using()`.
|
|
76
|
+
*
|
|
77
|
+
* @param registry - The query scope's registry.
|
|
78
|
+
* @param collection - The collection that declares the relationship.
|
|
79
|
+
* @param name - The relationship, field, or filter name a query used.
|
|
80
|
+
*/
|
|
81
|
+
function assertAvailable(registry, collection, name) {
|
|
82
|
+
const unavailable = registry[collection]?.unavailable;
|
|
83
|
+
if (!unavailable || !Object.hasOwn(unavailable, name)) return;
|
|
84
|
+
const target = exportNameOf(unavailable[name]);
|
|
85
|
+
invalidQuery(`Relationship "${name}" targets the ${target} collection, which this query has not loaded. Pass it to using(), such as ${exportNameOf(collection)}.using(${target}).`);
|
|
86
|
+
}
|
|
87
|
+
/** Starts a fresh query without binding a content revision until execution. */
|
|
88
|
+
function emptyPlan(collection) {
|
|
89
|
+
return {
|
|
90
|
+
collection,
|
|
91
|
+
filters: [],
|
|
92
|
+
order: [],
|
|
93
|
+
with: {}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/** Explains the explicit-selection rule wherever a scope returns rows without selecting data. */
|
|
97
|
+
const NO_SELECTION_MESSAGE = "Select fields, relationships, payloads, or adjacent entries before running this query.";
|
|
98
|
+
/** Explains why `paginate()` is unavailable once a query sets its own limit or offset. */
|
|
99
|
+
const PAGINATE_AFTER_LIMIT_MESSAGE = "paginate() sets the limit and offset itself; remove limit and offset from this query.";
|
|
100
|
+
/**
|
|
101
|
+
* Returns the order a scope's entries follow: explicit clauses, then ascending ID as the final
|
|
102
|
+
* tie-breaker unless ID is already sorted. Scopes without clauses sort by ascending ID, except
|
|
103
|
+
* relationship scopes that preserve an authored ID array's order.
|
|
104
|
+
*
|
|
105
|
+
* @param plan - The scope whose order to resolve.
|
|
106
|
+
* @param preserveOrder - Keeps authored order when the scope has no explicit clauses.
|
|
107
|
+
* @returns The sort clauses to apply, in priority order.
|
|
108
|
+
*/
|
|
109
|
+
function effectiveOrder(plan, preserveOrder = false) {
|
|
110
|
+
if (!plan.order.length) return preserveOrder ? [] : [{
|
|
111
|
+
field: "id",
|
|
112
|
+
direction: "asc"
|
|
113
|
+
}];
|
|
114
|
+
const order = [...plan.order];
|
|
115
|
+
if (!order.some((sort) => sort.field === "id")) order.push({
|
|
116
|
+
field: "id",
|
|
117
|
+
direction: "asc"
|
|
118
|
+
});
|
|
119
|
+
return order;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Checks whether a row-returning scope explicitly requests data. Nothing is implicit, not even
|
|
123
|
+
* `id`: a scope must select fields, include a relationship, request a payload, or select adjacency.
|
|
124
|
+
*
|
|
125
|
+
* @param plan - The scope to check; `undefined` when a callback returned no builder.
|
|
126
|
+
* @returns `true` when the scope requests at least one kind of data.
|
|
127
|
+
*/
|
|
128
|
+
function hasSelection(plan) {
|
|
129
|
+
return !!plan && (!!plan.select?.length || !!plan.adjacent || Object.keys(plan.with).length > 0 || Object.keys(plan.payloads ?? {}).length > 0);
|
|
130
|
+
}
|
|
131
|
+
//#endregion
|
|
3
132
|
//#region src/query/operators.ts
|
|
4
133
|
/** Builds a checked, backend-independent predicate instead of a per-entry callback. */
|
|
5
134
|
function predicate(operator, field, value) {
|
|
@@ -139,7 +268,10 @@ function resolveRelations(registry, collection, expression) {
|
|
|
139
268
|
case "has": {
|
|
140
269
|
const relationships = registry[collection]?.relationships ?? {};
|
|
141
270
|
const relation = Object.hasOwn(relationships, expression.field) ? relationships[expression.field] : void 0;
|
|
142
|
-
if (!relation)
|
|
271
|
+
if (!relation) {
|
|
272
|
+
assertAvailable(registry, collection, expression.field);
|
|
273
|
+
invalidQuery(`Unknown relationship "${expression.field}" in has().`);
|
|
274
|
+
}
|
|
143
275
|
return {
|
|
144
276
|
kind: "relation",
|
|
145
277
|
collection,
|
|
@@ -256,4 +388,4 @@ function validateExpression(expression) {
|
|
|
256
388
|
} else invalidQuery("Invalid expression structure.");
|
|
257
389
|
}
|
|
258
390
|
//#endregion
|
|
259
|
-
export { notIlike as C, resolveRelations as D, or as E, startsWith as O, not as S, notLike as T, isUndefined as _, arrayContainsAny as a, lte as b, eq as c, gte as d, has as f, isNull as g, isMissing as h, arrayContainsAll as i, validateExpression as k, fieldProxy as l, inArray as m, arrayContained as n, contains as o, ilike as p, arrayContains as r, endsWith as s, and as t, gt as u, like as v, notInArray as w, ne as x, lt as y };
|
|
391
|
+
export { NO_SELECTION_MESSAGE as A, notIlike as C, resolveRelations as D, or as E, hasSelection as F, collectionNames as I, assertAvailable as M, effectiveOrder as N, startsWith as O, emptyPlan as P, not as S, notLike as T, isUndefined as _, arrayContainsAny as a, lte as b, eq as c, gte as d, has as f, isNull as g, isMissing as h, arrayContainsAll as i, PAGINATE_AFTER_LIMIT_MESSAGE as j, validateExpression as k, fieldProxy as l, inArray as m, arrayContained as n, contains as o, ilike as p, arrayContains as r, endsWith as s, and as t, gt as u, like as v, notInArray as w, ne as x, lt as y };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/runtime/query-style.d.ts
|
|
2
|
+
/** Query APIs an application can allow through `queryStyle` in content-query.config. */
|
|
3
|
+
type QueryStyle = "fluent" | "relational";
|
|
4
|
+
/**
|
|
5
|
+
* Collection members that start each query style. Every other query API hangs off these members,
|
|
6
|
+
* so gating them gates payloads, relationships, and adjacency as well. `count()` without options
|
|
7
|
+
* belongs to both styles; `count(options)` takes relational options.
|
|
8
|
+
*/
|
|
9
|
+
declare const queryStyleMembers: {
|
|
10
|
+
readonly fluent: readonly ["select", "where", "orderBy", "limit", "offset", "with", "withPayload", "selectAdjacent"];
|
|
11
|
+
readonly relational: readonly ["findMany", "findFirst", "paginate", "count(options)"];
|
|
12
|
+
};
|
|
13
|
+
/** A collection member that belongs to exactly one query style. */
|
|
14
|
+
type QueryStyleMember = (typeof queryStyleMembers)[QueryStyle][number];
|
|
15
|
+
/** Collection members that start a query in the given style. */
|
|
16
|
+
type MembersOf<Style extends QueryStyle> = (typeof queryStyleMembers)[Style][number];
|
|
17
|
+
/**
|
|
18
|
+
* Describes a disabled collection member in the type error itself, for example:
|
|
19
|
+
* `posts.select is unavailable because content-query.config sets queryStyle to "relational".`
|
|
20
|
+
*/
|
|
21
|
+
type QueryStyleDisabled<Collection extends string, Member extends QueryStyleMember, Style extends QueryStyle> = `${Collection}.${Member} is unavailable because content-query.config sets queryStyle to "${Style}".`;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { QueryStyleMember as i, QueryStyle as n, QueryStyleDisabled as r, MembersOf as t };
|
package/dist/query.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as Selection, E as Expression, S as ScalarField, T as Where, _ as PaginateResult, a as RelationalQueryOptions, b as RelationField, c as Adjacent, d as Field, f as Fields, g as PaginateOptions, h as PageOptions, i as RelationalQueries, l as CursorOptions, m as Ordered, n as RelationalCountOptions, o as RelationalQueryResult, p as NumberedPage, r as RelationalPaginateOptions, s as RelationalWhere, u as CursorPage, w as SelectionResult, x as Scalar, y as QueryFields } from "./relational-types-PtrzENt0.mjs";
|
|
2
2
|
//#region src/query/operators.d.ts
|
|
3
3
|
/** Matches a scalar using strict value/date equality. */
|
|
4
4
|
export declare function eq<Value>(field: ScalarField<Value>, value: NoInfer<Value>): Expression;
|
|
@@ -64,4 +64,4 @@ export declare function or(...expressions: Expression[]): Expression;
|
|
|
64
64
|
/** Negates a predicate's boolean result. */
|
|
65
65
|
export declare function not(expression: Expression): Expression;
|
|
66
66
|
//#endregion
|
|
67
|
-
export type { Adjacent, RelationalCountOptions as CountOptions, Expression, Field, Fields, QueryFields, RelationalQueryOptions as QueryOptions, RelationalQueryOptions, RelationField, RelationalQueries, RelationalQueryResult, RelationalWhere, Selection, SelectionResult, Where };
|
|
67
|
+
export type { Adjacent, RelationalCountOptions as CountOptions, CursorOptions, CursorPage, Expression, Field, Fields, NumberedPage, PageOptions, PaginateOptions, PaginateResult, QueryFields, RelationalQueryOptions as QueryOptions, RelationalQueryOptions, RelationField, RelationalPaginateOptions, RelationalQueries, RelationalQueryResult, RelationalWhere, Selection, SelectionResult, Where };
|
package/dist/query.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as and, n as arrayContained, r as arrayContains, i as arrayContainsAll, a as arrayContainsAny, o as contains, s as endsWith, c as eq, u as gt, d as gte, f as has, p as ilike, m as inArray, h as isMissing, g as isNull, _ as isUndefined, v as like, y as lt, b as lte, x as ne, S as not, C as notIlike, w as notInArray, T as notLike, E as or, O as startsWith } from "./operators-
|
|
1
|
+
export { t as and, n as arrayContained, r as arrayContains, i as arrayContainsAll, a as arrayContainsAny, o as contains, s as endsWith, c as eq, u as gt, d as gte, f as has, p as ilike, m as inArray, h as isMissing, g as isNull, _ as isUndefined, v as like, y as lt, b as lte, x as ne, S as not, C as notIlike, w as notInArray, T as notLike, E as or, O as startsWith } from "./operators-D-w1-gDg.mjs";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as UnavailableRelationshipsOf, E as VariantOf, S as UnavailableRelationship, _ as Relationship, g as QueryData, h as PayloadsOf, i as CollectionRegistry, v as RelationshipsOf, x as SelectedData } from "./types-WOsFmNnN.mjs";
|
|
2
2
|
//#region src/query/plan.d.ts
|
|
3
3
|
type PredicateOperator = "eq" | "ne" | "gt" | "gte" | "lt" | "lte" | "in-array" | "not-in-array" | "contains" | "starts-with" | "ends-with" | "like" | "ilike" | "array-contains" | "array-contains-any" | "array-contains-all" | "array-contained" | "is-null" | "is-undefined" | "is-missing";
|
|
4
4
|
type Expression = {
|
|
@@ -37,6 +37,26 @@ type QueryPlan = {
|
|
|
37
37
|
adjacent?: AdjacentPlan;
|
|
38
38
|
/** Payloads to attach under `_payloads` after filtering, ordering, and pagination. */
|
|
39
39
|
payloads?: Readonly<Record<string, PlanPayload>>;
|
|
40
|
+
/** A root `paginate()` request; plans that carry it never set `limit` or `offset`. */
|
|
41
|
+
paginate?: PaginatePlan;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* A page-number or cursor page request. Cursor keys are already decoded into the sort values of the
|
|
45
|
+
* boundary entry, in effective-order position, so backends never parse cursor strings.
|
|
46
|
+
*/
|
|
47
|
+
type PaginatePlan = {
|
|
48
|
+
mode: "page";
|
|
49
|
+
page: number;
|
|
50
|
+
size: number;
|
|
51
|
+
} | {
|
|
52
|
+
mode: "cursor";
|
|
53
|
+
size: number;
|
|
54
|
+
/** `after` pages forward from `key`; `before` pages backward to it. */
|
|
55
|
+
direction: "after" | "before";
|
|
56
|
+
/** Sort values of the boundary entry; omitted to start at the first or last entry. */
|
|
57
|
+
key?: readonly unknown[];
|
|
58
|
+
/** Whether the result includes the filtered total. */
|
|
59
|
+
total: boolean;
|
|
40
60
|
};
|
|
41
61
|
/**
|
|
42
62
|
* Selects previous and next entries. `results` finds neighbors within the scope's own filtered and
|
|
@@ -51,6 +71,8 @@ type AdjacentPlan = {
|
|
|
51
71
|
type PlanPayload = {
|
|
52
72
|
variant: Readonly<Record<string, string>>;
|
|
53
73
|
};
|
|
74
|
+
/** How a plan returns its results; `paginate` requires the plan's `paginate` request. */
|
|
75
|
+
type QueryTerminal = "all" | "first" | "count" | "paginate";
|
|
54
76
|
/** Describes a payload that queries may request, without its resolver or schema. */
|
|
55
77
|
type PayloadDescriptor = {
|
|
56
78
|
variants: readonly string[];
|
|
@@ -59,9 +81,18 @@ type QueryRegistry = Record<string, {
|
|
|
59
81
|
relationships: Record<string, Relationship>;
|
|
60
82
|
/** Payload names available to queries; omitted when the collection has none. */
|
|
61
83
|
payloads?: Record<string, PayloadDescriptor>;
|
|
84
|
+
/**
|
|
85
|
+
* Declared relationships whose target collection this query scope has not loaded, by name, with
|
|
86
|
+
* the target collection. Queries that use one report which collection to pass to `using()`.
|
|
87
|
+
*/
|
|
88
|
+
unavailable?: Record<string, string>;
|
|
89
|
+
/** The declared `typeName`, which only generated declarations read. */
|
|
90
|
+
typeName?: string;
|
|
62
91
|
}>;
|
|
63
92
|
/** Explains the explicit-selection rule wherever a scope returns rows without selecting data. */
|
|
64
93
|
declare const NO_SELECTION_MESSAGE: "Select fields, relationships, payloads, or adjacent entries before running this query.";
|
|
94
|
+
/** Explains why `paginate()` is unavailable once a query sets its own limit or offset. */
|
|
95
|
+
declare const PAGINATE_AFTER_LIMIT_MESSAGE: "paginate() sets the limit and offset itself; remove limit and offset from this query.";
|
|
65
96
|
//#endregion
|
|
66
97
|
//#region src/query/types.d.ts
|
|
67
98
|
declare const queryType: unique symbol;
|
|
@@ -82,7 +113,9 @@ type RelationField<TargetFields> = {
|
|
|
82
113
|
readonly [relationTarget]: TargetFields;
|
|
83
114
|
};
|
|
84
115
|
/** Fields and relationships available to a fluent `where()` callback. */
|
|
85
|
-
type QueryFields<Registry extends CollectionRegistry, Name extends keyof Registry & string> = Fields<QueryData<Registry[Name]>> & { readonly [Key in keyof RelationshipsOf<Registry[Name]> & string]-?: RelationField<QueryFields<Registry, RelatedName$1<Registry, RelationOf<Registry, Name, Key>>>>; }
|
|
116
|
+
type QueryFields<Registry extends CollectionRegistry, Name extends keyof Registry & string> = Fields<QueryData<Registry[Name]>> & { readonly [Key in keyof RelationshipsOf<Registry[Name]> & string]-?: RelationField<QueryFields<Registry, RelatedName$1<Registry, RelationOf<Registry, Name, Key>>>>; } & { readonly [
|
|
117
|
+
/** A relationship into a collection the query has not loaded reads as the type error. */
|
|
118
|
+
Key in keyof UnavailableRelationshipsOf<Registry[Name]> & string]-?: UnavailableRelationship<Registry[Name], Key>; };
|
|
86
119
|
type Scalar = string | number | bigint | boolean | Date | null | undefined;
|
|
87
120
|
type ScalarField<Value> = Field$1<Value> & ([Value] extends [Scalar] ? unknown : never);
|
|
88
121
|
type Ordered<Value> = NonNullable<Value> extends string ? unknown : NonNullable<Value> extends number ? unknown : NonNullable<Value> extends bigint ? unknown : NonNullable<Value> extends Date ? unknown : never;
|
|
@@ -108,28 +141,30 @@ type RelatedName$1<Registry extends CollectionRegistry, Relation extends Relatio
|
|
|
108
141
|
/** Applies declared relationship cardinality, optional reference fields, and filtering to a result. */
|
|
109
142
|
type RelationshipResult<Definition, Relation extends Relationship, Result, Filtered extends boolean = false> = Relation["type"] extends "many" ? Result[] : Result | (Filtered extends true ? null : Relation["referenceSide"] extends "from" ? Relation["from"] extends keyof QueryData<Definition> ? null extends QueryData<Definition>[Relation["from"]] ? null : undefined extends QueryData<Definition>[Relation["from"]] ? null : never : null : null);
|
|
110
143
|
type RelationValue<Definition, Relation extends Relationship, Configured> = RelationshipResult<Definition, Relation, ResultOf<Configured>, FilteredOf<Configured>>;
|
|
111
|
-
type Query<Registry extends CollectionRegistry, Name extends keyof Registry & string, Result = {}, Selected extends boolean = false, Many extends boolean = true, Root extends boolean = true, Filtered extends boolean = false, AllowAdjacent extends boolean = true, Pagination extends boolean = true> = QueryInfo<Result, Selected, Filtered> & {
|
|
112
|
-
select<const Keys extends readonly [keyof QueryData<Registry[Name]> & string, ...(keyof QueryData<Registry[Name]> & string)[]]>(...keys: Keys): Query<Registry, Name, { [Key in Exclude<keyof Result, keyof QueryData<Registry[Name]>>
|
|
113
|
-
where(configure: (fields: QueryFields<Registry, Name>) => Expression): Query<Registry, Name, Result, Selected, Many, Root, true, AllowAdjacent, Pagination>;
|
|
114
|
-
with<Key extends keyof RelationshipsOf<Registry[Name]> & string, Configured extends QueryInfo<unknown, true>>(name: Key, configure: (query: Query<Registry, RelatedName$1<Registry, RelationOf<Registry, Name, Key>>, {}, false, RelationOf<Registry, Name, Key>["type"] extends "many" ? true : false, false, false, AllowAdjacent>) => Configured): Query<Registry, Name, Result & { [Property in Key]: RelationValue<Registry[Name], RelationOf<Registry, Name, Key>, Configured>; }, true, Many, Root, Filtered, AllowAdjacent, Pagination>;
|
|
144
|
+
type Query<Registry extends CollectionRegistry, Name extends keyof Registry & string, Result = {}, Selected extends boolean = false, Many extends boolean = true, Root extends boolean = true, Filtered extends boolean = false, AllowAdjacent extends boolean = true, Pagination extends boolean = true, Paged extends boolean = false> = QueryInfo<Result, Selected, Filtered> & {
|
|
145
|
+
select<const Keys extends readonly [keyof QueryData<Registry[Name]> & string, ...(keyof QueryData<Registry[Name]> & string)[]]>(...keys: Keys): Query<Registry, Name, Simplify$1<{ [Key in Exclude<keyof Result, keyof QueryData<Registry[Name]>>]: Result[Key]; } & SelectedData<QueryData<Registry[Name]>, Keys[number]>>, true, Many, Root, Filtered, AllowAdjacent, Pagination, Paged>;
|
|
146
|
+
where(configure: (fields: QueryFields<Registry, Name>) => Expression): Query<Registry, Name, Result, Selected, Many, Root, true, AllowAdjacent, Pagination, Paged>;
|
|
147
|
+
with<Key extends keyof RelationshipsOf<Registry[Name]> & string, Configured extends QueryInfo<unknown, true>>(name: Key, configure: (query: Query<Registry, RelatedName$1<Registry, RelationOf<Registry, Name, Key>>, {}, false, RelationOf<Registry, Name, Key>["type"] extends "many" ? true : false, false, false, AllowAdjacent>) => Configured): Query<Registry, Name, Result & { [Property in Key]: RelationValue<Registry[Name], RelationOf<Registry, Name, Key>, Configured>; }, true, Many, Root, Filtered, AllowAdjacent, Pagination, Paged>;
|
|
148
|
+
/** A relationship into a collection the query has not loaded reports which one to supply. */
|
|
149
|
+
with<Key extends keyof UnavailableRelationshipsOf<Registry[Name]> & string>(name: Key, configure: UnavailableRelationship<Registry[Name], Key>): never;
|
|
115
150
|
} & (Many extends true ? {
|
|
116
|
-
orderBy(field: SortKey<QueryData<Registry[Name]>>, direction?: "asc" | "desc"): Query<Registry, Name, Result, Selected, Many, Root, Filtered, AllowAdjacent, Pagination>;
|
|
151
|
+
orderBy(field: SortKey<QueryData<Registry[Name]>>, direction?: "asc" | "desc"): Query<Registry, Name, Result, Selected, Many, Root, Filtered, AllowAdjacent, Pagination, Paged>;
|
|
117
152
|
} : {}) & (Many extends true ? Pagination extends true ? {
|
|
118
|
-
limit(value: number): Query<Registry, Name, Result, Selected, Many, Root, Filtered, AllowAdjacent, Pagination>;
|
|
119
|
-
offset(value: number): Query<Registry, Name, Result, Selected, Many, Root, Filtered, AllowAdjacent, Pagination>;
|
|
153
|
+
limit(value: number): Query<Registry, Name, Result, Selected, Many, Root, Filtered, AllowAdjacent, Pagination, true>;
|
|
154
|
+
offset(value: number): Query<Registry, Name, Result, Selected, Many, Root, Filtered, AllowAdjacent, Pagination, true>;
|
|
120
155
|
} : {} : {}) & (AllowAdjacent extends true ? {
|
|
121
156
|
/** Attaches a payload under `_payloads` after filtering, ordering, and pagination. */
|
|
122
|
-
withPayload<Key extends keyof PayloadsOf<Registry[Name]> & string>(name: Key, ...variant: keyof VariantOf<Registry[Name], Key> extends never ? [] : [variant: Readonly<VariantOf<Registry[Name], Key>>]): Query<Registry, Name, WithPayload<Result, Key, PayloadsOf<Registry[Name]>[Key]>, true, Many, Root, Filtered, AllowAdjacent, Pagination>;
|
|
157
|
+
withPayload<Key extends keyof PayloadsOf<Registry[Name]> & string>(name: Key, ...variant: keyof VariantOf<Registry[Name], Key> extends never ? [] : [variant: Readonly<VariantOf<Registry[Name], Key>>]): Query<Registry, Name, WithPayload<Result, Key, PayloadsOf<Registry[Name]>[Key]>, true, Many, Root, Filtered, AllowAdjacent, Pagination, Paged>;
|
|
123
158
|
/** Selects neighbor fields within this scope's filtered and ordered results. */
|
|
124
159
|
selectAdjacent<const Keys extends readonly [keyof QueryData<Registry[Name]> & string, ...(keyof QueryData<Registry[Name]> & string)[]]>(...fields: Keys): Query<Registry, Name, Result & {
|
|
125
|
-
_adjacent: Adjacent<
|
|
126
|
-
}, true, Many, Root, Filtered, AllowAdjacent, Pagination>;
|
|
160
|
+
_adjacent: Adjacent<SelectedData<QueryData<Registry[Name]>, Keys[number]>>;
|
|
161
|
+
}, true, Many, Root, Filtered, AllowAdjacent, Pagination, Paged>;
|
|
127
162
|
selectAdjacent<Configured extends QueryInfo<unknown, true>>(configure: (siblings: Query<Registry, Name, {}, false, true, false, false, false, false>) => Configured): Query<Registry, Name, Result & {
|
|
128
163
|
_adjacent: Adjacent<ResultOf<Configured>>;
|
|
129
|
-
}, true, Many, Root, Filtered, AllowAdjacent, Pagination>;
|
|
164
|
+
}, true, Many, Root, Filtered, AllowAdjacent, Pagination, Paged>;
|
|
130
165
|
selectAdjacent<const Options extends AdjacentOptions<Registry, Name>>(options: Options & CheckedOptions<Registry, Name, NoInfer<Options>, true, false, false>): Query<Registry, Name, Result & {
|
|
131
166
|
_adjacent: Adjacent<SelectionResult<Registry, Name, Options["select"]>>;
|
|
132
|
-
}, true, Many, Root, Filtered, AllowAdjacent, Pagination>;
|
|
167
|
+
}, true, Many, Root, Filtered, AllowAdjacent, Pagination, Paged>;
|
|
133
168
|
} : {}) & (Root extends true ? {
|
|
134
169
|
all: Selected extends true ? () => Promise<Simplify$1<Result>[]> : UnselectedTerminal;
|
|
135
170
|
execute: Selected extends true ? () => Promise<Simplify$1<Result>[]> : UnselectedTerminal;
|
|
@@ -139,7 +174,79 @@ type Query<Registry extends CollectionRegistry, Name extends keyof Registry & st
|
|
|
139
174
|
count: [Result] extends [never] ? () => Promise<number> : [Result] extends [{
|
|
140
175
|
_payloads: unknown;
|
|
141
176
|
}] ? never : () => Promise<number>;
|
|
177
|
+
/**
|
|
178
|
+
* Returns one page from one revision: `{ page, size }` for page numbers, or
|
|
179
|
+
* `{ size, after?, before?, total? }` for cursors. Unavailable after `limit()` or `offset()`.
|
|
180
|
+
*/
|
|
181
|
+
paginate: Selected extends true ? [Paged] extends [true] ? PaginateAfterLimit : Paginate<Simplify$1<Result>> : UnselectedTerminal;
|
|
182
|
+
} : {});
|
|
183
|
+
/** `paginate()` after `limit()` or `offset()` reports why as its required `this` type. */
|
|
184
|
+
type PaginateAfterLimit = (this: typeof PAGINATE_AFTER_LIMIT_MESSAGE, ...arguments_: readonly unknown[]) => never;
|
|
185
|
+
/** The `paginate()` overloads for one item type. */
|
|
186
|
+
type Paginate<Item> = {
|
|
187
|
+
(options: PageOptions): Promise<NumberedPage<Item>>;
|
|
188
|
+
(options: CursorOptions & {
|
|
189
|
+
total: true;
|
|
190
|
+
}): Promise<CursorPage<Item, true>>;
|
|
191
|
+
(options: CursorOptions): Promise<CursorPage<Item>>;
|
|
192
|
+
};
|
|
193
|
+
/** Page-number pagination: `page` starts at 1 and `size` is the number of entries per page. */
|
|
194
|
+
type PageOptions = {
|
|
195
|
+
page: number;
|
|
196
|
+
size: number;
|
|
197
|
+
after?: never;
|
|
198
|
+
before?: never;
|
|
199
|
+
total?: never;
|
|
200
|
+
};
|
|
201
|
+
/**
|
|
202
|
+
* Cursor pagination. `after` continues from an earlier page's `endCursor`; `before` returns the
|
|
203
|
+
* entries just before a `startCursor`. A `null` cursor starts at the first entry (`after`) or the
|
|
204
|
+
* last entry (`before`). `total: true` adds the matching total.
|
|
205
|
+
*/
|
|
206
|
+
type CursorOptions = {
|
|
207
|
+
size: number;
|
|
208
|
+
page?: never;
|
|
209
|
+
total?: boolean;
|
|
210
|
+
} & ({
|
|
211
|
+
after?: string | null;
|
|
212
|
+
before?: never;
|
|
213
|
+
} | {
|
|
214
|
+
before?: string | null;
|
|
215
|
+
after?: never;
|
|
216
|
+
});
|
|
217
|
+
/** Options accepted by `paginate()`. */
|
|
218
|
+
type PaginateOptions = PageOptions | CursorOptions;
|
|
219
|
+
/** Option names that `paginate()` reads alongside relational query options. */
|
|
220
|
+
type PaginateKey = keyof PageOptions;
|
|
221
|
+
/** One numbered page and where it sits among every matching entry. */
|
|
222
|
+
type NumberedPage<Item> = {
|
|
223
|
+
items: Item[];
|
|
224
|
+
/** Matching entries across every page. */
|
|
225
|
+
total: number;
|
|
226
|
+
page: number;
|
|
227
|
+
/** At least 1: the first page exists even when nothing matches. */
|
|
228
|
+
pageCount: number;
|
|
229
|
+
hasNextPage: boolean;
|
|
230
|
+
hasPreviousPage: boolean;
|
|
231
|
+
};
|
|
232
|
+
/** One cursor page. Both cursors are `null` when the page is empty. */
|
|
233
|
+
type CursorPage<Item, Total extends boolean = false> = {
|
|
234
|
+
items: Item[];
|
|
235
|
+
/** Pass as `before` for the previous page. */
|
|
236
|
+
startCursor: string | null;
|
|
237
|
+
/** Pass as `after` for the next page. */
|
|
238
|
+
endCursor: string | null;
|
|
239
|
+
hasNextPage: boolean;
|
|
240
|
+
hasPreviousPage: boolean;
|
|
241
|
+
} & (Total extends true ? {
|
|
242
|
+
total: number;
|
|
142
243
|
} : {});
|
|
244
|
+
/** The page type `paginate()` returns for the given options. */
|
|
245
|
+
type PaginateResult<Item, Options> = Options extends {
|
|
246
|
+
page: number;
|
|
247
|
+
} ? NumberedPage<Item> : CursorPage<Item, Options extends {
|
|
248
|
+
total: true;
|
|
249
|
+
} ? true : false>;
|
|
143
250
|
type Adjacent<Entry> = {
|
|
144
251
|
previous: Entry | null;
|
|
145
252
|
next: Entry | null;
|
|
@@ -197,9 +304,11 @@ type Selection<Registry extends CollectionRegistry, Name extends keyof Registry
|
|
|
197
304
|
type ObjectRelationValue<Registry extends CollectionRegistry, Name extends keyof Registry & string, Key extends keyof RelationshipsOf<Registry[Name]>, Options> = Options extends {
|
|
198
305
|
select: infer Projection;
|
|
199
306
|
} ? RelationValue<Registry[Name], RelationOf<Registry, Name, Key>, QueryInfo<SelectionResult<Registry, RelatedName$1<Registry, RelationOf<Registry, Name, Key>>, Projection>, true, "where" extends keyof Options ? true : false>> : never;
|
|
200
|
-
|
|
307
|
+
/** Data fields an object projection requests, excluding relationships and `_adjacent`. */
|
|
308
|
+
type ProjectedFields<Registry extends CollectionRegistry, Name extends keyof Registry & string, Projection> = Exclude<{ [Key in keyof Projection]-?: Projection[Key] extends false | undefined ? never : Key; }[keyof Projection], "_adjacent" | keyof RelationshipsOf<Registry[Name]>> & keyof QueryData<Registry[Name]>;
|
|
309
|
+
type SelectionResult<Registry extends CollectionRegistry, Name extends keyof Registry & string, Projection> = Simplify$1<{ -readonly [Key in keyof Projection as Projection[Key] extends false | undefined ? never : Key extends ProjectedFields<Registry, Name, Projection> ? never : Key]-?: Key extends "_adjacent" ? Projection[Key] extends {
|
|
201
310
|
select: infer Neighbors;
|
|
202
|
-
} ? Adjacent<SelectionResult<Registry, Name, Neighbors>> : never : Key extends keyof RelationshipsOf<Registry[Name]> ? ObjectRelationValue<Registry, Name, Key, Projection[Key]> :
|
|
311
|
+
} ? Adjacent<SelectionResult<Registry, Name, Neighbors>> : never : Key extends keyof RelationshipsOf<Registry[Name]> ? ObjectRelationValue<Registry, Name, Key, Projection[Key]> : never; } & SelectedData<QueryData<Registry[Name]>, ProjectedFields<Registry, Name, Projection>>>;
|
|
203
312
|
type CheckedField<Value, Filter> = Filter extends Scalar ? Filter : { [Operator in keyof Filter]: Operator extends keyof FieldFilter$1<Value> ? Operator extends "not" ? CheckedField<Value, Filter[Operator]> : Filter[Operator] : never; };
|
|
204
313
|
type CheckedWhereList$1<Data, Filters extends readonly unknown[]> = { [Index in keyof Filters]: CheckedWhere$1<Data, Filters[Index]>; };
|
|
205
314
|
type CheckedWhere$1<Data, Filter> = Filter extends ((...arguments_: never[]) => unknown) ? Filter : { [Key in keyof Filter]: Key extends "AND" | "OR" | "NOT" ? Filter[Key] extends readonly unknown[] ? CheckedWhereList$1<Data, Filter[Key]> : CheckedWhere$1<Data, Filter[Key]> : Key extends keyof Data ? CheckedField<Data[Key], Filter[Key]> : never; };
|
|
@@ -289,11 +398,13 @@ type RelationalQueryOptions<Registry extends CollectionRegistry, Name extends ke
|
|
|
289
398
|
} & RelationalQueryOptions<Registry, Name, true, false, false>);
|
|
290
399
|
payloads?: PayloadOptions<Registry, Name>;
|
|
291
400
|
} : {});
|
|
401
|
+
/** Options accepted by relational `paginate()`: query options without limit or offset, plus a page request. */
|
|
402
|
+
type RelationalPaginateOptions<Registry extends CollectionRegistry, Name extends keyof Registry & string> = RelationalQueryOptions<Registry, Name, true, true, false> & PaginateOptions;
|
|
292
403
|
/** Options accepted by the root count helper, whose result ignores sorting and pagination. */
|
|
293
404
|
type RelationalCountOptions<Registry extends CollectionRegistry, Name extends keyof Registry & string> = Pick<RelationalQueryOptions<Registry, Name>, "where" | "orderBy" | "offset" | "limit">;
|
|
294
405
|
type ColumnResult<Data, Options> = Options extends {
|
|
295
406
|
columns: infer Columns;
|
|
296
|
-
} ? {
|
|
407
|
+
} ? SelectedData<Data, { [Key in keyof Columns]-?: Columns[Key] extends true ? Key : never; }[keyof Columns] & keyof Data> : {};
|
|
297
408
|
/** Keys whose option values request something, as opposed to `false` or `undefined`. */
|
|
298
409
|
type Requested<Map> = keyof { [Key in keyof Map as Map[Key] extends false | undefined ? never : Key]: unknown; };
|
|
299
410
|
/** Whether options select fields, include relationships, request payloads, or select adjacency. */
|
|
@@ -331,9 +442,9 @@ type RelationalQueryResult<Registry extends CollectionRegistry, Name extends key
|
|
|
331
442
|
type CheckedConditions<Value, Filters extends readonly unknown[]> = { [Index in keyof Filters]: CheckedCondition<Value, Filters[Index]>; };
|
|
332
443
|
type CheckedCondition<Value, Filter> = Filter extends Scalar ? Filter : { [Key in keyof Filter]: Key extends "AND" | "OR" ? Filter[Key] extends readonly unknown[] ? CheckedConditions<Value, Filter[Key]> : never : Key extends "NOT" ? CheckedCondition<Value, Filter[Key]> : Key extends keyof FieldFilter<Value> ? Filter[Key] : never; };
|
|
333
444
|
type CheckedWhereList<Registry extends CollectionRegistry, Name extends keyof Registry & string, Filters extends readonly unknown[]> = { [Index in keyof Filters]: CheckedWhere<Registry, Name, Filters[Index]>; };
|
|
334
|
-
type CheckedWhere<Registry extends CollectionRegistry, Name extends keyof Registry & string, Filter> = { [Key in keyof Filter]: Key extends "AND" | "OR" | "NOT" ? Filter[Key] extends readonly unknown[] ? CheckedWhereList<Registry, Name, Filter[Key]> : CheckedWhere<Registry, Name, Filter[Key]> : Key extends "RAW" ? Filter[Key] : Key extends keyof RelationshipsOf<Registry[Name]> ? Filter[Key] extends boolean ? Filter[Key] : CheckedWhere<Registry, RelatedName<Registry, Name, Key>, Filter[Key]> : Key extends keyof QueryData<Registry[Name]> ? CheckedCondition<QueryData<Registry[Name]>[Key], Filter[Key]> :
|
|
445
|
+
type CheckedWhere<Registry extends CollectionRegistry, Name extends keyof Registry & string, Filter> = { [Key in keyof Filter]: Key extends "AND" | "OR" | "NOT" ? Filter[Key] extends readonly unknown[] ? CheckedWhereList<Registry, Name, Filter[Key]> : CheckedWhere<Registry, Name, Filter[Key]> : Key extends "RAW" ? Filter[Key] : Key extends keyof RelationshipsOf<Registry[Name]> ? Filter[Key] extends boolean ? Filter[Key] : CheckedWhere<Registry, RelatedName<Registry, Name, Key>, Filter[Key]> : Key extends keyof QueryData<Registry[Name]> ? CheckedCondition<QueryData<Registry[Name]>[Key], Filter[Key]> : UnavailableRelationship<Registry[Name], Key>; };
|
|
335
446
|
/** Rejects unknown options recursively, including options supplied through inferred variables. */
|
|
336
|
-
type CheckedRelationalOptions<Registry extends CollectionRegistry, Name extends keyof Registry & string, Options, Many extends boolean = true, AllowAdjacent extends boolean = true, Pagination extends boolean = true> = { [Key in keyof Options]: Key extends "columns" ? { [Column in keyof Options[Key]]: Column extends keyof QueryData<Registry[Name]> ? Options[Key][Column] : never; } : Key extends "where" ? CheckedWhere<Registry, Name, Options[Key]> : Key extends "with" ? { [Related in keyof Options[Key]]: Related extends keyof RelationshipsOf<Registry[Name]> ? Options[Key][Related] extends false | undefined ? Options[Key][Related] : CheckedRelationalOptions<Registry, RelatedName<Registry, Name, Related>, Options[Key][Related], IsMany<Registry, Name, Related>, AllowAdjacent> & SelectionRequired<Options[Key][Related]> :
|
|
447
|
+
type CheckedRelationalOptions<Registry extends CollectionRegistry, Name extends keyof Registry & string, Options, Many extends boolean = true, AllowAdjacent extends boolean = true, Pagination extends boolean = true> = { [Key in keyof Options]: Key extends "columns" ? { [Column in keyof Options[Key]]: Column extends keyof QueryData<Registry[Name]> ? Options[Key][Column] : never; } : Key extends "where" ? CheckedWhere<Registry, Name, Options[Key]> : Key extends "with" ? { [Related in keyof Options[Key]]: Related extends keyof RelationshipsOf<Registry[Name]> ? Options[Key][Related] extends false | undefined ? Options[Key][Related] : CheckedRelationalOptions<Registry, RelatedName<Registry, Name, Related>, Options[Key][Related], IsMany<Registry, Name, Related>, AllowAdjacent> & SelectionRequired<Options[Key][Related]> : UnavailableRelationship<Registry[Name], Related>; } : Key extends "adjacent" ? AllowAdjacent extends true ? CheckedRelationalOptions<Registry, Name, Omit<Options[Key], "scope">, true, false, false> & SelectionRequired<Options[Key]> & (Options[Key] extends {
|
|
337
448
|
scope: "results";
|
|
338
449
|
} ? {
|
|
339
450
|
scope: "results";
|
|
@@ -342,12 +453,19 @@ type CheckedRelationalOptions<Registry extends CollectionRegistry, Name extends
|
|
|
342
453
|
} : {
|
|
343
454
|
scope?: "collection";
|
|
344
455
|
}) : never : Key extends "payloads" ? AllowAdjacent extends true ? { [Payload in keyof Options[Key]]: Payload extends keyof PayloadsOf<Registry[Name]> ? CheckedPayloadRequest<Options[Key][Payload], VariantOf<Registry[Name], Payload>> : never; } : never : Key extends "orderBy" ? Key extends keyof RelationalQueryOptions<Registry, Name, Many, AllowAdjacent, Pagination> ? { [Field in keyof Options[Key]]: Field extends keyof OrderBy<QueryData<Registry[Name]>> ? Options[Key][Field] : never; } : never : Key extends keyof RelationalQueryOptions<Registry, Name, Many, AllowAdjacent, Pagination> ? Options[Key] : never; };
|
|
345
|
-
/**
|
|
346
|
-
type
|
|
456
|
+
/** One collection's relational queries: `findMany`, `findFirst`, and `paginate`. */
|
|
457
|
+
type RelationalCollectionQueries<Registry extends CollectionRegistry, Name extends keyof Registry & string> = {
|
|
347
458
|
/** Returns matching rows with exactly the selected data. Options must select something. */
|
|
348
459
|
findMany<const Options extends RelationalQueryOptions<Registry, Name>>(options: Options & CheckedRelationalOptions<Registry, Name, NoInfer<Options>> & SelectionRequired<NoInfer<Options>>): Promise<RelationalQueryResult<Registry, Name, Options>[]>;
|
|
349
460
|
/** Returns the first matching row, or undefined when none matches. */
|
|
350
461
|
findFirst<const Options extends RelationalQueryOptions<Registry, Name>>(options: Options & CheckedRelationalOptions<Registry, Name, NoInfer<Options>> & SelectionRequired<NoInfer<Options>>): Promise<RelationalQueryResult<Registry, Name, Options> | undefined>;
|
|
351
|
-
|
|
462
|
+
/**
|
|
463
|
+
* Returns one page from one revision: `page` and `size` for page numbers, or `size` with
|
|
464
|
+
* `after`, `before`, or `total` for cursors. `limit` and `offset` are unavailable.
|
|
465
|
+
*/
|
|
466
|
+
paginate<const Options extends RelationalPaginateOptions<Registry, Name>>(options: Options & CheckedRelationalOptions<Registry, Name, NoInfer<Omit<Options, PaginateKey>>, true, true, false> & SelectionRequired<NoInfer<Options>>): Promise<PaginateResult<RelationalQueryResult<Registry, Name, Options>, Options>>;
|
|
467
|
+
};
|
|
468
|
+
/** Typed per-collection query entry points that never expose source configuration at runtime. */
|
|
469
|
+
type RelationalQueries<Registry extends CollectionRegistry> = string extends keyof Registry ? {} : { readonly [Name in keyof Registry & string]: RelationalCollectionQueries<Registry, Name>; };
|
|
352
470
|
//#endregion
|
|
353
|
-
export { Where as _,
|
|
471
|
+
export { Selection as C, QueryPlan as D, Expression as E, QueryRegistry as O, ScalarField as S, Where as T, PaginateResult as _, RelationalQueryOptions as a, RelationField as b, Adjacent as c, Field$1 as d, Fields as f, PaginateOptions as g, PageOptions as h, RelationalQueries as i, QueryTerminal as k, CursorOptions as l, Ordered as m, RelationalCountOptions as n, RelationalQueryResult as o, NumberedPage as p, RelationalPaginateOptions as r, RelationalWhere as s, RelationalCollectionQueries as t, CursorPage as u, Query as v, SelectionResult as w, Scalar as x, QueryFields as y };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { s as ContentError } from "./collection-types-DhIxnCSM.mjs";
|
|
2
|
+
import { n as ContentRenderResult } from "./types-Dh-Sydyw.mjs";
|
|
3
|
+
import { _ as Relationship } from "./types-WOsFmNnN.mjs";
|
|
4
|
+
import { D as QueryPlan, O as QueryRegistry, k as QueryTerminal } from "./relational-types-PtrzENt0.mjs";
|
|
5
|
+
import { n as QueryStyle } from "./query-style-C2FcT1f9.mjs";
|
|
6
|
+
//#region src/runtime/revision.d.ts
|
|
7
|
+
type QueryRecord = Record<string, unknown> & {
|
|
8
|
+
id: string;
|
|
9
|
+
};
|
|
10
|
+
/** Custom payload loaders by payload name, entry ID, and canonical variant key. */
|
|
11
|
+
type CustomPayloadTable = ReadonlyMap<string, ReadonlyMap<string, ReadonlyMap<string, () => Promise<unknown>>>>;
|
|
12
|
+
/** The built-in side payload shared by an entry's `_body` and `_rendered` payloads. */
|
|
13
|
+
type BuiltinPayload = {
|
|
14
|
+
body?: string;
|
|
15
|
+
rendered?: ContentRenderResult;
|
|
16
|
+
markdown?: string;
|
|
17
|
+
};
|
|
18
|
+
type PreparedCollection = {
|
|
19
|
+
records: readonly QueryRecord[];
|
|
20
|
+
relationships: Record<string, Relationship>;
|
|
21
|
+
/** Lazy built-in payloads, present only for entries with a body or rendered output. */
|
|
22
|
+
builtins: ReadonlyMap<string, () => Promise<BuiltinPayload>>;
|
|
23
|
+
/**
|
|
24
|
+
* Lazy custom payloads by payload name, entry ID, and canonical variant key. A missing variant
|
|
25
|
+
* key means the entry has no such combination.
|
|
26
|
+
*/
|
|
27
|
+
payloads?: CustomPayloadTable;
|
|
28
|
+
sources?: ReadonlyMap<string, string | undefined>;
|
|
29
|
+
};
|
|
30
|
+
type PreparedRevision = {
|
|
31
|
+
registry: QueryRegistry;
|
|
32
|
+
collections: Record<string, PreparedCollection>;
|
|
33
|
+
relations: Map<string, Map<string, readonly QueryRecord[]>>;
|
|
34
|
+
active: number;
|
|
35
|
+
/** Built-in payloads keyed by collection and ID; custom payloads also by name and variant. */
|
|
36
|
+
payloadCache: Map<string, Promise<unknown>>;
|
|
37
|
+
renderCache: Map<string, Promise<ContentRenderResult>>;
|
|
38
|
+
renderMarkdown?: (body: string) => Promise<ContentRenderResult>;
|
|
39
|
+
/** The only query style this revision's configuration allows; absent allows both. */
|
|
40
|
+
queryStyle?: QueryStyle;
|
|
41
|
+
execute?: (plan: QueryPlan, terminal: QueryTerminal, requests: PayloadRequest[]) => Promise<unknown>;
|
|
42
|
+
};
|
|
43
|
+
/** A projected row awaiting the payloads its query scope requested. */
|
|
44
|
+
type PayloadRequest = {
|
|
45
|
+
target: Record<string, unknown>;
|
|
46
|
+
collection: string;
|
|
47
|
+
id: string;
|
|
48
|
+
payloads: NonNullable<QueryPlan["payloads"]>;
|
|
49
|
+
};
|
|
50
|
+
type ContentState = {
|
|
51
|
+
revision?: PreparedRevision;
|
|
52
|
+
registry?: QueryRegistry;
|
|
53
|
+
error?: ContentError;
|
|
54
|
+
};
|
|
55
|
+
//#endregion
|
|
56
|
+
export { PreparedRevision as n, ContentState as t };
|
package/dist/runtime.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { c as ContentErrorCode, i as LoadedRegistry, n as Collection, o as ContentDiagnostic, r as CollectionHandles, s as ContentError, t as AnyCollection } from "./collection-types-DhIxnCSM.mjs";
|
|
2
2
|
import { n as ContentRenderResult, t as ContentHeading } from "./types-Dh-Sydyw.mjs";
|
|
3
|
-
import { n as QueryStyle, r as QueryStyleDisabled } from "./query-style-
|
|
4
|
-
export { type
|
|
3
|
+
import { n as QueryStyle, r as QueryStyleDisabled } from "./query-style-C2FcT1f9.mjs";
|
|
4
|
+
export { type AnyCollection, type Collection, type CollectionHandles, type ContentDiagnostic, ContentError, type ContentErrorCode, type ContentHeading, type ContentRenderResult, type LoadedRegistry, type QueryStyle, type QueryStyleDisabled };
|
|
@@ -4,6 +4,7 @@ import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
|
4
4
|
//#region src/collection/types.d.ts
|
|
5
5
|
declare const builtinPayloadsType: unique symbol;
|
|
6
6
|
declare const customPayloadsType: unique symbol;
|
|
7
|
+
declare const loadedCollectionsType: unique symbol;
|
|
7
8
|
type Schema = StandardSchemaV1;
|
|
8
9
|
type SchemaOutput<Value> = Value extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<Value> : Record<string, unknown>;
|
|
9
10
|
/** One file or record that a `files` helper read, shaped like a loader entry. */
|
|
@@ -127,6 +128,11 @@ type CollectionDefinition<SourceSchema extends Schema | undefined = Schema | und
|
|
|
127
128
|
payloads?: Record<string, PayloadDeclaration>;
|
|
128
129
|
/** Directories, relative to the project root, that every entry's `files` helpers may read. */
|
|
129
130
|
sharedFiles?: readonly string[];
|
|
131
|
+
/**
|
|
132
|
+
* The singular name in generated types, such as `"Category"` for `ContentCategory`. Defaults to
|
|
133
|
+
* the export name without one trailing `s`.
|
|
134
|
+
*/
|
|
135
|
+
typeName?: string;
|
|
130
136
|
};
|
|
131
137
|
type CollectionRegistry = Record<string, CollectionDefinition>;
|
|
132
138
|
type EntryData<Definition> = Definition extends {
|
|
@@ -137,12 +143,56 @@ type ComputedData<Definition> = Definition extends {
|
|
|
137
143
|
} ? { [Name in keyof Computed]: Computed[Name] extends {
|
|
138
144
|
schema: infer ResultSchema;
|
|
139
145
|
} ? SchemaOutput<ResultSchema> : never; } : {};
|
|
146
|
+
/**
|
|
147
|
+
* An entry's ID, validated metadata, and computed fields. JSDoc comments on schema fields and
|
|
148
|
+
* computed field names carry through, so editors show them when hovering a field.
|
|
149
|
+
*/
|
|
140
150
|
type QueryData<Definition> = {
|
|
151
|
+
/** The entry's ID, unique within its collection. */
|
|
141
152
|
id: string;
|
|
142
153
|
} & EntryData<Definition> & ComputedData<Definition>;
|
|
154
|
+
/** Maps `Field` without reading `Data`'s modifiers, so every key is required. */
|
|
155
|
+
type PresentFields<Data, Field extends PropertyKey> = { [Key in Field]: Key extends keyof Data ? Data[Key] : never; };
|
|
156
|
+
/** Flattens an intersection into one mutable object type, keeping each property's declaration. */
|
|
157
|
+
type MutableObject<Value> = { -readonly [Key in keyof Value]: Value[Key]; };
|
|
158
|
+
/**
|
|
159
|
+
* The shape of `Data` when a query selects `Field`. Every selected key is present and mutable,
|
|
160
|
+
* and an optional field's value includes `undefined` instead of the key being optional.
|
|
161
|
+
*
|
|
162
|
+
* Each property stays linked to its declaration in `Data`, so JSDoc comments written on schema
|
|
163
|
+
* fields show when hovering a selected field, and go to definition opens the schema.
|
|
164
|
+
*/
|
|
165
|
+
type SelectedData<Data, Field extends keyof Data> = MutableObject<PresentFields<Data, Field> & Pick<Data, Field>>;
|
|
166
|
+
/**
|
|
167
|
+
* Type-only marker recording which collections a query scope loaded. A marked definition offers
|
|
168
|
+
* only the relationships whose target is loaded; an unmarked one offers every relationship.
|
|
169
|
+
*/
|
|
170
|
+
type LoadedMarker<Loaded> = {
|
|
171
|
+
readonly [loadedCollectionsType]?: Loaded;
|
|
172
|
+
};
|
|
173
|
+
/** The collections a marked definition's query scope loaded, or `unknown` when unmarked. */
|
|
174
|
+
type LoadedOf<Definition> = Definition extends {
|
|
175
|
+
readonly [loadedCollectionsType]?: infer Loaded;
|
|
176
|
+
} ? Loaded : unknown;
|
|
177
|
+
/** The declared relationships, keeping only those into `Loaded` when it is not `unknown`. */
|
|
178
|
+
type RelationshipsInto<Relationships, Loaded, Keep extends boolean> = unknown extends Loaded ? Keep extends true ? Relationships : {} : { [Name in keyof Relationships as (Relationships[Name] extends {
|
|
179
|
+
collection: Loaded;
|
|
180
|
+
} ? Keep : Keep extends true ? false : true) extends true ? Name : never]: Relationships[Name]; };
|
|
181
|
+
/** Relationships a query can follow: every declared one, or only those into loaded collections. */
|
|
143
182
|
type RelationshipsOf<Definition> = Definition extends {
|
|
144
183
|
relationships: infer Relationships;
|
|
145
|
-
} ? Relationships : {};
|
|
184
|
+
} ? RelationshipsInto<Relationships, LoadedOf<Definition>, true> : {};
|
|
185
|
+
/**
|
|
186
|
+
* The type error for a declared relationship whose target collection the query has not loaded,
|
|
187
|
+
* or `never` for a name that is not such a relationship.
|
|
188
|
+
*/
|
|
189
|
+
type UnavailableRelationship<Definition, Name> = Name extends keyof UnavailableRelationshipsOf<Definition> ? UnavailableRelationshipsOf<Definition>[Name] extends {
|
|
190
|
+
collection: infer Target extends string;
|
|
191
|
+
} ? `Relationship "${Name & string}" targets the ${Target} collection, which this query has not loaded. Pass it to using().` : never : never;
|
|
192
|
+
/** Declared relationships into collections the query scope has not loaded. */
|
|
193
|
+
type UnavailableRelationshipsOf<Definition> = Definition extends {
|
|
194
|
+
relationships: infer Relationships;
|
|
195
|
+
} ? RelationshipsInto<Relationships, LoadedOf<Definition>, false> : {};
|
|
146
196
|
/**
|
|
147
197
|
* Payloads that Markdown sources, `glob()`, and custom loaders provide for every entry.
|
|
148
198
|
* Built-in names start with an underscore, so they never collide with custom payloads.
|
|
@@ -178,4 +228,4 @@ type PayloadData<Definition, Name extends keyof PayloadsOf<Definition>> = Payloa
|
|
|
178
228
|
/** The variant keys a payload request must supply; empty for built-in and single-value payloads. */
|
|
179
229
|
type VariantOf<Definition, Name> = Name extends keyof CustomPayloadsOf<Definition> ? CustomPayloadsOf<Definition>[Name] extends CustomPayload<unknown, infer Variant> ? Variant : {} : {};
|
|
180
230
|
//#endregion
|
|
181
|
-
export {
|
|
231
|
+
export { UnavailableRelationshipsOf as C, VariantValues as D, VariantOf as E, UnavailableRelationship as S, VariantField as T, Relationship as _, ComputedContext as a, SchemaOutput as b, EntryFiles as c, PayloadContext as d, PayloadData as f, QueryData as g, PayloadsOf as h, CollectionRegistry as i, FileEntry as l, PayloadDefinition as m, BuiltinPayloads as n, CustomPayload as o, PayloadDeclaration as p, CollectionDefinition as r, CustomPayloadMarker as s, BuiltinPayloadMarker as t, LoadedMarker as u, RelationshipsOf as v, VariantContext as w, SelectedData as x, Schema as y };
|