@aventara/core 1.0.0-rc.1 → 1.0.0-rc.11
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/CHANGELOG.md +1022 -16
- package/ERRORS.md +142 -0
- package/README.md +330 -16
- package/dist/adapters/adapter-discovery-diagnostic.guidance.d.ts +6 -0
- package/dist/adapters/adapter-discovery-diagnostic.guidance.js +7 -0
- package/dist/adapters/adapter-field.d.ts +22 -0
- package/dist/adapters/adapter-identifier.d.ts +9 -0
- package/dist/adapters/adapter-identifier.js +6 -1
- package/dist/adapters/adapter-model.d.ts +9 -0
- package/dist/adapters/adapter-operation.d.ts +18 -3
- package/dist/adapters/adapter-resource.d.ts +5 -0
- package/dist/adapters/adapter.interface.d.ts +10 -0
- package/dist/avz/avz.d.ts +1 -1
- package/dist/avz/json-shape.registry.d.ts +2 -1
- package/dist/compiler/contract-compiler-diagnostic.guidance.d.ts +6 -0
- package/dist/compiler/contract-compiler-diagnostic.guidance.js +97 -0
- package/dist/compiler/contract.compiler.d.ts +6 -0
- package/dist/compiler/contract.compiler.js +281 -31
- package/dist/compiler/create-requirements.projector.js +1 -3
- package/dist/compiler/field-validator.compiler.js +1 -3
- package/dist/compiler/managed-elsewhere.projector.d.ts +52 -0
- package/dist/compiler/managed-elsewhere.projector.js +179 -0
- package/dist/compiler/managed-elsewhere.validator.d.ts +9 -0
- package/dist/compiler/managed-elsewhere.validator.js +74 -0
- package/dist/config/cache-stage.factory.d.ts +24 -0
- package/dist/config/cache-stage.factory.js +3 -0
- package/dist/config/computed-fields.d.ts +62 -0
- package/dist/config/computed-fields.js +73 -0
- package/dist/config/config-diagnostic.guidance.d.ts +6 -0
- package/dist/config/config-diagnostic.guidance.js +32 -0
- package/dist/config/config.resolver.d.ts +24 -0
- package/dist/config/config.resolver.js +66 -7
- package/dist/config/config.validator.js +283 -21
- package/dist/config/define-resource.d.ts +1 -5
- package/dist/config/entrypoint.normalizer.d.ts +3 -2
- package/dist/config/exact-framework-config.d.ts +73 -22
- package/dist/config/field-compute.resolver.d.ts +2 -0
- package/dist/config/field-compute.resolver.js +9 -3
- package/dist/config/framework-config.d.ts +53 -15
- package/dist/config/framework-resources-config.d.ts +25 -14
- package/dist/config/pipeline-config.d.ts +20 -4
- package/dist/config/pipeline-tree.resolver.d.ts +2 -2
- package/dist/config/pipeline-tree.resolver.js +2 -3
- package/dist/contracts/access-route.rules.d.ts +10 -0
- package/dist/contracts/access-route.rules.js +45 -0
- package/dist/contracts/canonical-json.writer.d.ts +7 -0
- package/dist/contracts/canonical-json.writer.js +55 -0
- package/dist/contracts/capability.d.ts +26 -1
- package/dist/contracts/capability.js +20 -0
- package/dist/contracts/client-contract-structure.validator.d.ts +365 -89
- package/dist/contracts/client-contract-structure.validator.js +49 -2
- package/dist/contracts/contract-access.d.ts +29 -0
- package/dist/contracts/contract-access.js +1 -0
- package/dist/contracts/contract-canonicalizer.d.ts +9 -1
- package/dist/contracts/contract-canonicalizer.js +35 -4
- package/dist/contracts/contract-hash.d.ts +0 -1
- package/dist/contracts/contract-hash.js +1 -1
- package/dist/contracts/contract-limits.d.ts +6 -0
- package/dist/contracts/contract-limits.js +2 -0
- package/dist/contracts/contract.d.ts +42 -1
- package/dist/contracts/field.d.ts +58 -1
- package/dist/contracts/json-schema.projector.d.ts +11 -0
- package/dist/contracts/json-schema.projector.js +76 -0
- package/dist/contracts/scalar-value-type.d.ts +3 -1
- package/dist/framework/access-facade.d.ts +116 -0
- package/dist/framework/access-facade.js +118 -0
- package/dist/framework/contract-view.d.ts +120 -16
- package/dist/framework/framework-construction.error.d.ts +14 -4
- package/dist/framework/framework-construction.error.js +18 -2
- package/dist/framework/framework.d.ts +26 -5
- package/dist/framework/framework.factory.d.ts +1 -1
- package/dist/framework/framework.factory.js +145 -24
- package/dist/framework/operation-facade.d.ts +141 -13
- package/dist/framework/operation-facade.js +9 -1
- package/dist/framework/operation-set.runner.d.ts +47 -0
- package/dist/framework/operation-set.runner.js +168 -0
- package/dist/index.d.ts +19 -5
- package/dist/index.js +3 -0
- package/dist/internal.d.ts +9 -2
- package/dist/internal.js +8 -0
- package/dist/operations/database-refusal.d.ts +51 -0
- package/dist/operations/database-refusal.js +45 -0
- package/dist/operations/operation-arguments.d.ts +148 -60
- package/dist/operations/operation-call.d.ts +9 -5
- package/dist/operations/operation-result.d.ts +6 -4
- package/dist/operations/operation-validator-core.js +160 -39
- package/dist/operations/operation-validator.d.ts +1 -1
- package/dist/operations/structural-limits.walker.d.ts +1 -1
- package/dist/operations/structural-limits.walker.js +1 -3
- package/dist/operations/validation-code.guidance.d.ts +6 -0
- package/dist/operations/validation-code.guidance.js +90 -0
- package/dist/operations/write-scope.resolver.d.ts +4 -0
- package/dist/operations/write-scope.resolver.js +2 -0
- package/dist/policy/access-provider.interface.d.ts +91 -0
- package/dist/policy/access-provider.interface.js +1 -0
- package/dist/policy/access-provider.registry.d.ts +17 -0
- package/dist/policy/access-provider.registry.js +15 -0
- package/dist/policy/access-question.d.ts +20 -0
- package/dist/policy/access-question.js +1 -0
- package/dist/policy/access-question.registry.d.ts +5 -0
- package/dist/policy/access-question.registry.js +19 -0
- package/dist/policy/access-question.runtime.d.ts +36 -0
- package/dist/policy/access-question.runtime.js +295 -0
- package/dist/policy/access-verb.table.d.ts +56 -0
- package/dist/policy/access-verb.table.js +21 -0
- package/dist/policy/access-verbs.d.ts +46 -0
- package/dist/policy/access-verbs.js +1 -0
- package/dist/policy/policy-admission.d.ts +20 -0
- package/dist/policy/policy-admission.js +407 -0
- package/dist/policy/policy-after-update.runtime.d.ts +79 -0
- package/dist/policy/policy-after-update.runtime.js +206 -0
- package/dist/policy/policy-condition.d.ts +15 -0
- package/dist/policy/policy-condition.js +36 -0
- package/dist/policy/policy-engine.d.ts +205 -0
- package/dist/policy/policy-engine.js +1 -0
- package/dist/policy/policy-named-rows.d.ts +18 -0
- package/dist/policy/policy-named-rows.js +51 -0
- package/dist/policy/policy-nested-write.runtime.d.ts +44 -0
- package/dist/policy/policy-nested-write.runtime.js +536 -0
- package/dist/policy/policy-read.runtime.d.ts +81 -0
- package/dist/policy/policy-read.runtime.js +501 -0
- package/dist/policy/policy-reference-write.runtime.d.ts +51 -0
- package/dist/policy/policy-reference-write.runtime.js +336 -0
- package/dist/policy/policy-request.d.ts +72 -0
- package/dist/policy/policy-request.js +115 -0
- package/dist/policy/policy-session.d.ts +106 -0
- package/dist/policy/policy-session.js +293 -0
- package/dist/policy/policy-startup.validator.d.ts +10 -0
- package/dist/policy/policy-startup.validator.js +112 -0
- package/dist/policy/policy-write.runtime.d.ts +39 -0
- package/dist/policy/policy-write.runtime.js +530 -0
- package/dist/prebuilt/core-version.generated.d.ts +2 -0
- package/dist/prebuilt/core-version.generated.js +1 -0
- package/dist/prebuilt/prebuilt-changes.d.ts +29 -0
- package/dist/prebuilt/prebuilt-changes.js +63 -0
- package/dist/prebuilt/prebuilt-contracts.d.ts +40 -0
- package/dist/prebuilt/prebuilt-contracts.emitter.d.ts +16 -0
- package/dist/prebuilt/prebuilt-contracts.emitter.js +50 -0
- package/dist/prebuilt/prebuilt-contracts.js +1 -0
- package/dist/prebuilt/prebuilt-contracts.loader.d.ts +19 -0
- package/dist/prebuilt/prebuilt-contracts.loader.js +75 -0
- package/dist/prebuilt/prebuilt-inputs.fingerprint.d.ts +16 -0
- package/dist/prebuilt/prebuilt-inputs.fingerprint.js +227 -0
- package/dist/protocol/absent-route.responder.d.ts +49 -14
- package/dist/protocol/absent-route.responder.js +92 -15
- package/dist/protocol/contract-document.responder.d.ts +9 -1
- package/dist/protocol/contract-document.responder.js +3 -2
- package/dist/protocol/http-request.decoder.d.ts +52 -3
- package/dist/protocol/http-request.decoder.js +45 -6
- package/dist/protocol/http-request.reader.d.ts +10 -3
- package/dist/protocol/http-request.reader.js +12 -2
- package/dist/protocol/http-response.encoder.d.ts +12 -0
- package/dist/protocol/http-response.encoder.js +17 -3
- package/dist/protocol/operation-response.guard.js +1 -3
- package/dist/protocol/operation-set.decoder.d.ts +48 -0
- package/dist/protocol/operation-set.decoder.js +185 -0
- package/dist/protocol/operation-set.handler.d.ts +27 -0
- package/dist/protocol/operation-set.handler.js +179 -0
- package/dist/protocol/protocol-headers.d.ts +12 -3
- package/dist/protocol/protocol-headers.js +12 -5
- package/dist/protocol/protocol-surface.d.ts +16 -3
- package/dist/protocol/protocol-surface.js +41 -1
- package/dist/protocol/protocol.binder.d.ts +52 -1
- package/dist/protocol/protocol.binder.js +6 -1
- package/dist/protocol/protocol.handler.d.ts +45 -1
- package/dist/protocol/protocol.handler.js +164 -19
- package/dist/protocol/read-cache.responder.d.ts +26 -0
- package/dist/protocol/read-cache.responder.js +47 -0
- package/dist/protocol/read-query.codec.d.ts +34 -0
- package/dist/protocol/read-query.codec.js +125 -0
- package/dist/runtime/caller-data.copier.d.ts +18 -3
- package/dist/runtime/caller-data.copier.js +21 -8
- package/dist/runtime/caller-data.door.d.ts +13 -6
- package/dist/runtime/computed-read-runtime.d.ts +6 -1
- package/dist/runtime/computed-read-runtime.js +229 -48
- package/dist/runtime/computed-value.error.d.ts +3 -2
- package/dist/runtime/computed-value.error.js +3 -2
- package/dist/runtime/context-executor.runtime.d.ts +4 -3
- package/dist/runtime/context-executor.runtime.js +4 -2
- package/dist/runtime/core-class.brand.d.ts +10 -0
- package/dist/runtime/core-class.brand.js +21 -0
- package/dist/runtime/create-requirement.d.ts +31 -5
- package/dist/runtime/create-requirement.js +130 -24
- package/dist/runtime/decimal.d.ts +14 -0
- package/dist/runtime/decimal.js +21 -0
- package/dist/runtime/diagnostics-reporter.d.ts +49 -9
- package/dist/runtime/diagnostics-reporter.js +16 -9
- package/dist/runtime/error-boundary.d.ts +9 -2
- package/dist/runtime/error-boundary.js +12 -0
- package/dist/runtime/error-guidance.d.ts +12 -0
- package/dist/runtime/error-guidance.js +1 -0
- package/dist/runtime/error.catalog.d.ts +49 -0
- package/dist/runtime/error.catalog.js +49 -0
- package/dist/runtime/execution-options.d.ts +8 -0
- package/dist/runtime/field-check.evaluator.d.ts +0 -2
- package/dist/runtime/field-check.evaluator.js +1 -1
- package/dist/runtime/field-compute.d.ts +11 -10
- package/dist/runtime/field-stage.runtime.d.ts +3 -3
- package/dist/runtime/field-stage.runtime.js +9 -11
- package/dist/runtime/field-validator.runtime.d.ts +19 -1
- package/dist/runtime/field-validator.runtime.js +49 -9
- package/dist/runtime/framework-error.js +9 -0
- package/dist/runtime/framework-warning.emitter.d.ts +6 -0
- package/dist/runtime/framework-warning.emitter.js +8 -0
- package/dist/runtime/json-value.d.ts +10 -5
- package/dist/runtime/level-lifecycle.runtime.d.ts +4 -3
- package/dist/runtime/level-lifecycle.runtime.js +3 -5
- package/dist/runtime/mutation-planner.d.ts +1 -6
- package/dist/runtime/mutation-planner.js +4 -17
- package/dist/runtime/nested-write.walker.js +2 -1
- package/dist/runtime/operation-code.guidance.d.ts +6 -0
- package/dist/runtime/operation-code.guidance.js +167 -0
- package/dist/runtime/operation-request.d.ts +16 -9
- package/dist/runtime/operation-runtime.d.ts +35 -17
- package/dist/runtime/operation-runtime.js +220 -49
- package/dist/runtime/outcome-mapper.d.ts +2 -1
- package/dist/runtime/output-validator.d.ts +1 -1
- package/dist/runtime/output-validator.js +1 -3
- package/dist/runtime/owned-execution.registry.d.ts +34 -4
- package/dist/runtime/pipe-output.validator.d.ts +10 -0
- package/dist/runtime/pipe-output.validator.js +4 -2
- package/dist/runtime/pipeline.d.ts +52 -23
- package/dist/runtime/readonly-value.d.ts +20 -5
- package/dist/runtime/readonly-value.js +74 -26
- package/dist/runtime/record.guard.d.ts +14 -0
- package/dist/runtime/record.guard.js +10 -0
- package/dist/runtime/referential-action.d.ts +1 -1
- package/dist/runtime/request-envelope.validator.js +13 -10
- package/dist/runtime/scalar-runtime.d.ts +4 -21
- package/dist/runtime/scalar-runtime.js +91 -31
- package/dist/runtime/thenable.guard.d.ts +7 -0
- package/dist/runtime/thenable.guard.js +5 -0
- package/dist/runtime/unsent-value.normalizer.d.ts +15 -0
- package/dist/runtime/unsent-value.normalizer.js +129 -0
- package/dist/transactions/operation-arguments-encoder.js +9 -10
- package/dist/transactions/operation-fingerprint.js +2 -2
- package/dist/transactions/sql-statement.d.ts +10 -2
- package/dist/transactions/sql-statement.validator.d.ts +2 -2
- package/dist/transactions/sql-statement.validator.js +40 -6
- package/dist/transactions/transaction-envelope.d.ts +5 -4
- package/dist/transactions/transaction-integrity-error.js +2 -0
- package/dist/transactions/transaction-plan-assembler.d.ts +12 -5
- package/dist/transactions/transaction-plan-assembler.js +49 -17
- package/dist/transactions/transaction-plan-validator.d.ts +23 -7
- package/dist/transactions/transaction-plan-validator.js +31 -7
- package/dist/transactions/transaction-reference-collector.js +8 -10
- package/dist/transactions/transaction-reference-resolver.d.ts +3 -2
- package/dist/transactions/transaction-reference-resolver.js +1 -3
- package/dist/transactions/transaction-reference-validator.d.ts +43 -3
- package/dist/transactions/transaction-reference-validator.js +83 -57
- package/dist/transactions/transaction-reference.d.ts +1 -1
- package/dist/transactions/transaction-reference.js +5 -0
- package/dist/transactions/transaction-request.d.ts +8 -8
- package/dist/transactions/transaction-runtime.d.ts +5 -2
- package/dist/transactions/transaction-runtime.js +108 -27
- package/dist/transactions/transaction-settlement.runtime.d.ts +4 -3
- package/dist/transactions/transaction-slot-path-error.js +2 -0
- package/dist/transactions/transaction-stage.runtime.d.ts +5 -3
- package/dist/transactions/transaction-stage.runtime.js +8 -7
- package/package.json +6 -5
- package/src/runtime/field-check.evaluator.ts +1 -1
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { FILTER_MODES, toOneRelinkWithRewrite, } from "../contracts/capability.js";
|
|
1
2
|
import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
|
|
2
3
|
import { advertisedDirectivesAt, advertisedReducers, advertisedReducersAt, holdsAt, } from "../contracts/field.js";
|
|
3
|
-
import { isPlainRecord } from "../runtime/
|
|
4
|
+
import { isPlainRecord, isRecord } from "../runtime/record.guard.js";
|
|
5
|
+
import { unsentReadValueIssue } from "../runtime/scalar-runtime.js";
|
|
4
6
|
import { routeTransactionReferenceCandidate } from "../transactions/transaction-reference.js";
|
|
5
7
|
import { isOperationFamily, } from "./operation-identity.js";
|
|
6
8
|
import { NESTED_PROJECTION_SCOPE, resolveProjectionScope, } from "./projection-scope.resolver.js";
|
|
7
|
-
import { NESTED_WRITE_SCOPE, resolveWriteScope, } from "./write-scope.resolver.js";
|
|
9
|
+
import { NESTED_WRITE_SCOPE, resolveWriteScope, TO_MANY_UPDATE_WRITE_SCOPE, } from "./write-scope.resolver.js";
|
|
8
10
|
const OPERATION_ARGUMENT_RULES = {
|
|
9
11
|
"find.first": {
|
|
10
12
|
allowed: ["where", "orderBy", "select", "include"],
|
|
@@ -95,9 +97,6 @@ const OPERATION_ARGUMENT_RULES = {
|
|
|
95
97
|
projection: true,
|
|
96
98
|
},
|
|
97
99
|
};
|
|
98
|
-
function isRecord(value) {
|
|
99
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
100
|
-
}
|
|
101
100
|
function includes(values, value) {
|
|
102
101
|
return values?.includes(value) ?? false;
|
|
103
102
|
}
|
|
@@ -190,11 +189,16 @@ function validateScalarCondition(contract, fieldName, field, supported, value, p
|
|
|
190
189
|
addIssue(state.issues, "V1001", path, `Filter object for field "${fieldName}" must contain an operator.`);
|
|
191
190
|
return;
|
|
192
191
|
}
|
|
192
|
+
refuseDanglingQualifiers(fieldName, value, path, state);
|
|
193
193
|
for (const operator of operators) {
|
|
194
194
|
if (!includes(supported, operator)) {
|
|
195
195
|
addIssue(state.issues, "V1006", [...path, operator], `Filter operator "${operator}" is not available on field "${fieldName}".`);
|
|
196
196
|
continue;
|
|
197
197
|
}
|
|
198
|
+
if (operator === "mode") {
|
|
199
|
+
refuseUnavailableMode(field, fieldName, value, path, state);
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
198
202
|
if (operator === "not") {
|
|
199
203
|
const operand = value[operator];
|
|
200
204
|
if (isPlainRecord(operand) && !checkDepth(contract, state, depth + 1)) {
|
|
@@ -204,12 +208,55 @@ function validateScalarCondition(contract, fieldName, field, supported, value, p
|
|
|
204
208
|
}
|
|
205
209
|
}
|
|
206
210
|
}
|
|
211
|
+
function refuseDanglingQualifiers(fieldName, level, path, state) {
|
|
212
|
+
const qualifiers = DANGLING_QUALIFIERS.filter((key) => Object.hasOwn(level, key));
|
|
213
|
+
if (qualifiers.length === 0) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const compares = Object.entries(level).some(([operator, operand]) => !includes(DANGLING_QUALIFIERS, operator) &&
|
|
217
|
+
!(operator === "not" && isNegatedOperatorObject(operand, state)));
|
|
218
|
+
if (compares) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
for (const qualifier of qualifiers) {
|
|
222
|
+
addIssue(state.issues, "V1001", [...path, qualifier], `${qualifier} on field "${fieldName}" qualifies no operator: write it next to the operator it applies to (inside "not" to apply to a negated one).`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
const DANGLING_QUALIFIERS = ["mode", "path"];
|
|
226
|
+
function isNegatedOperatorObject(operand, state) {
|
|
227
|
+
return (isPlainRecord(operand) &&
|
|
228
|
+
!(state.transactionReferences === true &&
|
|
229
|
+
routeTransactionReferenceCandidate(operand).kind !== "ordinary"));
|
|
230
|
+
}
|
|
231
|
+
function refuseUnavailableMode(field, fieldName, level, path, state) {
|
|
232
|
+
const mode = level.mode;
|
|
233
|
+
if (mode === "default" ||
|
|
234
|
+
typeof mode !== "string" ||
|
|
235
|
+
!includes(FILTER_MODES, mode)) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
const { filterModes = [], pathFilterModes } = field.capabilities;
|
|
239
|
+
const atPath = Object.hasOwn(level, "path") && pathFilterModes !== undefined;
|
|
240
|
+
if (includes(atPath ? pathFilterModes : filterModes, mode)) {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const where = atPath
|
|
244
|
+
? " at a path"
|
|
245
|
+
: pathFilterModes !== undefined && includes(pathFilterModes, mode)
|
|
246
|
+
? " without a path"
|
|
247
|
+
: "";
|
|
248
|
+
addIssue(state.issues, "V1006", [...path, "mode"], `Filter mode "${mode}" is not available on field "${fieldName}"${where}.`);
|
|
249
|
+
}
|
|
207
250
|
function validateRelationFilter(contract, fieldName, field, value, path, state, depth) {
|
|
208
251
|
const supported = field.capabilities.filter;
|
|
209
252
|
if (supported === undefined) {
|
|
210
253
|
addIssue(state.issues, "V1006", path, `Filtering is not available on relation "${fieldName}".`);
|
|
211
254
|
return;
|
|
212
255
|
}
|
|
256
|
+
if (value === undefined) {
|
|
257
|
+
state.issues.push(unsentReadValueIssue(path));
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
213
260
|
if (field.cardinality === "one") {
|
|
214
261
|
if (value === null) {
|
|
215
262
|
if (!field.nullable || !includes(supported, "null")) {
|
|
@@ -249,10 +296,26 @@ function validateRelationFilter(contract, fieldName, field, value, path, state,
|
|
|
249
296
|
validateWhere(contract, field.target, value[operator], [...path, operator], state, depth + 1);
|
|
250
297
|
}
|
|
251
298
|
}
|
|
299
|
+
const UNDEFINED_ARGUMENT_MESSAGES = {
|
|
300
|
+
where: "where must not be undefined: leave the key out to mean no filter.",
|
|
301
|
+
limit: "limit must not be undefined: leave the key out to mean no limit.",
|
|
302
|
+
offset: "offset must not be undefined: leave the key out to mean no offset.",
|
|
303
|
+
cursor: "cursor must not be undefined: leave the key out to mean no cursor.",
|
|
304
|
+
};
|
|
305
|
+
const EMPTY_BOOLEAN_NODE_MESSAGE = "A boolean node must hold a condition here: an empty one matches every row, and the write would reach more rows.";
|
|
306
|
+
function isEmptyBooleanNode(value) {
|
|
307
|
+
return Array.isArray(value)
|
|
308
|
+
? value.length === 0
|
|
309
|
+
: isRecord(value) && Object.keys(value).length === 0;
|
|
310
|
+
}
|
|
252
311
|
function validateWhere(contract, resourceName, where, path, state, depth) {
|
|
253
312
|
if (!checkDepth(contract, state, depth)) {
|
|
254
313
|
return;
|
|
255
314
|
}
|
|
315
|
+
if (where === undefined) {
|
|
316
|
+
state.issues.push(unsentReadValueIssue(path));
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
256
319
|
if (!isRecord(where)) {
|
|
257
320
|
addIssue(state.issues, "V1001", path, "where must be an object.");
|
|
258
321
|
return;
|
|
@@ -263,6 +326,13 @@ function validateWhere(contract, resourceName, where, path, state, depth) {
|
|
|
263
326
|
return;
|
|
264
327
|
}
|
|
265
328
|
for (const [key, value] of Object.entries(where)) {
|
|
329
|
+
if (state.refuseEmptyNodes === true &&
|
|
330
|
+
(key === "AND" || key === "OR" || key === "NOT") &&
|
|
331
|
+
isEmptyBooleanNode(value)) {
|
|
332
|
+
countFilterNode(contract, state);
|
|
333
|
+
addIssue(state.issues, "V1001", [...path, key], EMPTY_BOOLEAN_NODE_MESSAGE);
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
266
336
|
if (key === "AND" || key === "OR") {
|
|
267
337
|
countFilterNode(contract, state);
|
|
268
338
|
if (!Array.isArray(value)) {
|
|
@@ -270,6 +340,10 @@ function validateWhere(contract, resourceName, where, path, state, depth) {
|
|
|
270
340
|
continue;
|
|
271
341
|
}
|
|
272
342
|
value.forEach((entry, index) => {
|
|
343
|
+
if (state.refuseEmptyNodes === true && isEmptyBooleanNode(entry)) {
|
|
344
|
+
addIssue(state.issues, "V1001", [...path, key, index], EMPTY_BOOLEAN_NODE_MESSAGE);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
273
347
|
validateWhere(contract, resourceName, entry, [...path, key, index], state, depth + 1);
|
|
274
348
|
});
|
|
275
349
|
continue;
|
|
@@ -366,7 +440,9 @@ function validateOrderBy(contract, resourceName, orderBy, path, issues) {
|
|
|
366
440
|
valueKeys[1] !== "sort" ||
|
|
367
441
|
(value.sort !== "asc" && value.sort !== "desc") ||
|
|
368
442
|
(value.nulls !== "first" && value.nulls !== "last")) {
|
|
369
|
-
addIssue(issues, "V1001", fieldPath,
|
|
443
|
+
addIssue(issues, "V1001", fieldPath, Object.hasOwn(value, "$ref")
|
|
444
|
+
? `A transaction reference cannot stand in orderBy: order "${fieldName}" by "asc", "desc" or { sort, nulls }.`
|
|
445
|
+
: `Null ordering for "${fieldName}" must be exactly { sort: "asc" | "desc", nulls: "first" | "last" }.`);
|
|
370
446
|
continue;
|
|
371
447
|
}
|
|
372
448
|
if (!field.nullable || field.capabilities.orderNulls !== true) {
|
|
@@ -393,6 +469,10 @@ function validateOrderBy(contract, resourceName, orderBy, path, issues) {
|
|
|
393
469
|
return analysis;
|
|
394
470
|
}
|
|
395
471
|
function validatePaginationValue(contract, name, value, path, issues) {
|
|
472
|
+
if (value === undefined) {
|
|
473
|
+
addIssue(issues, "V1001", path, UNDEFINED_ARGUMENT_MESSAGES[name]);
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
396
476
|
if (!Number.isInteger(value) || typeof value !== "number" || value < 0) {
|
|
397
477
|
addIssue(issues, "V1001", path, `${name} must be a non-negative integer.`);
|
|
398
478
|
return;
|
|
@@ -402,6 +482,10 @@ function validatePaginationValue(contract, name, value, path, issues) {
|
|
|
402
482
|
}
|
|
403
483
|
}
|
|
404
484
|
function validateCursor(contract, resourceName, cursor, orderBy, path, issues) {
|
|
485
|
+
if (cursor === undefined) {
|
|
486
|
+
addIssue(issues, "V1009", path, UNDEFINED_ARGUMENT_MESSAGES.cursor);
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
405
489
|
if (!isRecord(cursor) || orderBy === undefined) {
|
|
406
490
|
addIssue(issues, "V1009", path, "Cursor pagination requires an object cursor and explicit deterministic orderBy.");
|
|
407
491
|
return;
|
|
@@ -438,6 +522,12 @@ function validateProjection(contract, resourceName, mode, value, scope, path, is
|
|
|
438
522
|
}
|
|
439
523
|
value.forEach((entry, index) => {
|
|
440
524
|
const entryPath = [...path, index];
|
|
525
|
+
if (entry === "$defaults") {
|
|
526
|
+
if (mode !== "select") {
|
|
527
|
+
addIssue(issues, "V1008", entryPath, "$defaults is a select entry: include already returns the default fields.");
|
|
528
|
+
}
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
441
531
|
if (entry === "$count") {
|
|
442
532
|
if (mode !== "select" ||
|
|
443
533
|
reducerOwner?.edge.cardinality !== "many" ||
|
|
@@ -513,6 +603,9 @@ function validateRelationProjection(contract, edge, scope, value, path, issues)
|
|
|
513
603
|
if (!includes(edge.capabilities.filter, "nested")) {
|
|
514
604
|
addIssue(issues, "V1006", [...path, "where"], "Nested returned-relation filtering is not available on this edge.");
|
|
515
605
|
}
|
|
606
|
+
else if (value.where === undefined) {
|
|
607
|
+
addIssue(issues, "V1001", [...path, "where"], UNDEFINED_ARGUMENT_MESSAGES.where);
|
|
608
|
+
}
|
|
516
609
|
else {
|
|
517
610
|
const state = {
|
|
518
611
|
issues,
|
|
@@ -586,11 +679,16 @@ function validateScalarMutation(fieldName, field, value, stage, path, issues, tr
|
|
|
586
679
|
addIssue(issues, "V1001", path, "Scalar mutation action objects may contain only $-prefixed directive keys.");
|
|
587
680
|
return;
|
|
588
681
|
}
|
|
682
|
+
let unavailable = false;
|
|
589
683
|
for (const directive of directiveKeys) {
|
|
590
684
|
if (!includes(directives, directive)) {
|
|
685
|
+
unavailable = true;
|
|
591
686
|
addIssue(issues, "V1006", [...path, directive], `Mutation directive "${directive}" is not available on field "${fieldName}".`);
|
|
592
687
|
}
|
|
593
688
|
}
|
|
689
|
+
if (!unavailable && directiveKeys.length > 1) {
|
|
690
|
+
addIssue(issues, "V1001", path, "Scalar mutation action objects may contain only one directive.");
|
|
691
|
+
}
|
|
594
692
|
}
|
|
595
693
|
function validateRelationMutationEntry(contract, edge, directive, value, path, issues, transactionReferences) {
|
|
596
694
|
const target = edge.target;
|
|
@@ -610,8 +708,8 @@ function validateRelationMutationEntry(contract, edge, directive, value, path, i
|
|
|
610
708
|
addIssue(issues, "V1012", path, "To-many $disconnect requires one or more unique identifiers.");
|
|
611
709
|
return;
|
|
612
710
|
}
|
|
613
|
-
for (const selector of
|
|
614
|
-
validateUniqueSelector(contract, target, selector,
|
|
711
|
+
for (const { entry: selector, at } of entriesOf(edge, value, path)) {
|
|
712
|
+
validateUniqueSelector(contract, target, selector, at, issues);
|
|
615
713
|
}
|
|
616
714
|
return;
|
|
617
715
|
}
|
|
@@ -626,82 +724,81 @@ function validateRelationMutationEntry(contract, edge, directive, value, path, i
|
|
|
626
724
|
addIssue(issues, "V1012", path, "To-many $set requires an identifier array.");
|
|
627
725
|
return;
|
|
628
726
|
}
|
|
629
|
-
for (const selector of value) {
|
|
630
|
-
validateUniqueSelector(contract, target, selector,
|
|
727
|
+
for (const { entry: selector, at } of entriesOf(edge, value, path)) {
|
|
728
|
+
validateUniqueSelector(contract, target, selector, at, issues);
|
|
631
729
|
}
|
|
632
730
|
return;
|
|
633
731
|
}
|
|
634
732
|
if (directive === "$connect") {
|
|
635
|
-
const
|
|
636
|
-
|
|
637
|
-
validateUniqueSelector(contract, target, selector, path, issues);
|
|
733
|
+
for (const { entry: selector, at } of entriesOf(edge, value, path)) {
|
|
734
|
+
validateUniqueSelector(contract, target, selector, at, issues);
|
|
638
735
|
}
|
|
639
736
|
return;
|
|
640
737
|
}
|
|
641
738
|
if (directive === "$create") {
|
|
642
|
-
const
|
|
643
|
-
|
|
644
|
-
validateMutationData(contract, target, entry, "create", NESTED_WRITE_SCOPE, path, issues, transactionReferences);
|
|
739
|
+
for (const { entry, at } of entriesOf(edge, value, path)) {
|
|
740
|
+
validateMutationData(contract, target, entry, "create", NESTED_WRITE_SCOPE, at, issues, transactionReferences);
|
|
645
741
|
}
|
|
646
742
|
return;
|
|
647
743
|
}
|
|
648
744
|
if (directive === "$connectOrCreate") {
|
|
649
|
-
const
|
|
650
|
-
for (const entry of entries) {
|
|
745
|
+
for (const { entry, at } of entriesOf(edge, value, path)) {
|
|
651
746
|
if (!isRecord(entry) || !("where" in entry) || !("create" in entry)) {
|
|
652
|
-
addIssue(issues, "V1012",
|
|
747
|
+
addIssue(issues, "V1012", at, "$connectOrCreate requires where and create.");
|
|
653
748
|
continue;
|
|
654
749
|
}
|
|
655
|
-
validateUniqueSelector(contract, target, entry.where, [...
|
|
656
|
-
validateMutationData(contract, target, entry.create, "create", NESTED_WRITE_SCOPE, [...
|
|
750
|
+
validateUniqueSelector(contract, target, entry.where, [...at, "where"], issues);
|
|
751
|
+
validateMutationData(contract, target, entry.create, "create", NESTED_WRITE_SCOPE, [...at, "create"], issues, transactionReferences);
|
|
657
752
|
}
|
|
658
753
|
return;
|
|
659
754
|
}
|
|
660
755
|
if (directive === "$update") {
|
|
661
|
-
const
|
|
662
|
-
for (const entry of entries) {
|
|
756
|
+
for (const { entry, at } of entriesOf(edge, value, path)) {
|
|
663
757
|
if (!isRecord(entry) || !("data" in entry)) {
|
|
664
|
-
addIssue(issues, "V1012",
|
|
758
|
+
addIssue(issues, "V1012", at, "$update requires a data object.");
|
|
665
759
|
continue;
|
|
666
760
|
}
|
|
667
761
|
if (edge.cardinality === "many" && !("where" in entry)) {
|
|
668
|
-
addIssue(issues, "V1012",
|
|
762
|
+
addIssue(issues, "V1012", at, "To-many $update requires where.");
|
|
669
763
|
continue;
|
|
670
764
|
}
|
|
671
765
|
if ("where" in entry) {
|
|
672
766
|
const state = {
|
|
673
767
|
issues,
|
|
674
|
-
structuralRoot: [...
|
|
768
|
+
structuralRoot: [...at, "where"],
|
|
675
769
|
transactionReferences,
|
|
676
770
|
scalarOnly: edge.capabilities.nestedWriteFilter === "scalar",
|
|
771
|
+
...(edge.cardinality === "many" ? { refuseEmptyNodes: true } : {}),
|
|
677
772
|
booleanFilterNodes: 0,
|
|
678
773
|
nestingExceeded: false,
|
|
679
774
|
booleanNodesExceeded: false,
|
|
680
775
|
};
|
|
681
|
-
validateWhere(contract, target, entry.where, [...
|
|
776
|
+
validateWhere(contract, target, entry.where, [...at, "where"], state, 1);
|
|
682
777
|
}
|
|
683
|
-
validateMutationData(contract, target, entry.data, "update",
|
|
778
|
+
validateMutationData(contract, target, entry.data, "update", edge.cardinality === "many"
|
|
779
|
+
? TO_MANY_UPDATE_WRITE_SCOPE
|
|
780
|
+
: NESTED_WRITE_SCOPE, [...at, "data"], issues, transactionReferences);
|
|
684
781
|
}
|
|
685
782
|
return;
|
|
686
783
|
}
|
|
687
784
|
if (directive === "$delete") {
|
|
688
|
-
const
|
|
689
|
-
for (const entry of entries) {
|
|
785
|
+
for (const { entry, at } of entriesOf(edge, value, path)) {
|
|
690
786
|
if (edge.cardinality === "many") {
|
|
691
787
|
if (!isRecord(entry) || !("where" in entry)) {
|
|
692
|
-
addIssue(issues, "V1012",
|
|
788
|
+
addIssue(issues, "V1012", at, "To-many $delete requires where.");
|
|
693
789
|
continue;
|
|
694
790
|
}
|
|
695
791
|
const state = {
|
|
696
792
|
issues,
|
|
697
|
-
structuralRoot: [...
|
|
793
|
+
structuralRoot: [...at, "where"],
|
|
698
794
|
transactionReferences,
|
|
699
795
|
scalarOnly: edge.capabilities.nestedWriteFilter === "scalar",
|
|
796
|
+
refuseEmptyNodes: true,
|
|
700
797
|
booleanFilterNodes: 0,
|
|
701
798
|
nestingExceeded: false,
|
|
702
799
|
booleanNodesExceeded: false,
|
|
703
800
|
};
|
|
704
|
-
validateWhere(contract, target, entry.where, [...
|
|
801
|
+
validateWhere(contract, target, entry.where, [...at, "where"], state, 1);
|
|
705
802
|
}
|
|
706
803
|
else if (entry !== true &&
|
|
707
804
|
(!isRecord(entry) || Object.keys(entry).some((key) => key !== "where"))) {
|
|
@@ -723,23 +820,34 @@ function validateRelationMutationEntry(contract, edge, directive, value, path, i
|
|
|
723
820
|
return;
|
|
724
821
|
}
|
|
725
822
|
if (directive === "$upsert") {
|
|
726
|
-
const
|
|
727
|
-
for (const entry of entries) {
|
|
823
|
+
for (const { entry, at } of entriesOf(edge, value, path)) {
|
|
728
824
|
if (!isRecord(entry) ||
|
|
729
825
|
!("create" in entry) ||
|
|
730
826
|
!("update" in entry) ||
|
|
731
827
|
(edge.cardinality === "many" && !("where" in entry))) {
|
|
732
|
-
addIssue(issues, "V1012",
|
|
828
|
+
addIssue(issues, "V1012", at, "$upsert requires create/update and requires where on to-many relations.");
|
|
733
829
|
continue;
|
|
734
830
|
}
|
|
735
831
|
if ("where" in entry) {
|
|
736
|
-
validateUniqueSelector(contract, target, entry.where, [...
|
|
832
|
+
validateUniqueSelector(contract, target, entry.where, [...at, "where"], issues);
|
|
737
833
|
}
|
|
738
|
-
validateMutationData(contract, target, entry.create, "create", NESTED_WRITE_SCOPE, [...
|
|
739
|
-
validateMutationData(contract, target, entry.update, "update", NESTED_WRITE_SCOPE, [...
|
|
834
|
+
validateMutationData(contract, target, entry.create, "create", NESTED_WRITE_SCOPE, [...at, "create"], issues, transactionReferences);
|
|
835
|
+
validateMutationData(contract, target, entry.update, "update", NESTED_WRITE_SCOPE, [...at, "update"], issues, transactionReferences);
|
|
740
836
|
}
|
|
741
837
|
}
|
|
742
838
|
}
|
|
839
|
+
function entriesOf(edge, value, path) {
|
|
840
|
+
return edge.cardinality === "many" && Array.isArray(value)
|
|
841
|
+
? value.map((entry, index) => ({ entry, at: [...path, index] }))
|
|
842
|
+
: [{ entry: value, at: path }];
|
|
843
|
+
}
|
|
844
|
+
function refuseToOneRelinkWithRewrite(fieldName, field, value, path, issues) {
|
|
845
|
+
const paired = field.cardinality === "one" ? toOneRelinkWithRewrite(value) : undefined;
|
|
846
|
+
if (paired === undefined) {
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
addIssue(issues, "V1012", path, `To-one relation "${fieldName}" cannot combine ${paired.rewrite.join("/")} with ${paired.relink.join("/")} in one write: the row it would update is the newly linked one. Relink in one write and update in another.`);
|
|
850
|
+
}
|
|
743
851
|
function validateRelationMutation(contract, fieldName, field, value, stage, scope, path, issues, transactionReferences) {
|
|
744
852
|
const directives = advertisedDirectivesAt(field.capabilities[stage], scope);
|
|
745
853
|
if (directives === undefined) {
|
|
@@ -750,6 +858,7 @@ function validateRelationMutation(contract, fieldName, field, value, stage, scop
|
|
|
750
858
|
addIssue(issues, "V1012", path, `Relation "${fieldName}" mutation value must be a directive object.`);
|
|
751
859
|
return;
|
|
752
860
|
}
|
|
861
|
+
refuseToOneRelinkWithRewrite(fieldName, field, value, path, issues);
|
|
753
862
|
for (const [directive, directiveValue] of Object.entries(value)) {
|
|
754
863
|
const directivePath = [...path, directive];
|
|
755
864
|
if (!directive.startsWith("$") || !includes(directives, directive)) {
|
|
@@ -817,6 +926,14 @@ function validateMutationArguments(contract, resourceName, request, args, issues
|
|
|
817
926
|
}
|
|
818
927
|
}
|
|
819
928
|
}
|
|
929
|
+
function emptyNodeRefusalOf(request) {
|
|
930
|
+
return (request.family === "update" || request.family === "delete") &&
|
|
931
|
+
(request.variant === "many" ||
|
|
932
|
+
request.variant === "count" ||
|
|
933
|
+
request.variant === "first")
|
|
934
|
+
? { refuseEmptyNodes: true }
|
|
935
|
+
: {};
|
|
936
|
+
}
|
|
820
937
|
function isUniqueOperation(request) {
|
|
821
938
|
return (request.variant === "unique" &&
|
|
822
939
|
(request.family === "find" ||
|
|
@@ -854,11 +971,15 @@ export function validateOperationArguments(contract, request, options) {
|
|
|
854
971
|
if (isUniqueOperation(request)) {
|
|
855
972
|
validateUniqueSelector(contract, request.resource, request.arguments.where, ["arguments", "where"], issues);
|
|
856
973
|
}
|
|
974
|
+
else if (request.arguments.where === undefined) {
|
|
975
|
+
addIssue(issues, "V1001", ["arguments", "where"], UNDEFINED_ARGUMENT_MESSAGES.where);
|
|
976
|
+
}
|
|
857
977
|
else {
|
|
858
978
|
const state = {
|
|
859
979
|
issues,
|
|
860
980
|
structuralRoot: ["arguments", "where"],
|
|
861
981
|
transactionReferences: options?.transactionReferences === true,
|
|
982
|
+
...emptyNodeRefusalOf(request),
|
|
862
983
|
booleanFilterNodes: 0,
|
|
863
984
|
nestingExceeded: false,
|
|
864
985
|
booleanNodesExceeded: false,
|
|
@@ -2,7 +2,7 @@ import type { AvContract } from "../contracts/contract.js";
|
|
|
2
2
|
import { type AvOperationIdentity } from "./operation-identity.js";
|
|
3
3
|
import { type OperationValidationOptions, type OperationValidationResult } from "./operation-validator-core.js";
|
|
4
4
|
import type { AvValidationIssue } from "./validation-code.js";
|
|
5
|
-
export type { OperationValidationOptions,
|
|
5
|
+
export type { OperationValidationOptions, SemanticOperationArguments, } from "./operation-validator-core.js";
|
|
6
6
|
/** The key of a request's operation identity that makes it unavailable. */
|
|
7
7
|
export declare function unavailableOperationKey(contract: AvContract, request: {
|
|
8
8
|
readonly resource: string;
|
|
@@ -3,7 +3,7 @@ import type { AvOperationIdentity } from "./operation-identity.js";
|
|
|
3
3
|
import type { AvValidationIssue } from "./validation-code.js";
|
|
4
4
|
type Readable = Readonly<Record<string, unknown>>;
|
|
5
5
|
/** What one walk of an operation's arguments found. */
|
|
6
|
-
|
|
6
|
+
type StructuralLimitsFinding = {
|
|
7
7
|
/** The nesting issue, which wins over any boolean-node issue. */
|
|
8
8
|
readonly nesting: AvValidationIssue | undefined;
|
|
9
9
|
/** The boolean-node issue, when there is no nesting issue. */
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
|
|
2
2
|
import { advertisedDirectives, holdsAt, } from "../contracts/field.js";
|
|
3
|
+
import { isRecord } from "../runtime/record.guard.js";
|
|
3
4
|
import { NESTED_PROJECTION_SCOPE, resolveProjectionScope, } from "./projection-scope.resolver.js";
|
|
4
5
|
const UNTRACKED = [];
|
|
5
6
|
const RELATION_FILTER_OPERATORS = ["some", "every", "none"];
|
|
@@ -15,9 +16,6 @@ const DIRECTIVE_PAYLOADS = new Map([
|
|
|
15
16
|
],
|
|
16
17
|
]);
|
|
17
18
|
const NO_PAYLOADS = [];
|
|
18
|
-
function isRecord(value) {
|
|
19
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20
|
-
}
|
|
21
19
|
function extend(state, path, segment) {
|
|
22
20
|
return state.tracking ? [...path, segment] : UNTRACKED;
|
|
23
21
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ErrorCodeGuidance } from "../runtime/error-guidance.js";
|
|
2
|
+
import type { AvValidationCode } from "./validation-code.js";
|
|
3
|
+
/** Cause and fix of every validation code. */
|
|
4
|
+
export declare const VALIDATION_CODE_GUIDANCE: {
|
|
5
|
+
readonly [C in AvValidationCode]: ErrorCodeGuidance;
|
|
6
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
export const VALIDATION_CODE_GUIDANCE = {
|
|
2
|
+
V1000: {
|
|
3
|
+
cause: "A required value is absent: a create leaves out a required field that has no database default and no compute.create (the path names the field), a required relation and its reference field are both missing, a typed Json field lacks a required key, or a $ref has no fingerprint.",
|
|
4
|
+
fix: "Send the value at the issue's path. When the server must fill it, give the field a compute.create stage or a database default; a pipe cannot fill it.",
|
|
5
|
+
},
|
|
6
|
+
V1001: {
|
|
7
|
+
cause: "A value of the wrong type: a string where a number is expected, a negative limit, a non-integer id, null given to an operator with no null meaning (gt, contains, in), two directives in one scalar action object (`{ $increment: 1, $decrement: 2 }`), or a server-side value that is not plain data. Also a value that would make the call reach more rows: `undefined` in a filter, a unique selector or a cursor, an empty boolean node (`NOT: {}`, `AND: []`, `OR: []`) in the where of a write (update or delete many, count or first, a to-many $update or $delete).",
|
|
8
|
+
fix: "Send the type the contract states at that path (the generated client's types say it).",
|
|
9
|
+
},
|
|
10
|
+
V1002: {
|
|
11
|
+
cause: "A value that is not a member of the enum, or outside a typed Json field's AvZ.enum or AvZ.literal.",
|
|
12
|
+
fix: "Send one of the enum's members.",
|
|
13
|
+
},
|
|
14
|
+
V1003: {
|
|
15
|
+
cause: 'A malformed datetime, decimal, base64 or UUID string, or a failed pattern or format validator (`check: "string_format"`).',
|
|
16
|
+
fix: "Send the canonical encoding (ISO-8601 UTC datetime, decimal string, base64 bytes) and satisfy the validator that check and params name.",
|
|
17
|
+
},
|
|
18
|
+
V1004: {
|
|
19
|
+
cause: "A number, length or size outside its range: a failed bound, length or size validator, a BigInt outside signed 64 bits, an AvZ.int() outside the safe integer range, or a transaction with no operations. Under A2004 it is also a value the database refused as too long or out of its range, a BigInt beyond what the data source's driver can bind among them (some bind at most ±(2^53 − 1)).",
|
|
20
|
+
fix: "Send a value inside the range; check and params name the validator that failed.",
|
|
21
|
+
},
|
|
22
|
+
V1005: {
|
|
23
|
+
cause: "A field that does not exist or is hidden in the caller's layer, an unknown Resource (under A2001), or a key a typed Json field's shape does not declare.",
|
|
24
|
+
fix: "Use a field the caller's contract exposes, expose it through exemptions, or make the call from server code.",
|
|
25
|
+
},
|
|
26
|
+
V1006: {
|
|
27
|
+
cause: "An operator, directive or nested write the field does not offer (at any depth, inside not too; a to-many $update's data takes only what a bulk write takes), a mode it does not offer, or an operation that is not available (under A2002).",
|
|
28
|
+
fix: "Use what the contract lists for that field or Resource, or expose it through exemptions.",
|
|
29
|
+
},
|
|
30
|
+
V1007: {
|
|
31
|
+
cause: "The where of a unique operation is not exactly one complete identifier.",
|
|
32
|
+
fix: "Pass exactly one identifier: the id, or every field of one @unique or @@unique.",
|
|
33
|
+
},
|
|
34
|
+
V1008: {
|
|
35
|
+
cause: "Both select and include, a write-only field selected, or a relation that is not selectable there.",
|
|
36
|
+
fix: "Use select or include, not both, and select only readable fields.",
|
|
37
|
+
},
|
|
38
|
+
V1009: {
|
|
39
|
+
cause: "A cursor without an explicit orderBy, or cursor keys that do not match the ordered fields.",
|
|
40
|
+
fix: "Give an orderBy and a cursor holding exactly its ordered fields.",
|
|
41
|
+
},
|
|
42
|
+
V1010: {
|
|
43
|
+
cause: "A $ref path the earlier step does not return, a $ref to a step that is not in the transaction, or to a step with no single row (a many or count step).",
|
|
44
|
+
fix: "Select the referenced field in the earlier step, and reference a single-row step.",
|
|
45
|
+
},
|
|
46
|
+
V1011: {
|
|
47
|
+
cause: "The referenced value's type does not fit its target, a nullable source where only a non-null value is accepted included.",
|
|
48
|
+
fix: "Reference a field of the target's type, non-null where the target needs it.",
|
|
49
|
+
},
|
|
50
|
+
V1012: {
|
|
51
|
+
cause: "A nested write that does not fit the relation (a list where one record is expected), a reference field set together with its own relation, one record mixing reference fields and relation writes where the adapter cannot run both, or a record written through a relation that writes that relation (or a field holding its reference) back, where the adapter admits no such write. Also a to-one $update or $upsert beside $connect, $connectOrCreate, $create, $set or $disconnect on the same relation: the row it would update is the newly linked one.",
|
|
52
|
+
fix: "Write either the relation or its reference field, in the relation's cardinality. Relink a to-one relation in one write and update the linked row in another.",
|
|
53
|
+
},
|
|
54
|
+
V1013: {
|
|
55
|
+
cause: "Nested projections, filters or writes deeper than maxNestingDepth.",
|
|
56
|
+
fix: "Nest less, or raise limits.maxNestingDepth.",
|
|
57
|
+
},
|
|
58
|
+
V1014: {
|
|
59
|
+
cause: "A limit above maxListLimit, or more steps than maxTransactionOperations.",
|
|
60
|
+
fix: "Paginate or split the plan, or raise the limit.",
|
|
61
|
+
},
|
|
62
|
+
V1015: {
|
|
63
|
+
cause: "A where tree with more nodes than maxBooleanNodes.",
|
|
64
|
+
fix: "Simplify the filter (in instead of many OR clauses), or raise limits.maxBooleanNodes.",
|
|
65
|
+
},
|
|
66
|
+
V1016: {
|
|
67
|
+
cause: "A $ref to the referencing step itself or a later one, or to an index no step has.",
|
|
68
|
+
fix: "Reference an earlier step only.",
|
|
69
|
+
},
|
|
70
|
+
V1017: {
|
|
71
|
+
cause: "A hand-written plan whose fingerprint does not match its step.",
|
|
72
|
+
fix: "Let the generated client, framework.appTx or framework.clientTx build the plan.",
|
|
73
|
+
},
|
|
74
|
+
V1018: {
|
|
75
|
+
cause: "The referenced step returned no value at that path, such as a first step that matched no row.",
|
|
76
|
+
fix: "Make sure the earlier step returns a row, or use a unique step, which fails with A2003.",
|
|
77
|
+
},
|
|
78
|
+
V1019: {
|
|
79
|
+
cause: "A later step uses a row that an earlier step's delete removed through a database cascade.",
|
|
80
|
+
fix: "Reorder or drop the dependent step.",
|
|
81
|
+
},
|
|
82
|
+
V1020: {
|
|
83
|
+
cause: "One framework.transaction([...]) list mixes appTx and clientTx steps.",
|
|
84
|
+
fix: "Build every step of a plan from one origin.",
|
|
85
|
+
},
|
|
86
|
+
V1021: {
|
|
87
|
+
cause: "A Json field's value nests deeper than maxJsonDepth.",
|
|
88
|
+
fix: "Flatten the value, or raise limits.maxJsonDepth.",
|
|
89
|
+
},
|
|
90
|
+
};
|
|
@@ -13,3 +13,7 @@ export declare function resolveWriteScope(resource: AvResource<AvContract> | und
|
|
|
13
13
|
* unrestricted one, at every depth, under every top-level scope.
|
|
14
14
|
*/
|
|
15
15
|
export declare const NESTED_WRITE_SCOPE: AvWriteScope;
|
|
16
|
+
/** The position a to-many `$update`'s `data` sits in: the flat-bulk write position. */
|
|
17
|
+
export declare const TO_MANY_UPDATE_WRITE_SCOPE: AvWriteScope;
|
|
18
|
+
/** The position of a relation's other end inside a record written through it. */
|
|
19
|
+
export declare const LOOPBACK_WRITE_SCOPE: AvWriteScope;
|
|
@@ -5,3 +5,5 @@ export function resolveWriteScope(resource, request) {
|
|
|
5
5
|
return writeScopeOf(lookupOwn(advertised, request.variant));
|
|
6
6
|
}
|
|
7
7
|
export const NESTED_WRITE_SCOPE = "nested";
|
|
8
|
+
export const TO_MANY_UPDATE_WRITE_SCOPE = "bulkWrite";
|
|
9
|
+
export const LOOPBACK_WRITE_SCOPE = "loopback";
|