@query-graph/core 1.1.4 → 1.1.5
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 +95 -969
- package/definition.d.ts +11 -0
- package/definition.js +1 -2
- package/docs/authoring.md +161 -0
- package/docs/composition.md +100 -0
- package/docs/diagnostics.md +52 -0
- package/docs/sql.md +68 -0
- package/docs/type-system.md +86 -0
- package/dsl.d.ts +182 -1839
- package/dsl.js +57 -763
- package/index.d.ts +8 -100
- package/index.js +13 -568
- package/lib/authoring/definition.js +425 -0
- package/lib/authoring/primitives.js +433 -0
- package/lib/authoring/symbols.js +4 -0
- package/{composition.js → lib/composition.js} +9 -35
- package/lib/configuration.js +66 -0
- package/native.d.ts +98 -0
- package/native.js +714 -0
- package/package.json +16 -11
- package/types/authoring.d.ts +667 -0
- package/types/composition.d.ts +327 -0
- package/types/model.d.ts +425 -0
- package/types/result.d.ts +394 -0
- package/types/runtime.d.ts +168 -0
package/definition.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @deprecated Import the object authoring API from `@query-graph/core/dsl`.
|
|
3
|
+
* This compatibility entrypoint will be removed in 2.0.
|
|
4
|
+
*/
|
|
1
5
|
export * from './dsl.js'
|
|
2
6
|
|
|
3
7
|
import type {
|
|
@@ -25,8 +29,10 @@ import type {
|
|
|
25
29
|
TypedProjectionField,
|
|
26
30
|
} from './dsl.js'
|
|
27
31
|
|
|
32
|
+
/** @deprecated Import authoring primitives from `@query-graph/core/dsl`. */
|
|
28
33
|
export const GRAPH_DEFINITION_VERSION: 10
|
|
29
34
|
|
|
35
|
+
/** @deprecated Use `source.field(name)` from `@query-graph/core/dsl`. */
|
|
30
36
|
export function field<
|
|
31
37
|
const Key extends string,
|
|
32
38
|
const Fields extends FieldSpecMap,
|
|
@@ -53,6 +59,7 @@ export interface RelationOptions<
|
|
|
53
59
|
selection?: RelationSelection
|
|
54
60
|
}
|
|
55
61
|
|
|
62
|
+
/** @deprecated Use `relation({ name, from, to, on, ...options })`. */
|
|
56
63
|
export function relation<
|
|
57
64
|
const Name extends string,
|
|
58
65
|
const From extends string | SourceRef,
|
|
@@ -71,12 +78,14 @@ export interface ConstraintOptions {
|
|
|
71
78
|
when?: string | ParameterRef
|
|
72
79
|
}
|
|
73
80
|
|
|
81
|
+
/** @deprecated Use `constraint({ predicate, when })`. */
|
|
74
82
|
export function constraint(predicate: Expression, options?: ConstraintOptions): ConstraintDefinition
|
|
75
83
|
|
|
76
84
|
export interface ProjectionOptions<SelectedByDefault extends boolean = boolean> {
|
|
77
85
|
default?: SelectedByDefault
|
|
78
86
|
}
|
|
79
87
|
|
|
88
|
+
/** @deprecated Use `project({ path, expression, default })`. */
|
|
80
89
|
export function project<
|
|
81
90
|
const Path extends string,
|
|
82
91
|
const Value extends ExpressionInput,
|
|
@@ -106,6 +115,7 @@ export function project<
|
|
|
106
115
|
SelectedByDefault
|
|
107
116
|
>
|
|
108
117
|
|
|
118
|
+
/** @deprecated Use `dimension({ path, expression, default })`. */
|
|
109
119
|
export function dimension<
|
|
110
120
|
const Path extends string,
|
|
111
121
|
const Value extends ExpressionInput,
|
|
@@ -135,6 +145,7 @@ export function dimension<
|
|
|
135
145
|
SelectedByDefault
|
|
136
146
|
>
|
|
137
147
|
|
|
148
|
+
/** @deprecated Use `measure({ path, expression, default })`. */
|
|
138
149
|
export function measure<
|
|
139
150
|
const Path extends string,
|
|
140
151
|
const Value extends ExpressionInput,
|
package/definition.js
CHANGED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Authoring DSL
|
|
2
|
+
|
|
3
|
+
Authoring API находится в <code>@query-graph/core/dsl</code>. Он создает
|
|
4
|
+
семантический definition версии 10, который не содержит таблиц, SQL aliases или
|
|
5
|
+
синтаксиса диалекта.
|
|
6
|
+
|
|
7
|
+
## Sources и поля
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { fieldType, hidden, nullable, source } from '@query-graph/core/dsl'
|
|
11
|
+
|
|
12
|
+
const users = source('users', {
|
|
13
|
+
id: 'int64',
|
|
14
|
+
email: nullable('string'),
|
|
15
|
+
internalRank: hidden(fieldType('int32', { nullable: true })),
|
|
16
|
+
})
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Поле имеет scalar type, nullability и флаг selectable. Hidden-поля можно
|
|
20
|
+
использовать в constraints и relations, но нельзя вывести в projection.
|
|
21
|
+
|
|
22
|
+
## Параметры
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
const id = requiredParameter('id', 'int64')
|
|
26
|
+
const status = optionalParameter('status', 'string')
|
|
27
|
+
const ids = requiredListParameter('ids', 'int64')
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Scalar parameter используется через <code>param</code>, list parameter через
|
|
31
|
+
<code>inParameter</code>. Optional parameter не активирует constraint с
|
|
32
|
+
<code>when</code>, пока значение отсутствует.
|
|
33
|
+
|
|
34
|
+
## Expressions
|
|
35
|
+
|
|
36
|
+
DSL предоставляет сравнения, boolean groups, null tests, semantic functions,
|
|
37
|
+
агрегаты и literals:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
const predicate = and(eq(users.field('organisationId'), param(organisationId)), isNull(users.field('dateDelete')))
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Типы operands проверяются TypeScript во время authoring и повторно Rust при
|
|
44
|
+
регистрации.
|
|
45
|
+
|
|
46
|
+
## Relations
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
const profileRelation = relation({
|
|
50
|
+
name: 'profile',
|
|
51
|
+
from: users,
|
|
52
|
+
to: profiles,
|
|
53
|
+
on: eq(users.field('id'), profiles.field('userId')),
|
|
54
|
+
cardinality: 'one',
|
|
55
|
+
required: false,
|
|
56
|
+
selection: firstBy(asc(profiles.field('id'))),
|
|
57
|
+
})
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
- <code>cardinality</code> описывает форму связи: <code>one</code> или
|
|
61
|
+
<code>many</code>.
|
|
62
|
+
- <code>required</code> определяет, может ли отсутствие связанной строки удалить
|
|
63
|
+
root из результата.
|
|
64
|
+
- <code>firstBy</code> детерминированно выбирает одну строку среди кандидатов и
|
|
65
|
+
компилируется через dialect-specific APPLY/LATERAL семантику.
|
|
66
|
+
|
|
67
|
+
У каждого source должен быть единственный путь от root. Planner использует этот
|
|
68
|
+
инвариант для минимального набора JOIN.
|
|
69
|
+
|
|
70
|
+
## Constraints и exists
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
constraint({
|
|
74
|
+
when: organisationId,
|
|
75
|
+
predicate: eq(users.field('organisationId'), param(organisationId)),
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
constraint({
|
|
79
|
+
predicate: exists(memberships, eq(memberships.field('active'), true)),
|
|
80
|
+
})
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
<code>exists</code> является semijoin: он фильтрует множество root и не
|
|
84
|
+
материализует many relation. В relation predicate корреляция задается явно:
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
exists(flags, flagPredicate, { from: profiles })
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Projection и presence
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
const projection = [
|
|
94
|
+
project({ path: 'id', expression: users.field('id'), default: true }),
|
|
95
|
+
projectObject({ path: 'profile', presence: profiles.field('id') }),
|
|
96
|
+
project({
|
|
97
|
+
path: 'profile.name',
|
|
98
|
+
expression: profiles.field('name'),
|
|
99
|
+
default: true,
|
|
100
|
+
}),
|
|
101
|
+
]
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
<code>projectObject</code> позволяет executor отличить отсутствующий to-one
|
|
105
|
+
объект от существующего объекта, все поля которого равны NULL.
|
|
106
|
+
|
|
107
|
+
## Ordering
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
const byName = ordering({
|
|
111
|
+
name: 'nameAsc',
|
|
112
|
+
by: [asc(users.field('name'), { nulls: 'last' })],
|
|
113
|
+
default: true,
|
|
114
|
+
})
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Operation выбирает ordering по имени. SQL expression остается частью
|
|
118
|
+
definition, поэтому потребитель не передает произвольный ORDER BY.
|
|
119
|
+
|
|
120
|
+
## GraphModule
|
|
121
|
+
|
|
122
|
+
<code>defineGraphModule</code> объединяет sources, parameters, relations,
|
|
123
|
+
constraints, projection objects и orderings без собственного root:
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
const auditModule = defineGraphModule({
|
|
127
|
+
name: 'audit',
|
|
128
|
+
sources: [audit],
|
|
129
|
+
relations: [auditRelation],
|
|
130
|
+
projection: [createdAtProjection],
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
const definition = defineGraph({
|
|
134
|
+
name: 'users',
|
|
135
|
+
root: users,
|
|
136
|
+
modules: [auditModule],
|
|
137
|
+
sources: [users],
|
|
138
|
+
projection: [idProjection],
|
|
139
|
+
})
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Повторно подключенный тот же constraint object дедуплицируется по identity.
|
|
143
|
+
Конфликтующие sources, parameters, relations и projection paths отклоняются.
|
|
144
|
+
|
|
145
|
+
## Summary
|
|
146
|
+
|
|
147
|
+
<code>defineSummaryGraph</code> принимает dimensions и measures:
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
const summary = defineSummaryGraph({
|
|
151
|
+
name: 'ordersByStatus',
|
|
152
|
+
root: orders,
|
|
153
|
+
sources: [orders],
|
|
154
|
+
dimensions: [dimension({ path: 'status', expression: orders.field('status'), default: true })],
|
|
155
|
+
measures: [measure({ path: 'count', expression: count(), default: true })],
|
|
156
|
+
})
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Dimensions становятся GROUP BY, aggregate constraints становятся HAVING. Rust
|
|
160
|
+
отклоняет nested aggregates, неагрегированные поля вне dimensions и независимые
|
|
161
|
+
many-ветви, которым нужен отдельный aggregate subquery plan.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Composition
|
|
2
|
+
|
|
3
|
+
В query-graph есть два разных вида композиции.
|
|
4
|
+
|
|
5
|
+
- <code>GraphModule</code> расширяет один SQL-граф до регистрации.
|
|
6
|
+
- <code>batchRelation</code> связывает уже зарегистрированные графы несколькими
|
|
7
|
+
SQL-запросами.
|
|
8
|
+
|
|
9
|
+
## Когда использовать GraphModule
|
|
10
|
+
|
|
11
|
+
GraphModule подходит, когда данные безопасно входят в один relational plan:
|
|
12
|
+
to-one связи, общие constraints, набор projection fields или ordering.
|
|
13
|
+
|
|
14
|
+
Many-связь в одном SQL может размножить root-строки и нарушить пагинацию. Для
|
|
15
|
+
таких полей нужен batch.
|
|
16
|
+
|
|
17
|
+
## Batch query
|
|
18
|
+
|
|
19
|
+
Child-модуль один раз закрепляет контракт ключа:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
const itemIds = requiredListParameter('itemIds', 'int64')
|
|
23
|
+
|
|
24
|
+
const childrenQuery = batchQuery({
|
|
25
|
+
graph: childrenGraph,
|
|
26
|
+
key: {
|
|
27
|
+
path: 'itemId',
|
|
28
|
+
parameter: itemIds,
|
|
29
|
+
},
|
|
30
|
+
})
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
<code>key.path</code> должен быть projection child-графа.
|
|
34
|
+
<code>key.parameter</code> должен быть list parameter того же scalar type.
|
|
35
|
+
|
|
36
|
+
## Batch relation
|
|
37
|
+
|
|
38
|
+
Root-граф подключает child query:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
const children = batchRelation({
|
|
42
|
+
name: 'children',
|
|
43
|
+
from: 'id',
|
|
44
|
+
query: childrenQuery,
|
|
45
|
+
cardinality: 'many',
|
|
46
|
+
parameters: {
|
|
47
|
+
state: 'active',
|
|
48
|
+
},
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
const graph = composeGraph({
|
|
52
|
+
root: rootGraph,
|
|
53
|
+
relations: [children],
|
|
54
|
+
})
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
<code>from</code> является projection path root-графа. Static parameters
|
|
58
|
+
проверяются при композиции. Сам list parameter ключей в <code>parameters</code>
|
|
59
|
+
передавать нельзя: compiled plan заполняет его автоматически.
|
|
60
|
+
|
|
61
|
+
## Компиляция плана
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
const plan = graph.compileOraclePlan({
|
|
65
|
+
select: ['id', 'children.id', 'children.name'],
|
|
66
|
+
parameters: rootParameters,
|
|
67
|
+
})
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Planner:
|
|
71
|
+
|
|
72
|
+
1. отделяет root selection от child selections;
|
|
73
|
+
2. добавляет root key в select, если потребитель его не запросил;
|
|
74
|
+
3. добавляет child key в child select;
|
|
75
|
+
4. компилирует только root statement;
|
|
76
|
+
5. возвращает metadata выбранных batch steps.
|
|
77
|
+
|
|
78
|
+
Batch relation не компилируется и не выполняется, если ее поля не выбраны.
|
|
79
|
+
|
|
80
|
+
## Deferred batch
|
|
81
|
+
|
|
82
|
+
После выполнения root executor собирает уникальные ключи и компилирует один
|
|
83
|
+
child statement:
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
for (const batch of plan.batches) {
|
|
87
|
+
const keys = collectKeys(rootRows, batch.parentKey)
|
|
88
|
+
const statement = plan.compileBatch(batch.name, keys)
|
|
89
|
+
const childRows = await driver.query(statement.sql, bind(statement, keys))
|
|
90
|
+
attach(rootRows, childRows, batch)
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
При <code>cardinality: 'many'</code> executor присоединяет массив. При
|
|
95
|
+
<code>cardinality: 'one'</code> он присоединяет объект или NULL. Cardinality
|
|
96
|
+
описывает результат, а не количество SQL-запросов.
|
|
97
|
+
|
|
98
|
+
Metadata сообщает <code>parentKeyInjected</code> и
|
|
99
|
+
<code>childKeyInjected</code>. Executor может удалить технически добавленные
|
|
100
|
+
ключи после сборки результата.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Diagnostics
|
|
2
|
+
|
|
3
|
+
Ошибки Node API представлены как <code>QueryGraphError</code>:
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
try {
|
|
7
|
+
registerDefinition(definition)
|
|
8
|
+
} catch (error) {
|
|
9
|
+
if (error instanceof Error && error.name === 'QueryGraphError') {
|
|
10
|
+
console.table(error.issues)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Поля ошибки:
|
|
16
|
+
|
|
17
|
+
- <code>name</code>: всегда <code>QueryGraphError</code>;
|
|
18
|
+
- <code>phase</code>: definition, mapping, composition, operation или sql;
|
|
19
|
+
- <code>code</code>: основной код ошибки;
|
|
20
|
+
- <code>issues</code>: все diagnostics текущей фазы.
|
|
21
|
+
|
|
22
|
+
Каждый diagnostic содержит stable code, location и message. Location указывает
|
|
23
|
+
на wire path, например
|
|
24
|
+
<code>relations[1].selection.orderBy[0].expression</code>.
|
|
25
|
+
|
|
26
|
+
## Границы проверки
|
|
27
|
+
|
|
28
|
+
JavaScript DSL выполняет shallow validation сразу:
|
|
29
|
+
|
|
30
|
+
- configuration должна быть object;
|
|
31
|
+
- неизвестные ключи отклоняются;
|
|
32
|
+
- boolean и enum options проверяются до построения wire object;
|
|
33
|
+
- пустые обязательные строки отклоняются.
|
|
34
|
+
|
|
35
|
+
Rust выполняет semantic validation:
|
|
36
|
+
|
|
37
|
+
- уникальность и topology;
|
|
38
|
+
- ссылки и expression scope;
|
|
39
|
+
- scalar types и parameter shapes;
|
|
40
|
+
- projection conflicts и visibility;
|
|
41
|
+
- aggregate semantics;
|
|
42
|
+
- mapping completeness;
|
|
43
|
+
- operation select, ordering и parameter values.
|
|
44
|
+
|
|
45
|
+
Такое разделение дает ранние ошибки опечаток, не дублируя planner rules в
|
|
46
|
+
JavaScript.
|
|
47
|
+
|
|
48
|
+
## Совместимость diagnostics
|
|
49
|
+
|
|
50
|
+
Wire schema остается версии 10. В совместимых выпусках сохраняются diagnostic
|
|
51
|
+
codes и locations. Message предназначен человеку и не должен использоваться как
|
|
52
|
+
machine-readable contract.
|
package/docs/sql.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# SQL Compilation
|
|
2
|
+
|
|
3
|
+
Definition не содержит физическую схему БД. Mapping добавляется после
|
|
4
|
+
регистрации:
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
const graph = registerDefinition(definition).withRelationalMapping({
|
|
8
|
+
sources: {
|
|
9
|
+
users: {
|
|
10
|
+
table: { catalog: 'app', schema: 'dbo', name: 'Users' },
|
|
11
|
+
columns: { displayName: 'display_name' },
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
})
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Можно передать несколько fragments через
|
|
18
|
+
<code>withRelationalMappings</code>. Одинаковые mappings объединяются,
|
|
19
|
+
конфликтующие table/column names возвращают ошибку фазы mapping.
|
|
20
|
+
|
|
21
|
+
## Диалекты
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
const sqlServer = graph.compileSqlServer(operation, { version: '2022' })
|
|
25
|
+
const oracle = graph.compileOracle(operation, { version: '19c' })
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Поддерживаемые версии:
|
|
29
|
+
|
|
30
|
+
- SQL Server: 2008, 2012, 2016, 2019, 2022;
|
|
31
|
+
- Oracle: 11g, 12c, 19c, 21c, 23ai.
|
|
32
|
+
|
|
33
|
+
Version capabilities проверяются до возврата SQL. Например, pagination и
|
|
34
|
+
<code>firstBy</code> могут требовать более новую версию диалекта.
|
|
35
|
+
|
|
36
|
+
## Bindings
|
|
37
|
+
|
|
38
|
+
Compiler никогда не вставляет operation values в SQL. Каждый binding содержит:
|
|
39
|
+
|
|
40
|
+
- SQL placeholder name;
|
|
41
|
+
- имя parameter;
|
|
42
|
+
- scalar type;
|
|
43
|
+
- index элемента для list parameter.
|
|
44
|
+
|
|
45
|
+
Повторное использование parameter переиспользует binding. Пустой list
|
|
46
|
+
компилируется в ложное условие без placeholders.
|
|
47
|
+
|
|
48
|
+
## Result metadata
|
|
49
|
+
|
|
50
|
+
SQL columns получают технические aliases <code>c0</code>,
|
|
51
|
+
<code>c1</code> и так далее. <code>statement.columns</code> хранит logical path,
|
|
52
|
+
scalar type, nullability и relation path. <code>statement.objects</code> хранит
|
|
53
|
+
presence columns для nullable объектов.
|
|
54
|
+
|
|
55
|
+
Executor должен опираться на metadata, а не анализировать SQL.
|
|
56
|
+
|
|
57
|
+
## Граница исполнения
|
|
58
|
+
|
|
59
|
+
query-graph не владеет:
|
|
60
|
+
|
|
61
|
+
- connection pool и transaction;
|
|
62
|
+
- timeout, cancellation и retry;
|
|
63
|
+
- tracing и logging;
|
|
64
|
+
- преобразованием driver-specific bind values;
|
|
65
|
+
- hydration rows и batch attachment.
|
|
66
|
+
|
|
67
|
+
Эти обязанности остаются у приложения. Один и тот же graph можно использовать
|
|
68
|
+
с разными executors, пока они соблюдают контракт statement metadata.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Type System
|
|
2
|
+
|
|
3
|
+
TypeScript помогает автору до регистрации, Rust остается авторитетной runtime
|
|
4
|
+
проверкой wire definition.
|
|
5
|
+
|
|
6
|
+
## Scalar types
|
|
7
|
+
|
|
8
|
+
| Scalar | Operation value | Результат по умолчанию |
|
|
9
|
+
| ------------------------------ | ----------------- | ---------------------- |
|
|
10
|
+
| boolean | boolean | boolean |
|
|
11
|
+
| int32, float64 | number | number |
|
|
12
|
+
| int64, decimal | number или string | number или string |
|
|
13
|
+
| string, date, dateTime, binary | string | string |
|
|
14
|
+
| json | JSON value | JSON value |
|
|
15
|
+
|
|
16
|
+
<code>int64</code> принимает number только в безопасном диапазоне JavaScript.
|
|
17
|
+
Decimal string проверяется как конечная десятичная запись.
|
|
18
|
+
|
|
19
|
+
## QueryOperation
|
|
20
|
+
|
|
21
|
+
Definition передает свои параметры, projection paths и ordering names в
|
|
22
|
+
operation:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
const operation = {
|
|
26
|
+
select: ['id', 'profile.name'],
|
|
27
|
+
ordering: 'nameAsc',
|
|
28
|
+
parameters: {
|
|
29
|
+
organisationId: 42,
|
|
30
|
+
},
|
|
31
|
+
} as const satisfies QueryOperation<typeof definition>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Required parameters обязательны, optional параметры могут отсутствовать,
|
|
35
|
+
list parameters принимают readonly arrays.
|
|
36
|
+
|
|
37
|
+
## Nullability
|
|
38
|
+
|
|
39
|
+
Nullability выражения складывается из:
|
|
40
|
+
|
|
41
|
+
- nullable исходного поля;
|
|
42
|
+
- optional relation на пути к source;
|
|
43
|
+
- семантики функции;
|
|
44
|
+
- projection object presence.
|
|
45
|
+
|
|
46
|
+
Required relation под optional ancestor остается nullable. Это свойство
|
|
47
|
+
вычисляется из topology один раз при регистрации.
|
|
48
|
+
|
|
49
|
+
## ResultOf
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
type Row = ResultOf<typeof definition, typeof operation>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
<code>ResultOf</code> строит вложенный объект из выбранных projection paths.
|
|
56
|
+
Если operation не передана, используются поля с <code>default: true</code>.
|
|
57
|
+
Для composed graph выбранные batch relations добавляются как массивы либо
|
|
58
|
+
nullable объекты согласно cardinality.
|
|
59
|
+
|
|
60
|
+
Driver может заменить представление scalar values:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
interface DriverScalars extends DefaultScalarOutputTypeMap {
|
|
64
|
+
int64: bigint
|
|
65
|
+
decimal: string
|
|
66
|
+
dateTime: Date
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
type DriverRow = ResultOf<typeof definition, typeof operation, DriverScalars>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Этот mapping существует только на уровне TypeScript. Wire schema и SQL
|
|
73
|
+
compilation не меняются.
|
|
74
|
+
|
|
75
|
+
## Runtime checker
|
|
76
|
+
|
|
77
|
+
Rust проверяет:
|
|
78
|
+
|
|
79
|
+
- ссылки на sources, fields и parameters;
|
|
80
|
+
- scalar/list shape параметров;
|
|
81
|
+
- совместимость сравнений и функций;
|
|
82
|
+
- boolean тип predicates;
|
|
83
|
+
- orderable и groupable expressions;
|
|
84
|
+
- aggregate context и concrete projection types.
|
|
85
|
+
|
|
86
|
+
Ошибки собираются в diagnostics с location исходного definition.
|