content-query 0.3.0 → 0.4.0
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 +21 -1
- package/dist/{build-CI4s0oFP.mjs → build-CcqIpkes.mjs} +709 -39
- package/dist/{build-jKnjDjQE.d.mts → build-DL1GzmRy.d.mts} +12 -5
- package/dist/build.d.mts +1 -1
- package/dist/build.mjs +1 -1
- package/dist/cli.mjs +14 -8
- package/dist/computed.d.mts +2 -2
- package/dist/{content-N1gYshjg.mjs → content-BXrgP7nL.mjs} +271 -81
- package/dist/{content-lwPxE9Yu.d.mts → content-CwTKqRs9.d.mts} +39 -14
- package/dist/{types-FmUJ3cH1.d.mts → descriptor-bcPa6XLk.d.mts} +17 -1
- package/dist/{diagnostics-Cu94mZhl.mjs → diagnostics-DmUZtrJ6.mjs} +3 -1
- package/dist/{errors-C2iuBM0G.mjs → errors-Bfd0R4_P.mjs} +16 -1
- package/dist/file-DSOcdFj0.mjs +81 -0
- package/dist/{glob-Bv0dpvCQ.mjs → glob-BXJuwy_p.mjs} +94 -6
- package/dist/index.d.mts +61 -18
- package/dist/index.mjs +1 -1
- package/dist/internal.d.mts +11 -4
- package/dist/internal.mjs +29 -5
- package/dist/loaders.d.mts +1 -2
- package/dist/loaders.mjs +2 -81
- package/dist/next.d.mts +1 -1
- package/dist/next.mjs +2 -2
- package/dist/{operators-UqWUhKQJ.mjs → operators-Cwy8Kx4o.mjs} +88 -2
- package/dist/query-style-eXENQJ0O.d.mts +22 -0
- package/dist/query.d.mts +25 -2
- package/dist/query.mjs +1 -1
- package/dist/{relational-types-B45zM34W.d.mts → relational-types-C8xJtLG5.d.mts} +113 -38
- package/dist/runtime.d.mts +3 -2
- package/dist/runtime.mjs +1 -1
- package/dist/types-DbFfF6JE.d.mts +181 -0
- package/dist/vite.d.mts +1 -1
- package/dist/vite.mjs +2 -2
- package/package.json +1 -1
- package/dist/descriptor-BUPT2J7X.d.mts +0 -18
- package/dist/types-BC8gVJ6u.d.mts +0 -69
- package/dist/validation-D_XdE1pF.mjs +0 -84
package/dist/loaders.d.mts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import { n as GlobOptions, t as FileOptions } from "./descriptor-BUPT2J7X.mjs";
|
|
1
|
+
import { a as DataStore, c as Loader, d as LoaderLogger, f as LoaderSource, h as RecordLoader, i as DataEntry, l as LoaderConfig, m as MetaStore, n as GlobOptions, o as FileEntrySource, p as LoaderWatcher, r as BodyLoader, s as FileSource, t as FileOptions, u as LoaderContext } from "./descriptor-bcPa6XLk.mjs";
|
|
3
2
|
//#region src/loaders/file.d.ts
|
|
4
3
|
/** Declares a multi-entry data file with typed source paths and record keys, plus an optional parser. */
|
|
5
4
|
export declare function file(filename: string, options?: FileOptions): RecordLoader<FileEntrySource>;
|
package/dist/loaders.mjs
CHANGED
|
@@ -1,85 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { i as groupDiagnostics, n as contentError, r as describeCause, t as ContentError } from "./errors-C2iuBM0G.mjs";
|
|
3
|
-
import { a as populateStore, i as recordData, n as coerceIdentity, r as parseData, t as glob } from "./glob-Bv0dpvCQ.mjs";
|
|
1
|
+
import { t as glob } from "./glob-BXJuwy_p.mjs";
|
|
4
2
|
import { t as assertServerOnly } from "./server-only-CIJUlyL-.mjs";
|
|
5
|
-
import {
|
|
6
|
-
import path from "node:path";
|
|
7
|
-
import { fileURLToPath } from "node:url";
|
|
8
|
-
//#region src/loaders/file.ts
|
|
9
|
-
/** Declares a multi-entry data file with typed source paths and record keys, plus an optional parser. */
|
|
10
|
-
function file(filename, options = {}) {
|
|
11
|
-
if (typeof filename !== "string" || !filename) throw new TypeError("file() requires a filename.");
|
|
12
|
-
const descriptor = {
|
|
13
|
-
kind: "file",
|
|
14
|
-
filename,
|
|
15
|
-
options
|
|
16
|
-
};
|
|
17
|
-
return {
|
|
18
|
-
[builtinSymbol]: descriptor,
|
|
19
|
-
name: "content-query/file",
|
|
20
|
-
async load(context) {
|
|
21
|
-
const entries = await loadFile(descriptor, fileURLToPath(context.config.root), context.signal ?? new AbortController().signal);
|
|
22
|
-
await populateStore(context, entries);
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
/** Captures a complete multi-entry data source without applying collection validation. */
|
|
27
|
-
async function loadFile(descriptor, root, signal) {
|
|
28
|
-
const resolved = builtinPath(descriptor, root);
|
|
29
|
-
let parsed;
|
|
30
|
-
try {
|
|
31
|
-
const text = await readFile(resolved, {
|
|
32
|
-
encoding: "utf8",
|
|
33
|
-
signal
|
|
34
|
-
});
|
|
35
|
-
parsed = descriptor.options.parser ? await descriptor.options.parser(text) : parseData(text, resolved);
|
|
36
|
-
} catch (cause) {
|
|
37
|
-
signal.throwIfAborted();
|
|
38
|
-
throw contentError(cause, {
|
|
39
|
-
code: "source-error",
|
|
40
|
-
source: resolved,
|
|
41
|
-
message: `Could not load "${descriptor.filename}": ${describeCause(cause)}`,
|
|
42
|
-
cause
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
const array = Array.isArray(parsed);
|
|
46
|
-
if (!array && (!parsed || typeof parsed !== "object")) throw new ContentError({
|
|
47
|
-
code: "source-error",
|
|
48
|
-
source: resolved,
|
|
49
|
-
message: `"${descriptor.filename}" must parse to an array or keyed record.`
|
|
50
|
-
});
|
|
51
|
-
const diagnostics = [];
|
|
52
|
-
const entries = Object.entries(parsed).flatMap(([key, value]) => {
|
|
53
|
-
if (!array && key === "$schema" && typeof value === "string") return [];
|
|
54
|
-
const source = `${resolved}#${key}`;
|
|
55
|
-
try {
|
|
56
|
-
const data = recordData(value);
|
|
57
|
-
const identity = array ? data.id ?? data.slug : key;
|
|
58
|
-
if (identity == null || coerceIdentity(identity) === "") throw new Error("Array entries require a nonempty id or slug.");
|
|
59
|
-
const { id: _transportId, ...metadata } = data;
|
|
60
|
-
return [{
|
|
61
|
-
id: coerceIdentity(identity),
|
|
62
|
-
data: metadata,
|
|
63
|
-
source: array ? source : `${resolved}#${coerceIdentity(identity)}`,
|
|
64
|
-
sourceData: {
|
|
65
|
-
filePath: path.relative(root, resolved).split(path.sep).join("/"),
|
|
66
|
-
key
|
|
67
|
-
}
|
|
68
|
-
}];
|
|
69
|
-
} catch (cause) {
|
|
70
|
-
diagnostics.push({
|
|
71
|
-
code: "source-error",
|
|
72
|
-
source,
|
|
73
|
-
message: `Invalid entry "${key}" in "${descriptor.filename}": ${describeCause(cause)}`,
|
|
74
|
-
cause
|
|
75
|
-
});
|
|
76
|
-
return [];
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
if (diagnostics.length) throw groupDiagnostics(diagnostics);
|
|
80
|
-
return entries;
|
|
81
|
-
}
|
|
82
|
-
//#endregion
|
|
3
|
+
import { t as file } from "./file-DSOcdFj0.mjs";
|
|
83
4
|
//#region src/loaders.ts
|
|
84
5
|
assertServerOnly();
|
|
85
6
|
//#endregion
|
package/dist/next.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as BuildContentOptions } from "./build-
|
|
1
|
+
import { t as BuildContentOptions } from "./build-DL1GzmRy.mjs";
|
|
2
2
|
import { NextConfig } from "next";
|
|
3
3
|
//#region src/integrations/next/plugin.d.ts
|
|
4
4
|
/** Content locations for Next.js; the adapter chooses generated storage and the watch lifecycle. */
|
package/dist/next.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { c as contentDeclarations, i as resolveConfigPath, t as buildAtRoot } from "./build-
|
|
2
|
-
import { n as serializeContentError } from "./diagnostics-
|
|
1
|
+
import { c as contentDeclarations, i as resolveConfigPath, t as buildAtRoot } from "./build-CcqIpkes.mjs";
|
|
2
|
+
import { n as serializeContentError } from "./diagnostics-DmUZtrJ6.mjs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
5
|
import { mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as invalidQuery } from "./errors-
|
|
1
|
+
import { a as invalidQuery } from "./errors-Bfd0R4_P.mjs";
|
|
2
2
|
import { c as isScalar, i as detach } from "./values-BbTV4QT-.mjs";
|
|
3
3
|
//#region src/query/operators.ts
|
|
4
4
|
/** Builds a checked, backend-independent predicate instead of a per-entry callback. */
|
|
@@ -78,6 +78,89 @@ function startsWith(field, value) {
|
|
|
78
78
|
function endsWith(field, value) {
|
|
79
79
|
return predicate("ends-with", field, value);
|
|
80
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Matches a SQL-style pattern: `%` matches any run of characters and `_` matches one character.
|
|
83
|
+
* A backslash escapes a wildcard. Matching is case-sensitive.
|
|
84
|
+
*/
|
|
85
|
+
function like(field, pattern) {
|
|
86
|
+
return predicate("like", field, pattern);
|
|
87
|
+
}
|
|
88
|
+
/** Matches a SQL-style pattern like {@link like}, ignoring case. */
|
|
89
|
+
function ilike(field, pattern) {
|
|
90
|
+
return predicate("ilike", field, pattern);
|
|
91
|
+
}
|
|
92
|
+
/** Negates {@link like}; entries without a matching string, including absent values, match. */
|
|
93
|
+
function notLike(field, pattern) {
|
|
94
|
+
return not(like(field, pattern));
|
|
95
|
+
}
|
|
96
|
+
/** Negates {@link ilike}; entries without a matching string, including absent values, match. */
|
|
97
|
+
function notIlike(field, pattern) {
|
|
98
|
+
return not(ilike(field, pattern));
|
|
99
|
+
}
|
|
100
|
+
/** Tests whether every item of an existing scalar array belongs to the candidates. */
|
|
101
|
+
function arrayContained(field, values) {
|
|
102
|
+
return predicate("array-contained", field, values);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Matches entries with at least one related entry. With a filter, a related entry must also match
|
|
106
|
+
* it, for example `has(fields.author, (author) => eq(author.name, "Ada"))`. Wrap the result in
|
|
107
|
+
* {@link not} to match entries without such a related entry.
|
|
108
|
+
*
|
|
109
|
+
* @param relation - A relationship from the `where()` callback's fields.
|
|
110
|
+
* @param filter - Optional filter over the related entry's fields and relationships.
|
|
111
|
+
* @returns An expression that the query resolves against the relationship's target collection.
|
|
112
|
+
*/
|
|
113
|
+
function has(relation, filter) {
|
|
114
|
+
if (!relation || typeof relation.name !== "string" || !relation.name) invalidQuery("has() requires a relationship from the where() fields.");
|
|
115
|
+
if (filter !== void 0 && typeof filter !== "function") invalidQuery("has() filters must be callbacks over the related entry's fields.");
|
|
116
|
+
const expression = filter === void 0 ? and() : filter(fieldProxy());
|
|
117
|
+
validateExpression(expression);
|
|
118
|
+
return {
|
|
119
|
+
kind: "has",
|
|
120
|
+
field: relation.name,
|
|
121
|
+
expression
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/** Creates the field and relationship accessors passed to filter callbacks. */
|
|
125
|
+
function fieldProxy() {
|
|
126
|
+
return new Proxy(Object.create(null), { get: (_target, name) => ({ name }) });
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Resolves fluent `has()` filters against a scope's declared relationships, producing portable
|
|
130
|
+
* `relation` expressions that both runtime backends evaluate.
|
|
131
|
+
*
|
|
132
|
+
* @param registry - The query registry with each collection's relationships.
|
|
133
|
+
* @param collection - The collection the expression filters.
|
|
134
|
+
* @param expression - A validated expression that may contain `has()` filters.
|
|
135
|
+
* @returns The expression with every `has()` filter resolved.
|
|
136
|
+
*/
|
|
137
|
+
function resolveRelations(registry, collection, expression) {
|
|
138
|
+
switch (expression.kind) {
|
|
139
|
+
case "has": {
|
|
140
|
+
const relationships = registry[collection]?.relationships ?? {};
|
|
141
|
+
const relation = Object.hasOwn(relationships, expression.field) ? relationships[expression.field] : void 0;
|
|
142
|
+
if (!relation) invalidQuery(`Unknown relationship "${expression.field}" in has().`);
|
|
143
|
+
return {
|
|
144
|
+
kind: "relation",
|
|
145
|
+
collection,
|
|
146
|
+
field: expression.field,
|
|
147
|
+
target: relation.collection,
|
|
148
|
+
expression: resolveRelations(registry, relation.collection, expression.expression)
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
case "relation": return {
|
|
152
|
+
...expression,
|
|
153
|
+
expression: resolveRelations(registry, expression.target, expression.expression)
|
|
154
|
+
};
|
|
155
|
+
case "and":
|
|
156
|
+
case "or":
|
|
157
|
+
case "not": return {
|
|
158
|
+
...expression,
|
|
159
|
+
expressions: expression.expressions.map((child) => resolveRelations(registry, collection, child))
|
|
160
|
+
};
|
|
161
|
+
default: return expression;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
81
164
|
/** Tests scalar membership in an array, ignoring holes. */
|
|
82
165
|
function arrayContains(field, value) {
|
|
83
166
|
return predicate("array-contains", field, value);
|
|
@@ -160,6 +243,9 @@ function validateExpression(expression) {
|
|
|
160
243
|
expression.target
|
|
161
244
|
].some((name) => typeof name !== "string" || !name)) invalidQuery("Relationship filters require registered collection and relationship names.");
|
|
162
245
|
validateExpression(expression.expression);
|
|
246
|
+
} else if (expression.kind === "has") {
|
|
247
|
+
if (typeof expression.field !== "string" || !expression.field) invalidQuery("has() requires a relationship from the where() fields.");
|
|
248
|
+
validateExpression(expression.expression);
|
|
163
249
|
} else if ([
|
|
164
250
|
"and",
|
|
165
251
|
"or",
|
|
@@ -170,4 +256,4 @@ function validateExpression(expression) {
|
|
|
170
256
|
} else invalidQuery("Invalid expression structure.");
|
|
171
257
|
}
|
|
172
258
|
//#endregion
|
|
173
|
-
export { not as _,
|
|
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 };
|
|
@@ -0,0 +1,22 @@
|
|
|
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
|
+
* Root `content` members that start each query style. Every other query API hangs off these
|
|
6
|
+
* members, so gating them gates payloads, relationships, and adjacency as well.
|
|
7
|
+
*/
|
|
8
|
+
declare const queryStyleMembers: {
|
|
9
|
+
readonly fluent: readonly ["from"];
|
|
10
|
+
readonly relational: readonly ["query", "count"];
|
|
11
|
+
};
|
|
12
|
+
/** A root `content` member that belongs to exactly one query style. */
|
|
13
|
+
type QueryStyleMember = (typeof queryStyleMembers)[QueryStyle][number];
|
|
14
|
+
/** Root members that start a query in the given style. */
|
|
15
|
+
type MembersOf<Style extends QueryStyle> = (typeof queryStyleMembers)[Style][number];
|
|
16
|
+
/**
|
|
17
|
+
* Describes a disabled root member in the type error itself, for example:
|
|
18
|
+
* `content.from is unavailable because content-query.config sets queryStyle to "relational".`
|
|
19
|
+
*/
|
|
20
|
+
type QueryStyleDisabled<Member extends QueryStyleMember, Style extends QueryStyle> = `content.${Member} is unavailable because content-query.config sets queryStyle to "${Style}".`;
|
|
21
|
+
//#endregion
|
|
22
|
+
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 { a as RelationalWhere, c as Fields, d as
|
|
1
|
+
import { _ as Where, a as RelationalWhere, c as Fields, d as QueryFields, f as RelationField, g as SelectionResult, h as Selection, i as RelationalQueryResult, l as Ordered, m as ScalarField, n as RelationalQueries, o as Adjacent, p as Scalar, r as RelationalQueryOptions, s as Field, t as RelationalCountOptions, v as Expression } from "./relational-types-C8xJtLG5.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;
|
|
@@ -22,6 +22,29 @@ export declare function contains<Value>(field: Field<Value> & (NonNullable<Value
|
|
|
22
22
|
export declare function startsWith<Value>(field: Field<Value> & (NonNullable<Value> extends string ? unknown : never), value: string): Expression;
|
|
23
23
|
/** Matches a literal string suffix. */
|
|
24
24
|
export declare function endsWith<Value>(field: Field<Value> & (NonNullable<Value> extends string ? unknown : never), value: string): Expression;
|
|
25
|
+
/**
|
|
26
|
+
* Matches a SQL-style pattern: `%` matches any run of characters and `_` matches one character.
|
|
27
|
+
* A backslash escapes a wildcard. Matching is case-sensitive.
|
|
28
|
+
*/
|
|
29
|
+
export declare function like<Value>(field: Field<Value> & (NonNullable<Value> extends string ? unknown : never), pattern: string): Expression;
|
|
30
|
+
/** Matches a SQL-style pattern like {@link like}, ignoring case. */
|
|
31
|
+
export declare function ilike<Value>(field: Field<Value> & (NonNullable<Value> extends string ? unknown : never), pattern: string): Expression;
|
|
32
|
+
/** Negates {@link like}; entries without a matching string, including absent values, match. */
|
|
33
|
+
export declare function notLike<Value>(field: Field<Value> & (NonNullable<Value> extends string ? unknown : never), pattern: string): Expression;
|
|
34
|
+
/** Negates {@link ilike}; entries without a matching string, including absent values, match. */
|
|
35
|
+
export declare function notIlike<Value>(field: Field<Value> & (NonNullable<Value> extends string ? unknown : never), pattern: string): Expression;
|
|
36
|
+
/** Tests whether every item of an existing scalar array belongs to the candidates. */
|
|
37
|
+
export declare function arrayContained<Value extends Scalar>(field: Field<readonly Value[] | null | undefined>, values: readonly NoInfer<Value>[]): Expression;
|
|
38
|
+
/**
|
|
39
|
+
* Matches entries with at least one related entry. With a filter, a related entry must also match
|
|
40
|
+
* it, for example `has(fields.author, (author) => eq(author.name, "Ada"))`. Wrap the result in
|
|
41
|
+
* {@link not} to match entries without such a related entry.
|
|
42
|
+
*
|
|
43
|
+
* @param relation - A relationship from the `where()` callback's fields.
|
|
44
|
+
* @param filter - Optional filter over the related entry's fields and relationships.
|
|
45
|
+
* @returns An expression that the query resolves against the relationship's target collection.
|
|
46
|
+
*/
|
|
47
|
+
export declare function has<TargetFields>(relation: RelationField<TargetFields>, filter?: (fields: TargetFields) => Expression): Expression;
|
|
25
48
|
/** Tests scalar membership in an array, ignoring holes. */
|
|
26
49
|
export declare function arrayContains<Value extends Scalar>(field: Field<readonly Value[] | null | undefined>, value: NoInfer<Value>): Expression;
|
|
27
50
|
/** Tests whether any candidate belongs to an existing scalar array. */
|
|
@@ -41,4 +64,4 @@ export declare function or(...expressions: Expression[]): Expression;
|
|
|
41
64
|
/** Negates a predicate's boolean result. */
|
|
42
65
|
export declare function not(expression: Expression): Expression;
|
|
43
66
|
//#endregion
|
|
44
|
-
export type { Adjacent, RelationalCountOptions as CountOptions, Expression, Field, Fields, RelationalQueryOptions as QueryOptions, RelationalQueryOptions, RelationalQueries, RelationalQueryResult, RelationalWhere, Selection, SelectionResult, Where };
|
|
67
|
+
export type { Adjacent, RelationalCountOptions as CountOptions, Expression, Field, Fields, QueryFields, RelationalQueryOptions as QueryOptions, RelationalQueryOptions, RelationField, RelationalQueries, RelationalQueryResult, RelationalWhere, Selection, SelectionResult, Where };
|
package/dist/query.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as and, n as
|
|
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-Cwy8Kx4o.mjs";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { S as VariantOf, _ as RelationshipsOf, g as Relationship, h as QueryData, i as CollectionRegistry, m as PayloadsOf } from "./types-DbFfF6JE.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 = {
|
|
@@ -12,15 +12,20 @@ type Expression = {
|
|
|
12
12
|
field: string;
|
|
13
13
|
target: string;
|
|
14
14
|
expression: Expression;
|
|
15
|
+
} |
|
|
16
|
+
/** A fluent `has()` filter that query builders resolve into a `relation` expression. */
|
|
17
|
+
{
|
|
18
|
+
kind: "has";
|
|
19
|
+
field: string;
|
|
20
|
+
expression: Expression;
|
|
15
21
|
} | {
|
|
16
22
|
kind: "and" | "or" | "not";
|
|
17
23
|
expressions: readonly Expression[];
|
|
18
24
|
};
|
|
19
25
|
type QueryPlan = {
|
|
20
26
|
collection: string;
|
|
27
|
+
/** Explicitly selected fields; scopes never include unselected fields, including `id`. */
|
|
21
28
|
select?: readonly string[];
|
|
22
|
-
allFields?: boolean;
|
|
23
|
-
exclude?: readonly string[];
|
|
24
29
|
filters: readonly Expression[];
|
|
25
30
|
order: readonly {
|
|
26
31
|
field: string;
|
|
@@ -29,10 +34,19 @@ type QueryPlan = {
|
|
|
29
34
|
limit?: number;
|
|
30
35
|
offset?: number;
|
|
31
36
|
with: Readonly<Record<string, QueryPlan>>;
|
|
32
|
-
adjacent?:
|
|
37
|
+
adjacent?: AdjacentPlan;
|
|
33
38
|
/** Payloads to attach under `_payloads` after filtering, ordering, and pagination. */
|
|
34
39
|
payloads?: Readonly<Record<string, PlanPayload>>;
|
|
35
40
|
};
|
|
41
|
+
/**
|
|
42
|
+
* Selects previous and next entries. `results` finds neighbors within the scope's own filtered and
|
|
43
|
+
* ordered entries, or a parent's related entries, and `plan` holds only their selection;
|
|
44
|
+
* `collection` finds neighbors in an independent sibling scope described by `plan`.
|
|
45
|
+
*/
|
|
46
|
+
type AdjacentPlan = {
|
|
47
|
+
scope: "results" | "collection";
|
|
48
|
+
plan: QueryPlan;
|
|
49
|
+
};
|
|
36
50
|
/** One requested payload; variant keys are empty for payloads without variants. */
|
|
37
51
|
type PlanPayload = {
|
|
38
52
|
variant: Readonly<Record<string, string>>;
|
|
@@ -46,15 +60,29 @@ type QueryRegistry = Record<string, {
|
|
|
46
60
|
/** Payload names available to queries; omitted when the collection has none. */
|
|
47
61
|
payloads?: Record<string, PayloadDescriptor>;
|
|
48
62
|
}>;
|
|
63
|
+
/** Explains the explicit-selection rule wherever a scope returns rows without selecting data. */
|
|
64
|
+
declare const NO_SELECTION_MESSAGE: "Select fields, relationships, payloads, or adjacent entries before running this query.";
|
|
49
65
|
//#endregion
|
|
50
66
|
//#region src/query/types.d.ts
|
|
51
67
|
declare const queryType: unique symbol;
|
|
68
|
+
/** Running an unselected query reports the explicit-selection rule as its required `this` type. */
|
|
69
|
+
type UnselectedTerminal = (this: typeof NO_SELECTION_MESSAGE, ...arguments_: readonly unknown[]) => never;
|
|
70
|
+
/** A `then` that cannot resolve a value, so awaiting an unselected query fails to compile. */
|
|
71
|
+
type UnselectedThen = (selectBeforeAwaiting: typeof NO_SELECTION_MESSAGE) => never;
|
|
52
72
|
declare const fieldType: unique symbol;
|
|
53
73
|
type Field$1<Value> = {
|
|
54
74
|
readonly name: string;
|
|
55
75
|
readonly [fieldType]: Value;
|
|
56
76
|
};
|
|
57
77
|
type Fields<Data> = { readonly [Name in keyof Data]-?: Field$1<Data[Name]>; };
|
|
78
|
+
declare const relationTarget: unique symbol;
|
|
79
|
+
/** A relationship in a fluent `where()` callback, filtered with `has()`. */
|
|
80
|
+
type RelationField<TargetFields> = {
|
|
81
|
+
readonly name: string;
|
|
82
|
+
readonly [relationTarget]: TargetFields;
|
|
83
|
+
};
|
|
84
|
+
/** 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>>>>; };
|
|
58
86
|
type Scalar = string | number | bigint | boolean | Date | null | undefined;
|
|
59
87
|
type ScalarField<Value> = Field$1<Value> & ([Value] extends [Scalar] ? unknown : never);
|
|
60
88
|
type Ordered<Value> = NonNullable<Value> extends string ? unknown : NonNullable<Value> extends number ? unknown : NonNullable<Value> extends bigint ? unknown : NonNullable<Value> extends Date ? unknown : never;
|
|
@@ -82,7 +110,7 @@ type RelationshipResult<Definition, Relation extends Relationship, Result, Filte
|
|
|
82
110
|
type RelationValue<Definition, Relation extends Relationship, Configured> = RelationshipResult<Definition, Relation, ResultOf<Configured>, FilteredOf<Configured>>;
|
|
83
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> & {
|
|
84
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]>> | Keys[number]]: Key extends Keys[number] ? QueryData<Registry[Name]>[Key & keyof QueryData<Registry[Name]>] : Key extends keyof Result ? Result[Key] : never; }, true, Many, Root, Filtered, AllowAdjacent, Pagination>;
|
|
85
|
-
where(configure: (fields:
|
|
113
|
+
where(configure: (fields: QueryFields<Registry, Name>) => Expression): Query<Registry, Name, Result, Selected, Many, Root, true, AllowAdjacent, Pagination>;
|
|
86
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>;
|
|
87
115
|
} & (Many extends true ? {
|
|
88
116
|
orderBy(field: SortKey<QueryData<Registry[Name]>>, direction?: "asc" | "desc"): Query<Registry, Name, Result, Selected, Many, Root, Filtered, AllowAdjacent, Pagination>;
|
|
@@ -91,11 +119,10 @@ type Query<Registry extends CollectionRegistry, Name extends keyof Registry & st
|
|
|
91
119
|
offset(value: number): Query<Registry, Name, Result, Selected, Many, Root, Filtered, AllowAdjacent, Pagination>;
|
|
92
120
|
} : {} : {}) & (AllowAdjacent extends true ? {
|
|
93
121
|
/** Attaches a payload under `_payloads` after filtering, ordering, and pagination. */
|
|
94
|
-
withPayload<Key extends keyof PayloadsOf<Registry[Name]> & string>(name: Key): Query<Registry, Name, WithPayload<Result, Key, PayloadsOf<Registry[Name]>[Key]>,
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}>;
|
|
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>;
|
|
123
|
+
/** Selects neighbor fields within this scope's filtered and ordered results. */
|
|
124
|
+
selectAdjacent<const Keys extends readonly [keyof QueryData<Registry[Name]> & string, ...(keyof QueryData<Registry[Name]> & string)[]]>(...fields: Keys): Query<Registry, Name, Result & {
|
|
125
|
+
_adjacent: Adjacent<{ [Key in Keys[number]]: QueryData<Registry[Name]>[Key & keyof QueryData<Registry[Name]>]; }>;
|
|
99
126
|
}, true, Many, Root, Filtered, AllowAdjacent, Pagination>;
|
|
100
127
|
selectAdjacent<Configured extends QueryInfo<unknown, true>>(configure: (siblings: Query<Registry, Name, {}, false, true, false, false, false, false>) => Configured): Query<Registry, Name, Result & {
|
|
101
128
|
_adjacent: Adjacent<ResultOf<Configured>>;
|
|
@@ -104,11 +131,11 @@ type Query<Registry extends CollectionRegistry, Name extends keyof Registry & st
|
|
|
104
131
|
_adjacent: Adjacent<SelectionResult<Registry, Name, Options["select"]>>;
|
|
105
132
|
}, true, Many, Root, Filtered, AllowAdjacent, Pagination>;
|
|
106
133
|
} : {}) & (Root extends true ? {
|
|
107
|
-
all: Selected extends true ? () => Promise<Simplify$1<Result>[]> :
|
|
108
|
-
execute: Selected extends true ? () => Promise<Simplify$1<Result>[]> :
|
|
109
|
-
then: Selected extends true ? Promise<Simplify$1<Result>[]>["then"] :
|
|
110
|
-
first: Selected extends true ? () => Promise<Simplify$1<Result> | undefined> :
|
|
111
|
-
/** Counts matching entries; unavailable once payloads are requested. */
|
|
134
|
+
all: Selected extends true ? () => Promise<Simplify$1<Result>[]> : UnselectedTerminal;
|
|
135
|
+
execute: Selected extends true ? () => Promise<Simplify$1<Result>[]> : UnselectedTerminal;
|
|
136
|
+
then: Selected extends true ? Promise<Simplify$1<Result>[]>["then"] : UnselectedThen;
|
|
137
|
+
first: Selected extends true ? () => Promise<Simplify$1<Result> | undefined> : UnselectedTerminal;
|
|
138
|
+
/** Counts matching entries without a selection; unavailable once payloads are requested. */
|
|
112
139
|
count: [Result] extends [never] ? () => Promise<number> : [Result] extends [{
|
|
113
140
|
_payloads: unknown;
|
|
114
141
|
}] ? never : () => Promise<number>;
|
|
@@ -149,7 +176,7 @@ type Where<Data> = { [Name in keyof Data]?: [Data[Name]] extends [Scalar] ? Data
|
|
|
149
176
|
};
|
|
150
177
|
type OrderBy<Data> = Partial<Record<SortKey<Data>, "asc" | "desc">>;
|
|
151
178
|
type ObjectScope<Registry extends CollectionRegistry, Name extends keyof Registry & string, Many extends boolean> = {
|
|
152
|
-
where?: Where<QueryData<Registry[Name]>> | ((fields:
|
|
179
|
+
where?: Where<QueryData<Registry[Name]>> | ((fields: QueryFields<Registry, Name>) => Expression);
|
|
153
180
|
} & (Many extends true ? {
|
|
154
181
|
orderBy?: OrderBy<QueryData<Registry[Name]>> | readonly OrderBy<QueryData<Registry[Name]>>[];
|
|
155
182
|
limit?: number;
|
|
@@ -160,20 +187,27 @@ type QueryOptions<Registry extends CollectionRegistry, Name extends keyof Regist
|
|
|
160
187
|
};
|
|
161
188
|
type AdjacentOptions<Registry extends CollectionRegistry, Name extends keyof Registry & string> = Omit<QueryOptions<Registry, Name, true, false>, "limit" | "offset">;
|
|
162
189
|
type Selection<Registry extends CollectionRegistry, Name extends keyof Registry & string, AllowAdjacent extends boolean = true> = { [Field in keyof QueryData<Registry[Name]>]?: boolean; } & { [Key in keyof RelationshipsOf<Registry[Name]>]?: QueryOptions<Registry, RelatedName$1<Registry, RelationOf<Registry, Name, Key>>, RelationOf<Registry, Name, Key>["type"] extends "many" ? true : false, AllowAdjacent> | false; } & (AllowAdjacent extends true ? {
|
|
163
|
-
_adjacent?:
|
|
190
|
+
_adjacent?: {
|
|
191
|
+
scope: "results";
|
|
192
|
+
select: Selection<Registry, Name, false>;
|
|
193
|
+
} | (AdjacentOptions<Registry, Name> & {
|
|
194
|
+
scope?: "collection";
|
|
195
|
+
});
|
|
164
196
|
} : {});
|
|
165
197
|
type ObjectRelationValue<Registry extends CollectionRegistry, Name extends keyof Registry & string, Key extends keyof RelationshipsOf<Registry[Name]>, Options> = Options extends {
|
|
166
198
|
select: infer Projection;
|
|
167
199
|
} ? 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;
|
|
168
|
-
type SelectionResult<Registry extends CollectionRegistry, Name extends keyof Registry & string, Projection> = { -readonly [Key in keyof Projection as Projection[Key] extends false | undefined ? never : Key]-?: Key extends "_adjacent" ? Projection[Key] extends
|
|
169
|
-
id: string;
|
|
170
|
-
}> : Projection[Key] extends {
|
|
200
|
+
type SelectionResult<Registry extends CollectionRegistry, Name extends keyof Registry & string, Projection> = { -readonly [Key in keyof Projection as Projection[Key] extends false | undefined ? never : Key]-?: Key extends "_adjacent" ? Projection[Key] extends {
|
|
171
201
|
select: infer Neighbors;
|
|
172
202
|
} ? Adjacent<SelectionResult<Registry, Name, Neighbors>> : never : Key extends keyof RelationshipsOf<Registry[Name]> ? ObjectRelationValue<Registry, Name, Key, Projection[Key]> : Key extends keyof QueryData<Registry[Name]> ? QueryData<Registry[Name]>[Key] : never; };
|
|
173
203
|
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; };
|
|
174
204
|
type CheckedWhereList$1<Data, Filters extends readonly unknown[]> = { [Index in keyof Filters]: CheckedWhere$1<Data, Filters[Index]>; };
|
|
175
205
|
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; };
|
|
176
|
-
type CheckedSelection<Registry extends CollectionRegistry, Name extends keyof Registry & string, Projection, AllowAdjacent extends boolean> = { [Key in keyof Projection]: Key extends "_adjacent" ? AllowAdjacent extends true ? Projection[Key] extends
|
|
206
|
+
type CheckedSelection<Registry extends CollectionRegistry, Name extends keyof Registry & string, Projection, AllowAdjacent extends boolean> = { [Key in keyof Projection]: Key extends "_adjacent" ? AllowAdjacent extends true ? Projection[Key] extends {
|
|
207
|
+
scope: "results";
|
|
208
|
+
} ? { [Option in keyof Projection[Key]]: Option extends "scope" ? "results" : Option extends "select" ? CheckedSelection<Registry, Name, Projection[Key][Option], false> : never; } : CheckedOptions<Registry, Name, Omit<Projection[Key], "scope">, true, false, false> & {
|
|
209
|
+
scope?: "collection";
|
|
210
|
+
} : never : Key extends keyof RelationshipsOf<Registry[Name]> ? Projection[Key] extends false ? false : CheckedOptions<Registry, RelatedName$1<Registry, RelationOf<Registry, Name, Key>>, Projection[Key], RelationOf<Registry, Name, Key>["type"] extends "many" ? true : false, AllowAdjacent> : Key extends keyof QueryData<Registry[Name]> ? Projection[Key] : never; };
|
|
177
211
|
/** Rejects extra properties throughout inferred options, including recursive neighbor projections. */
|
|
178
212
|
type CheckedOptions<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 "select" ? CheckedSelection<Registry, Name, Options[Key], AllowAdjacent> : Key extends "where" ? CheckedWhere$1<QueryData<Registry[Name]>, Options[Key]> : Key extends "limit" | "offset" ? Pagination extends true ? Many extends true ? Options[Key] : never : never : Key extends keyof ObjectScope<Registry, Name, Many> ? Options[Key] : never; };
|
|
179
213
|
//#endregion
|
|
@@ -221,36 +255,69 @@ type RelationalWhere<Registry extends CollectionRegistry, Name extends keyof Reg
|
|
|
221
255
|
NOT?: RelationalWhere<Registry, Name> | readonly RelationalWhere<Registry, Name>[];
|
|
222
256
|
RAW?: (fields: Fields<QueryData<Registry[Name]>>) => Expression;
|
|
223
257
|
};
|
|
258
|
+
/** Requests one payload: `true` without variants, or a record giving every variant key. */
|
|
259
|
+
type PayloadRequest<Variant> = keyof Variant extends never ? true : Readonly<Variant>;
|
|
224
260
|
/** Payloads to attach under `_payloads`; payloads set to false are omitted. */
|
|
225
|
-
type PayloadOptions<Registry extends CollectionRegistry, Name extends keyof Registry & string> = { [Key in keyof PayloadsOf<Registry[Name]>]?:
|
|
226
|
-
/**
|
|
261
|
+
type PayloadOptions<Registry extends CollectionRegistry, Name extends keyof Registry & string> = { [Key in keyof PayloadsOf<Registry[Name]>]?: false | PayloadRequest<VariantOf<Registry[Name], Key>>; };
|
|
262
|
+
/** Rejects variant keys a payload does not declare, including through inferred variables. */
|
|
263
|
+
type CheckedPayloadRequest<Request, Variant> = Request extends boolean ? Request : { [Key in keyof Request]: Key extends keyof Variant ? string : never; };
|
|
264
|
+
/**
|
|
265
|
+
* Collection-scoped metadata queries with Drizzle-style columns, relationships, and filters.
|
|
266
|
+
* Nothing is selected implicitly, not even `id`: list fields in `columns`, include relationships
|
|
267
|
+
* with nested options, request payloads, or select adjacency.
|
|
268
|
+
*/
|
|
227
269
|
type RelationalQueryOptions<Registry extends CollectionRegistry, Name extends keyof Registry & string, Many extends boolean = true, AllowAdjacent extends boolean = true, Pagination extends boolean = true> = {
|
|
228
|
-
|
|
270
|
+
/** Fields to include, each set to `true`. Omitted fields are never returned. */
|
|
271
|
+
columns?: Partial<Record<keyof QueryData<Registry[Name]>, true>>;
|
|
229
272
|
where?: RelationalWhere<Registry, Name>;
|
|
230
|
-
|
|
273
|
+
/** Related entries to include; each selects its own data. `false` omits a relationship. */
|
|
274
|
+
with?: { [Key in keyof RelationshipsOf<Registry[Name]>]?: false | RelationalQueryOptions<Registry, RelatedName<Registry, Name, Key>, IsMany<Registry, Name, Key>, AllowAdjacent>; };
|
|
231
275
|
} & (Many extends true ? {
|
|
232
276
|
orderBy?: OrderBy<QueryData<Registry[Name]>>;
|
|
233
277
|
} : {}) & (Many extends true ? (Pagination extends true ? {
|
|
234
278
|
limit?: number;
|
|
235
279
|
offset?: number;
|
|
236
280
|
} : {}) : {}) & (AllowAdjacent extends true ? {
|
|
237
|
-
|
|
281
|
+
/**
|
|
282
|
+
* Previous and next entries, which select their own data. `scope: "results"` finds
|
|
283
|
+
* neighbors within these results; other options describe an independent sibling scope.
|
|
284
|
+
*/
|
|
285
|
+
adjacent?: ({
|
|
286
|
+
scope: "results";
|
|
287
|
+
} & Pick<RelationalQueryOptions<Registry, Name, true, false, false>, "columns" | "with">) | ({
|
|
288
|
+
scope?: "collection";
|
|
289
|
+
} & RelationalQueryOptions<Registry, Name, true, false, false>);
|
|
238
290
|
payloads?: PayloadOptions<Registry, Name>;
|
|
239
291
|
} : {});
|
|
240
292
|
/** Options accepted by the root count helper, whose result ignores sorting and pagination. */
|
|
241
293
|
type RelationalCountOptions<Registry extends CollectionRegistry, Name extends keyof Registry & string> = Pick<RelationalQueryOptions<Registry, Name>, "where" | "orderBy" | "offset" | "limit">;
|
|
242
294
|
type ColumnResult<Data, Options> = Options extends {
|
|
243
295
|
columns: infer Columns;
|
|
244
|
-
} ?
|
|
296
|
+
} ? { -readonly [Key in keyof Columns as Columns[Key] extends true ? Key : never]-?: Key extends keyof Data ? Data[Key] : never; } : {};
|
|
297
|
+
/** Keys whose option values request something, as opposed to `false` or `undefined`. */
|
|
298
|
+
type Requested<Map> = keyof { [Key in keyof Map as Map[Key] extends false | undefined ? never : Key]: unknown; };
|
|
299
|
+
/** Whether options select fields, include relationships, request payloads, or select adjacency. */
|
|
300
|
+
type SelectsData<Options> = (Options extends {
|
|
301
|
+
columns: infer Columns;
|
|
302
|
+
} ? Requested<Columns> : never) | (Options extends {
|
|
303
|
+
with: infer Related;
|
|
304
|
+
} ? Requested<Related> : never) | (Options extends {
|
|
305
|
+
payloads: infer Payloads;
|
|
306
|
+
} ? Requested<Payloads> : never) | (Options extends {
|
|
307
|
+
adjacent: infer Neighbors;
|
|
308
|
+
} ? Neighbors extends false | undefined ? never : "adjacent" : never) extends never ? false : true;
|
|
309
|
+
/**
|
|
310
|
+
* Requires a row-returning scope to request data. An unselected scope must supply an impossible
|
|
311
|
+
* property named after the rule, so the compiler error states it.
|
|
312
|
+
*/
|
|
313
|
+
type SelectionRequired<Options> = SelectsData<Options> extends true ? unknown : { [Rule in typeof NO_SELECTION_MESSAGE]: never; };
|
|
245
314
|
type IncludedResult<Registry extends CollectionRegistry, Name extends keyof Registry & string, Options> = Options extends {
|
|
246
315
|
with: infer Related;
|
|
247
|
-
} ? { -readonly [Key in keyof Related as Related[Key] extends false | undefined ? never : Key]-?: Key extends keyof RelationshipsOf<Registry[Name]> ? RelationshipResult<Registry[Name], RelationshipsOf<Registry[Name]>[Key] & Relationship, RelationalQueryResult<Registry, RelatedName<Registry, Name, Key>, Related[Key]
|
|
316
|
+
} ? { -readonly [Key in keyof Related as Related[Key] extends false | undefined ? never : Key]-?: Key extends keyof RelationshipsOf<Registry[Name]> ? RelationshipResult<Registry[Name], RelationshipsOf<Registry[Name]>[Key] & Relationship, RelationalQueryResult<Registry, RelatedName<Registry, Name, Key>, Related[Key]>, "where" extends keyof Related[Key] ? true : false> : never; } : {};
|
|
248
317
|
type AdjacentResult<Registry extends CollectionRegistry, Name extends keyof Registry & string, Options> = Options extends {
|
|
249
318
|
adjacent: infer Neighbors;
|
|
250
319
|
} ? {
|
|
251
|
-
_adjacent:
|
|
252
|
-
id: string;
|
|
253
|
-
}> : Adjacent<RelationalQueryResult<Registry, Name, Neighbors>>;
|
|
320
|
+
_adjacent: Adjacent<RelationalQueryResult<Registry, Name, Neighbors>>;
|
|
254
321
|
} : {};
|
|
255
322
|
type Simplify<Value> = { [Key in keyof Value]: Value[Key]; };
|
|
256
323
|
type RequestedPayloads<Payloads, Requested> = { -readonly [Key in keyof Requested as Requested[Key] extends false | undefined ? never : Key]-?: Key extends keyof Payloads ? Payloads[Key] : never; };
|
|
@@ -259,20 +326,28 @@ type PayloadResult<Registry extends CollectionRegistry, Name extends keyof Regis
|
|
|
259
326
|
} ? keyof RequestedPayloads<PayloadsOf<Registry[Name]>, Requested> extends never ? {} : {
|
|
260
327
|
_payloads: Simplify<RequestedPayloads<PayloadsOf<Registry[Name]>, Requested>>;
|
|
261
328
|
} : {};
|
|
262
|
-
/** Infers selected columns
|
|
329
|
+
/** Infers exactly the selected columns, relationships, adjacency, and payloads. */
|
|
263
330
|
type RelationalQueryResult<Registry extends CollectionRegistry, Name extends keyof Registry & string, Options> = Options extends unknown ? Simplify<ColumnResult<QueryData<Registry[Name]>, Options> & IncludedResult<Registry, Name, Options> & AdjacentResult<Registry, Name, Options> & PayloadResult<Registry, Name, Options>> : never;
|
|
264
331
|
type CheckedConditions<Value, Filters extends readonly unknown[]> = { [Index in keyof Filters]: CheckedCondition<Value, Filters[Index]>; };
|
|
265
332
|
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; };
|
|
266
333
|
type CheckedWhereList<Registry extends CollectionRegistry, Name extends keyof Registry & string, Filters extends readonly unknown[]> = { [Index in keyof Filters]: CheckedWhere<Registry, Name, Filters[Index]>; };
|
|
267
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]> : never; };
|
|
268
335
|
/** Rejects unknown options recursively, including options supplied through inferred variables. */
|
|
269
|
-
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
|
|
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]> : never; } : Key extends "adjacent" ? AllowAdjacent extends true ? CheckedRelationalOptions<Registry, Name, Omit<Options[Key], "scope">, true, false, false> & SelectionRequired<Options[Key]> & (Options[Key] extends {
|
|
337
|
+
scope: "results";
|
|
338
|
+
} ? {
|
|
339
|
+
scope: "results";
|
|
340
|
+
where?: never;
|
|
341
|
+
orderBy?: never;
|
|
342
|
+
} : {
|
|
343
|
+
scope?: "collection";
|
|
344
|
+
}) : 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; };
|
|
270
345
|
/** Typed per-collection query entry points that never expose source configuration at runtime. */
|
|
271
346
|
type RelationalQueries<Registry extends CollectionRegistry> = string extends keyof Registry ? {} : { readonly [Name in keyof Registry & string]: {
|
|
272
|
-
/** Returns matching
|
|
273
|
-
findMany<const Options extends RelationalQueryOptions<Registry, Name
|
|
274
|
-
/** Returns the first matching
|
|
275
|
-
findFirst<const Options extends RelationalQueryOptions<Registry, Name
|
|
347
|
+
/** Returns matching rows with exactly the selected data. Options must select something. */
|
|
348
|
+
findMany<const Options extends RelationalQueryOptions<Registry, Name>>(options: Options & CheckedRelationalOptions<Registry, Name, NoInfer<Options>> & SelectionRequired<NoInfer<Options>>): Promise<RelationalQueryResult<Registry, Name, Options>[]>;
|
|
349
|
+
/** Returns the first matching row, or undefined when none matches. */
|
|
350
|
+
findFirst<const Options extends RelationalQueryOptions<Registry, Name>>(options: Options & CheckedRelationalOptions<Registry, Name, NoInfer<Options>> & SelectionRequired<NoInfer<Options>>): Promise<RelationalQueryResult<Registry, Name, Options> | undefined>;
|
|
276
351
|
}; };
|
|
277
352
|
//#endregion
|
|
278
|
-
export {
|
|
353
|
+
export { Where as _, RelationalWhere as a, QueryRegistry as b, Fields as c, QueryFields as d, RelationField as f, SelectionResult as g, Selection as h, RelationalQueryResult as i, Ordered as l, ScalarField as m, RelationalQueries as n, Adjacent as o, Scalar as p, RelationalQueryOptions as r, Field$1 as s, RelationalCountOptions as t, Query as u, Expression as v, QueryPlan as y };
|
package/dist/runtime.d.mts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import { a as ContentDiagnostic, o as ContentError, s as ContentErrorCode, t as Content } from "./content-
|
|
1
|
+
import { a as ContentDiagnostic, o as ContentError, s as ContentErrorCode, t as Content } from "./content-CwTKqRs9.mjs";
|
|
2
2
|
import { n as ContentRenderResult, t as ContentHeading } from "./types-Dh-Sydyw.mjs";
|
|
3
|
-
|
|
3
|
+
import { n as QueryStyle, r as QueryStyleDisabled } from "./query-style-eXENQJ0O.mjs";
|
|
4
|
+
export { type Content, type ContentDiagnostic, ContentError, type ContentErrorCode, type ContentHeading, type ContentRenderResult, type QueryStyle, type QueryStyleDisabled };
|
package/dist/runtime.mjs
CHANGED