ultimabase 0.0.0-stage → 0.1.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/CHANGELOG.md +7 -0
- package/README.md +4 -2
- package/dist/access.d.ts +62 -0
- package/dist/access.d.ts.map +1 -0
- package/dist/access.js +258 -0
- package/dist/adapter-errors.d.ts +43 -0
- package/dist/adapter-errors.d.ts.map +1 -0
- package/dist/adapter-errors.js +72 -0
- package/dist/adapter-json.d.ts +20 -0
- package/dist/adapter-json.d.ts.map +1 -0
- package/dist/adapter-json.js +2 -0
- package/dist/adapter-migrations.d.ts +90 -0
- package/dist/adapter-migrations.d.ts.map +1 -0
- package/dist/adapter-migrations.js +1 -0
- package/dist/adapter.d.ts +333 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +5 -0
- package/dist/aggregate.d.ts +31 -0
- package/dist/aggregate.d.ts.map +1 -0
- package/dist/aggregate.js +99 -0
- package/dist/app-internals.d.ts +10 -0
- package/dist/app-internals.d.ts.map +1 -0
- package/dist/app-internals.js +12 -0
- package/dist/app-options.d.ts +22 -0
- package/dist/app-options.d.ts.map +1 -0
- package/dist/app-options.js +3 -0
- package/dist/cascade.d.ts +47 -0
- package/dist/cascade.d.ts.map +1 -0
- package/dist/cascade.js +209 -0
- package/dist/cli-config.d.ts +6 -0
- package/dist/cli-config.d.ts.map +1 -0
- package/dist/cli-config.js +45 -0
- package/dist/cli-deploy.d.ts +14 -0
- package/dist/cli-deploy.d.ts.map +1 -0
- package/dist/cli-deploy.js +193 -0
- package/dist/cli-main.d.ts +16 -0
- package/dist/cli-main.d.ts.map +1 -0
- package/dist/cli-main.js +151 -0
- package/dist/cli-migrate.d.ts +20 -0
- package/dist/cli-migrate.d.ts.map +1 -0
- package/dist/cli-migrate.js +105 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +4 -0
- package/dist/complete.d.ts +13 -0
- package/dist/complete.d.ts.map +1 -0
- package/dist/complete.js +60 -0
- package/dist/console-logger.d.ts +3 -0
- package/dist/console-logger.d.ts.map +1 -0
- package/dist/console-logger.js +62 -0
- package/dist/create-many.d.ts +7 -0
- package/dist/create-many.d.ts.map +1 -0
- package/dist/create-many.js +88 -0
- package/dist/decimal.d.ts +23 -0
- package/dist/decimal.d.ts.map +1 -0
- package/dist/decimal.js +50 -0
- package/dist/define-app.d.ts +59 -0
- package/dist/define-app.d.ts.map +1 -0
- package/dist/define-app.js +5 -0
- package/dist/define-enum.d.ts +6 -0
- package/dist/define-enum.d.ts.map +1 -0
- package/dist/define-enum.js +18 -0
- package/dist/define-function.d.ts +25 -0
- package/dist/define-function.d.ts.map +1 -0
- package/dist/define-function.js +111 -0
- package/dist/define-model.d.ts +48 -0
- package/dist/define-model.d.ts.map +1 -0
- package/dist/define-model.js +85 -0
- package/dist/definition.d.ts +179 -0
- package/dist/definition.d.ts.map +1 -0
- package/dist/definition.js +165 -0
- package/dist/delete-many.d.ts +13 -0
- package/dist/delete-many.d.ts.map +1 -0
- package/dist/delete-many.js +58 -0
- package/dist/engine.d.ts +16 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +174 -0
- package/dist/errors.d.ts +50 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +43 -0
- package/dist/exact.d.ts +20 -0
- package/dist/exact.d.ts.map +1 -0
- package/dist/exact.js +1 -0
- package/dist/feed.d.ts +6 -0
- package/dist/feed.d.ts.map +1 -0
- package/dist/feed.js +33 -0
- package/dist/field-codec.d.ts +11 -0
- package/dist/field-codec.d.ts.map +1 -0
- package/dist/field-codec.js +48 -0
- package/dist/field-rules.d.ts +57 -0
- package/dist/field-rules.d.ts.map +1 -0
- package/dist/field-rules.js +1 -0
- package/dist/field-type.d.ts +51 -0
- package/dist/field-type.d.ts.map +1 -0
- package/dist/field-type.js +106 -0
- package/dist/fields.d.ts +295 -0
- package/dist/fields.d.ts.map +1 -0
- package/dist/fields.js +1 -0
- package/dist/function.d.ts +126 -0
- package/dist/function.d.ts.map +1 -0
- package/dist/function.js +1 -0
- package/dist/functions.d.ts +18 -0
- package/dist/functions.d.ts.map +1 -0
- package/dist/functions.js +99 -0
- package/dist/group-by.d.ts +10 -0
- package/dist/group-by.d.ts.map +1 -0
- package/dist/group-by.js +145 -0
- package/dist/group-having.d.ts +8 -0
- package/dist/group-having.d.ts.map +1 -0
- package/dist/group-having.js +97 -0
- package/dist/hooks.d.ts +41 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +149 -0
- package/dist/hosts.d.ts +3 -0
- package/dist/hosts.d.ts.map +1 -0
- package/dist/hosts.js +8 -0
- package/dist/identify.d.ts +15 -0
- package/dist/identify.d.ts.map +1 -0
- package/dist/identify.js +71 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/internal.d.ts +28 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +39 -0
- package/dist/lifecycle.d.ts +21 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +149 -0
- package/dist/list-update.d.ts +12 -0
- package/dist/list-update.d.ts.map +1 -0
- package/dist/list-update.js +52 -0
- package/dist/live.d.ts +37 -0
- package/dist/live.d.ts.map +1 -0
- package/dist/live.js +139 -0
- package/dist/manifest.d.ts +11 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +60 -0
- package/dist/memory-aggregate.d.ts +7 -0
- package/dist/memory-aggregate.d.ts.map +1 -0
- package/dist/memory-aggregate.js +107 -0
- package/dist/memory-conditions.d.ts +8 -0
- package/dist/memory-conditions.d.ts.map +1 -0
- package/dist/memory-conditions.js +82 -0
- package/dist/memory-draft.d.ts +34 -0
- package/dist/memory-draft.d.ts.map +1 -0
- package/dist/memory-draft.js +255 -0
- package/dist/memory-json.d.ts +6 -0
- package/dist/memory-json.d.ts.map +1 -0
- package/dist/memory-json.js +86 -0
- package/dist/memory-read.d.ts +45 -0
- package/dist/memory-read.d.ts.map +1 -0
- package/dist/memory-read.js +244 -0
- package/dist/memory-search.d.ts +16 -0
- package/dist/memory-search.d.ts.map +1 -0
- package/dist/memory-search.js +110 -0
- package/dist/memory-values.d.ts +23 -0
- package/dist/memory-values.d.ts.map +1 -0
- package/dist/memory-values.js +82 -0
- package/dist/memory.d.ts +4 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +157 -0
- package/dist/migrate.d.ts +22 -0
- package/dist/migrate.d.ts.map +1 -0
- package/dist/migrate.js +131 -0
- package/dist/model.d.ts +239 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +1 -0
- package/dist/nested-write.d.ts +64 -0
- package/dist/nested-write.d.ts.map +1 -0
- package/dist/nested-write.js +274 -0
- package/dist/number-update.d.ts +18 -0
- package/dist/number-update.d.ts.map +1 -0
- package/dist/number-update.js +96 -0
- package/dist/plugin-app.d.ts +48 -0
- package/dist/plugin-app.d.ts.map +1 -0
- package/dist/plugin-app.js +230 -0
- package/dist/plugin-code.d.ts +17 -0
- package/dist/plugin-code.d.ts.map +1 -0
- package/dist/plugin-code.js +125 -0
- package/dist/plugin-use.d.ts +22 -0
- package/dist/plugin-use.d.ts.map +1 -0
- package/dist/plugin-use.js +161 -0
- package/dist/plugin.d.ts +357 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +17 -0
- package/dist/query-aggregate.d.ts +82 -0
- package/dist/query-aggregate.d.ts.map +1 -0
- package/dist/query-aggregate.js +1 -0
- package/dist/query-args.d.ts +41 -0
- package/dist/query-args.d.ts.map +1 -0
- package/dist/query-args.js +263 -0
- package/dist/query-bulk.d.ts +35 -0
- package/dist/query-bulk.d.ts.map +1 -0
- package/dist/query-bulk.js +1 -0
- package/dist/query-conditions.d.ts +9 -0
- package/dist/query-conditions.d.ts.map +1 -0
- package/dist/query-conditions.js +46 -0
- package/dist/query-context.d.ts +32 -0
- package/dist/query-context.d.ts.map +1 -0
- package/dist/query-context.js +55 -0
- package/dist/query-filter.d.ts +46 -0
- package/dist/query-filter.d.ts.map +1 -0
- package/dist/query-filter.js +1 -0
- package/dist/query-group.d.ts +82 -0
- package/dist/query-group.d.ts.map +1 -0
- package/dist/query-group.js +1 -0
- package/dist/query-json.d.ts +9 -0
- package/dist/query-json.d.ts.map +1 -0
- package/dist/query-json.js +66 -0
- package/dist/query-order.d.ts +15 -0
- package/dist/query-order.d.ts.map +1 -0
- package/dist/query-order.js +115 -0
- package/dist/query-project.d.ts +15 -0
- package/dist/query-project.d.ts.map +1 -0
- package/dist/query-project.js +45 -0
- package/dist/query-search.d.ts +24 -0
- package/dist/query-search.d.ts.map +1 -0
- package/dist/query-search.js +2 -0
- package/dist/query-values.d.ts +28 -0
- package/dist/query-values.d.ts.map +1 -0
- package/dist/query-values.js +91 -0
- package/dist/query-where.d.ts +46 -0
- package/dist/query-where.d.ts.map +1 -0
- package/dist/query-where.js +200 -0
- package/dist/query-write.d.ts +14 -0
- package/dist/query-write.d.ts.map +1 -0
- package/dist/query-write.js +260 -0
- package/dist/query.d.ts +254 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +1 -0
- package/dist/record.d.ts +257 -0
- package/dist/record.d.ts.map +1 -0
- package/dist/record.js +1 -0
- package/dist/recorder.d.ts +32 -0
- package/dist/recorder.d.ts.map +1 -0
- package/dist/recorder.js +152 -0
- package/dist/relation-write.d.ts +41 -0
- package/dist/relation-write.d.ts.map +1 -0
- package/dist/relation-write.js +112 -0
- package/dist/relations.d.ts +42 -0
- package/dist/relations.d.ts.map +1 -0
- package/dist/relations.js +119 -0
- package/dist/rules.d.ts +97 -0
- package/dist/rules.d.ts.map +1 -0
- package/dist/rules.js +71 -0
- package/dist/running.d.ts +29 -0
- package/dist/running.d.ts.map +1 -0
- package/dist/running.js +39 -0
- package/dist/schema-indexes.d.ts +11 -0
- package/dist/schema-indexes.d.ts.map +1 -0
- package/dist/schema-indexes.js +59 -0
- package/dist/schema-virtuals.d.ts +19 -0
- package/dist/schema-virtuals.d.ts.map +1 -0
- package/dist/schema-virtuals.js +100 -0
- package/dist/schema.d.ts +35 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +267 -0
- package/dist/scope.d.ts +46 -0
- package/dist/scope.d.ts.map +1 -0
- package/dist/scope.js +82 -0
- package/dist/scratch.d.ts +14 -0
- package/dist/scratch.d.ts.map +1 -0
- package/dist/scratch.js +10 -0
- package/dist/serve.d.ts +2 -0
- package/dist/serve.d.ts.map +1 -0
- package/dist/serve.js +4 -0
- package/dist/symbols.d.ts +10 -0
- package/dist/symbols.d.ts.map +1 -0
- package/dist/symbols.js +1 -0
- package/dist/transaction.d.ts +28 -0
- package/dist/transaction.d.ts.map +1 -0
- package/dist/transaction.js +156 -0
- package/dist/types.d.ts +58 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/update-many.d.ts +7 -0
- package/dist/update-many.d.ts.map +1 -0
- package/dist/update-many.js +182 -0
- package/dist/uuid.d.ts +7 -0
- package/dist/uuid.d.ts.map +1 -0
- package/dist/uuid.js +48 -0
- package/dist/validation.d.ts +24 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +72 -0
- package/dist/virtual-read.d.ts +9 -0
- package/dist/virtual-read.d.ts.map +1 -0
- package/dist/virtual-read.js +145 -0
- package/dist/virtual.d.ts +142 -0
- package/dist/virtual.d.ts.map +1 -0
- package/dist/virtual.js +1 -0
- package/dist/write-context.d.ts +46 -0
- package/dist/write-context.d.ts.map +1 -0
- package/dist/write-context.js +102 -0
- package/dist/write-data.d.ts +26 -0
- package/dist/write-data.d.ts.map +1 -0
- package/dist/write-data.js +144 -0
- package/dist/write-plan.d.ts +107 -0
- package/dist/write-plan.d.ts.map +1 -0
- package/dist/write-plan.js +170 -0
- package/dist/write-target.d.ts +17 -0
- package/dist/write-target.d.ts.map +1 -0
- package/dist/write-target.js +59 -0
- package/dist/writes.d.ts +23 -0
- package/dist/writes.d.ts.map +1 -0
- package/dist/writes.js +246 -0
- package/dist/writing.d.ts +10 -0
- package/dist/writing.d.ts.map +1 -0
- package/dist/writing.js +66 -0
- package/package.json +42 -3
- package/src/access.ts +329 -0
- package/src/adapter-errors.ts +89 -0
- package/src/adapter-json.ts +21 -0
- package/src/adapter-migrations.ts +98 -0
- package/src/adapter.ts +363 -0
- package/src/aggregate.ts +136 -0
- package/src/app-internals.ts +26 -0
- package/src/app-options.ts +24 -0
- package/src/cascade.ts +297 -0
- package/src/cli-config.ts +45 -0
- package/src/cli-deploy.ts +235 -0
- package/src/cli-main.ts +165 -0
- package/src/cli-migrate.ts +143 -0
- package/src/cli.ts +5 -0
- package/src/complete.ts +73 -0
- package/src/console-logger.ts +87 -0
- package/src/create-many.ts +126 -0
- package/src/decimal.ts +74 -0
- package/src/define-app.ts +108 -0
- package/src/define-enum.ts +26 -0
- package/src/define-function.ts +188 -0
- package/src/define-model.ts +220 -0
- package/src/definition.ts +352 -0
- package/src/delete-many.ts +76 -0
- package/src/engine.ts +281 -0
- package/src/errors.ts +97 -0
- package/src/exact.ts +49 -0
- package/src/feed.ts +39 -0
- package/src/field-codec.ts +72 -0
- package/src/field-rules.ts +77 -0
- package/src/field-type.ts +219 -0
- package/src/fields.ts +383 -0
- package/src/function.ts +143 -0
- package/src/functions.ts +154 -0
- package/src/group-by.ts +186 -0
- package/src/group-having.ts +143 -0
- package/src/hooks.ts +215 -0
- package/src/hosts.ts +11 -0
- package/src/identify.ts +95 -0
- package/src/index.ts +125 -0
- package/src/internal.ts +68 -0
- package/src/lifecycle.ts +214 -0
- package/src/list-update.ts +71 -0
- package/src/live.ts +199 -0
- package/src/manifest.ts +71 -0
- package/src/memory-aggregate.ts +162 -0
- package/src/memory-conditions.ts +88 -0
- package/src/memory-draft.ts +319 -0
- package/src/memory-json.ts +91 -0
- package/src/memory-read.ts +311 -0
- package/src/memory-search.ts +149 -0
- package/src/memory-values.ts +106 -0
- package/src/memory.ts +173 -0
- package/src/migrate.ts +152 -0
- package/src/model.ts +312 -0
- package/src/nested-write.ts +390 -0
- package/src/number-update.ts +142 -0
- package/src/plugin-app.ts +308 -0
- package/src/plugin-code.ts +158 -0
- package/src/plugin-use.ts +217 -0
- package/src/plugin.ts +400 -0
- package/src/query-aggregate.ts +96 -0
- package/src/query-args.ts +375 -0
- package/src/query-bulk.ts +53 -0
- package/src/query-conditions.ts +53 -0
- package/src/query-context.ts +104 -0
- package/src/query-filter.ts +54 -0
- package/src/query-group.ts +137 -0
- package/src/query-json.ts +90 -0
- package/src/query-order.ts +158 -0
- package/src/query-project.ts +73 -0
- package/src/query-search.ts +31 -0
- package/src/query-values.ts +131 -0
- package/src/query-where.ts +318 -0
- package/src/query-write.ts +360 -0
- package/src/query.ts +400 -0
- package/src/record.ts +379 -0
- package/src/recorder.ts +212 -0
- package/src/relation-write.ts +176 -0
- package/src/relations.ts +165 -0
- package/src/rules.ts +188 -0
- package/src/running.ts +62 -0
- package/src/schema-indexes.ts +88 -0
- package/src/schema-virtuals.ts +134 -0
- package/src/schema.ts +367 -0
- package/src/scope.ts +123 -0
- package/src/scratch.ts +28 -0
- package/src/serve.ts +5 -0
- package/src/symbols.ts +11 -0
- package/src/transaction.ts +211 -0
- package/src/types.ts +79 -0
- package/src/update-many.ts +268 -0
- package/src/uuid.ts +51 -0
- package/src/validation.ts +107 -0
- package/src/virtual-read.ts +198 -0
- package/src/virtual.ts +187 -0
- package/src/write-context.ts +170 -0
- package/src/write-data.ts +188 -0
- package/src/write-plan.ts +273 -0
- package/src/write-target.ts +92 -0
- package/src/writes.ts +361 -0
- package/src/writing.ts +93 -0
package/src/adapter.ts
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
// The adapter contract (D-73): what the kernel sends a storage adapter, fully
|
|
2
|
+
// prepared. Names are the models' own; `dbName` says what to store them as.
|
|
3
|
+
import type { JsonCondition } from './adapter-json.ts'
|
|
4
|
+
import type { Migrations } from './adapter-migrations.ts'
|
|
5
|
+
import type { Logger } from './app-options.ts'
|
|
6
|
+
|
|
7
|
+
export type {
|
|
8
|
+
Migration,
|
|
9
|
+
Migrations,
|
|
10
|
+
Run,
|
|
11
|
+
Statement,
|
|
12
|
+
Stored,
|
|
13
|
+
} from './adapter-migrations.ts'
|
|
14
|
+
export {
|
|
15
|
+
CheckFailed,
|
|
16
|
+
MigrationFailed,
|
|
17
|
+
OutOfRange,
|
|
18
|
+
RelationViolation,
|
|
19
|
+
UniqueViolation,
|
|
20
|
+
} from './adapter-errors.ts'
|
|
21
|
+
|
|
22
|
+
export type ScalarType =
|
|
23
|
+
| 'string'
|
|
24
|
+
| 'number'
|
|
25
|
+
| 'decimal'
|
|
26
|
+
| 'boolean'
|
|
27
|
+
| 'dateTime'
|
|
28
|
+
| 'date'
|
|
29
|
+
| 'json'
|
|
30
|
+
| 'enum'
|
|
31
|
+
|
|
32
|
+
export type SchemaField =
|
|
33
|
+
| {
|
|
34
|
+
readonly kind: 'scalar'
|
|
35
|
+
readonly name: string
|
|
36
|
+
readonly type: ScalarType
|
|
37
|
+
/** An `enum`'s values. */
|
|
38
|
+
readonly values?: readonly string[]
|
|
39
|
+
/**
|
|
40
|
+
* A list of `type`, a string, a number or an enum value: never
|
|
41
|
+
* `null`, `[]` when empty (D-120, D-127).
|
|
42
|
+
*/
|
|
43
|
+
readonly list: boolean
|
|
44
|
+
/** A `number` of whole numbers from -2^31 to 2^31 - 1 (D-132). */
|
|
45
|
+
readonly integer?: true
|
|
46
|
+
/**
|
|
47
|
+
* A `decimal`'s digits, `scale` of them after the point; its values
|
|
48
|
+
* are strings at that scale (D-145).
|
|
49
|
+
*/
|
|
50
|
+
readonly precision?: number
|
|
51
|
+
readonly scale?: number
|
|
52
|
+
readonly optional: boolean
|
|
53
|
+
readonly unique: boolean
|
|
54
|
+
/** A `string` in its model's document, which `_search` matches (D-148). */
|
|
55
|
+
readonly search?: true
|
|
56
|
+
readonly dbName?: string
|
|
57
|
+
/** Its default when it is a value, not a function (D-105). */
|
|
58
|
+
readonly default?: unknown
|
|
59
|
+
}
|
|
60
|
+
| {
|
|
61
|
+
readonly kind: 'one'
|
|
62
|
+
readonly name: string
|
|
63
|
+
readonly target: string
|
|
64
|
+
/** The target's field on the other side (D-37). */
|
|
65
|
+
readonly inverse: string
|
|
66
|
+
/** Whether this side stores the key, one per pair (D-37). */
|
|
67
|
+
readonly stored: boolean
|
|
68
|
+
/** One-to-one: the stored key is unique. */
|
|
69
|
+
readonly unique: boolean
|
|
70
|
+
readonly optional: boolean
|
|
71
|
+
readonly onDelete: 'cascade' | 'restrict' | 'setNull'
|
|
72
|
+
readonly dbName?: string
|
|
73
|
+
}
|
|
74
|
+
| {
|
|
75
|
+
readonly kind: 'many'
|
|
76
|
+
readonly name: string
|
|
77
|
+
readonly target: string
|
|
78
|
+
readonly inverse: string
|
|
79
|
+
/** Facing a `many`: a join holding the two keys only (D-64). */
|
|
80
|
+
readonly join: boolean
|
|
81
|
+
/** Its reads see the rows a filter keeps; it takes no `set` (D-151). */
|
|
82
|
+
readonly filtered?: true
|
|
83
|
+
/**
|
|
84
|
+
* A view: read-only, on the link of the `many` it names, with that
|
|
85
|
+
* relation's `inverse` and `join` (D-151).
|
|
86
|
+
*/
|
|
87
|
+
readonly from?: string
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export type SchemaModel = {
|
|
91
|
+
readonly name: string
|
|
92
|
+
readonly dbName?: string
|
|
93
|
+
/** `id`, `createdAt` and `updatedAt` are implicit (D-22). */
|
|
94
|
+
readonly fields: readonly SchemaField[]
|
|
95
|
+
readonly indexes: readonly {
|
|
96
|
+
readonly fields: readonly string[]
|
|
97
|
+
readonly unique: boolean
|
|
98
|
+
/** Serves `contains` and `mode: 'insensitive'` (D-141). */
|
|
99
|
+
readonly contains: boolean
|
|
100
|
+
}[]
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export type Schema = { readonly models: readonly SchemaModel[] }
|
|
104
|
+
|
|
105
|
+
/** A normalized condition on one field: no shorthand, no `undefined`. */
|
|
106
|
+
export type Condition = JsonCondition & {
|
|
107
|
+
readonly equals?: unknown
|
|
108
|
+
readonly not?: unknown
|
|
109
|
+
readonly in?: readonly unknown[]
|
|
110
|
+
readonly notIn?: readonly unknown[]
|
|
111
|
+
readonly lt?: unknown
|
|
112
|
+
readonly lte?: unknown
|
|
113
|
+
readonly gt?: unknown
|
|
114
|
+
readonly gte?: unknown
|
|
115
|
+
readonly contains?: string
|
|
116
|
+
readonly startsWith?: string
|
|
117
|
+
readonly endsWith?: string
|
|
118
|
+
/** The string operators ignore case (D-140). */
|
|
119
|
+
readonly mode?: 'insensitive'
|
|
120
|
+
/** A list holds this element (D-120, D-127). */
|
|
121
|
+
readonly has?: unknown
|
|
122
|
+
/** A list holds one of these elements (D-120, D-127). */
|
|
123
|
+
readonly hasSome?: readonly unknown[]
|
|
124
|
+
/** A list holds each of these elements (D-149). */
|
|
125
|
+
readonly hasEvery?: readonly unknown[]
|
|
126
|
+
/** A list is empty, or not (D-149). */
|
|
127
|
+
readonly isEmpty?: boolean
|
|
128
|
+
readonly is?: Filter | null
|
|
129
|
+
readonly isNot?: Filter | null
|
|
130
|
+
readonly some?: Filter
|
|
131
|
+
readonly every?: Filter
|
|
132
|
+
readonly none?: Filter
|
|
133
|
+
/**
|
|
134
|
+
* A stored `one` key names a row that the delete at this index of the
|
|
135
|
+
* write's changes removed, a change before this one (D-102).
|
|
136
|
+
*/
|
|
137
|
+
readonly removedBy?: number
|
|
138
|
+
/**
|
|
139
|
+
* Under the key `_search`: the row's searched fields match this text, in
|
|
140
|
+
* PostgreSQL's `websearch_to_tsquery` syntax (D-148).
|
|
141
|
+
*/
|
|
142
|
+
readonly search?: string
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** A normalized `where`: `AND`, `OR` and `NOT` are lists (D-73). */
|
|
146
|
+
export interface Filter {
|
|
147
|
+
readonly AND?: readonly Filter[]
|
|
148
|
+
readonly OR?: readonly Filter[]
|
|
149
|
+
readonly NOT?: readonly Filter[]
|
|
150
|
+
readonly [field: string]: Condition | readonly Filter[] | undefined
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** A `one` relation a sort key goes through, to the rows `where` selects. */
|
|
154
|
+
export type Step = { readonly relation: string; readonly where?: Filter }
|
|
155
|
+
|
|
156
|
+
export type Order = {
|
|
157
|
+
/** A field of the row, or of the row `through` reaches. */
|
|
158
|
+
readonly field: string
|
|
159
|
+
readonly direction: 'asc' | 'desc'
|
|
160
|
+
/** Where `null` sorts: by default last ascending, first descending (D-149). */
|
|
161
|
+
readonly nulls?: 'first' | 'last'
|
|
162
|
+
/** The `one` relations followed first; an absent row sorts as `null` (D-134). */
|
|
163
|
+
readonly through?: readonly Step[]
|
|
164
|
+
/** `field` is a `many` relation: its rows this filter selects are counted (D-134). */
|
|
165
|
+
readonly count?: Filter
|
|
166
|
+
/** `field` is `_relevance`: how well the row matches this text (D-148). */
|
|
167
|
+
readonly relevance?: string
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export type Sort = Pick<Order, 'direction' | 'nulls'>
|
|
171
|
+
|
|
172
|
+
/** A relation to read with its rows; a `one` relation reads `where` only. */
|
|
173
|
+
export type Nested = {
|
|
174
|
+
readonly where?: Filter
|
|
175
|
+
/** Always ends with `id`, so the order is total. */
|
|
176
|
+
readonly orderBy?: readonly Order[]
|
|
177
|
+
/** A unique target the page starts at, as Prisma's `cursor`. */
|
|
178
|
+
readonly cursor?: Filter
|
|
179
|
+
readonly skip?: number
|
|
180
|
+
/** Negative: the rows before the cursor, or the last ones. */
|
|
181
|
+
readonly take?: number
|
|
182
|
+
/**
|
|
183
|
+
* The system and scalar fields the rows return, `id` always; absent, every
|
|
184
|
+
* field and each `one` key (D-136).
|
|
185
|
+
*/
|
|
186
|
+
readonly fields?: readonly string[]
|
|
187
|
+
readonly include?: { readonly [field: string]: Nested }
|
|
188
|
+
/** `many` relations to count in the row's `_count`, by filter (D-134). */
|
|
189
|
+
readonly count?: { readonly [field: string]: Filter }
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export type Read = Nested & {
|
|
193
|
+
readonly model: string
|
|
194
|
+
/** Locks the root rows, in `id` order, until the transaction ends (D-99, D-133). */
|
|
195
|
+
readonly lock?: boolean
|
|
196
|
+
/**
|
|
197
|
+
* Keeps, of the rows with the same keys, the first in `orderBy`'s order,
|
|
198
|
+
* before `skip` and `take` (D-147).
|
|
199
|
+
*/
|
|
200
|
+
readonly distinct?: readonly GroupKey[]
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export type CountRead = { readonly model: string; readonly where?: Filter }
|
|
204
|
+
|
|
205
|
+
/** One aggregate: `count` without a field counts the rows (D-143). */
|
|
206
|
+
export type Aggregate = {
|
|
207
|
+
readonly operation: 'count' | 'sum' | 'avg' | 'min' | 'max'
|
|
208
|
+
/** A scalar field, neither a list nor `json`. */
|
|
209
|
+
readonly field?: string
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** A group's key: a field, or the `id` of the row `through` reaches (D-146). */
|
|
213
|
+
export type GroupKey = {
|
|
214
|
+
readonly field: string
|
|
215
|
+
readonly through?: readonly Step[]
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Aggregates of the rows `where` selects, one value each, in order: a count
|
|
220
|
+
* is a number, the others `null` without a value (D-143). With `by`, of each
|
|
221
|
+
* group of rows with the same keys; an absent row gives `null` (D-146).
|
|
222
|
+
*/
|
|
223
|
+
export type AggregateRead = CountRead & {
|
|
224
|
+
readonly aggregates: readonly Aggregate[]
|
|
225
|
+
readonly by?: readonly GroupKey[]
|
|
226
|
+
/** A position, `orderBy`'s `at` or a `having` key (D-149): keys, then aggregates. */
|
|
227
|
+
readonly having?: Filter
|
|
228
|
+
readonly orderBy?: readonly ({ readonly at: number } & Sort)[]
|
|
229
|
+
readonly skip?: number
|
|
230
|
+
readonly take?: number
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* A stored row: system and scalar fields, and each `one` relation as its key
|
|
235
|
+
* `{ id } | null`, or the included row. An included `many` is a list of rows.
|
|
236
|
+
*/
|
|
237
|
+
export type Row = { readonly id: string; readonly [field: string]: unknown }
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* A number update computed on each row the write changes, `null` counting
|
|
241
|
+
* as 0; an integer's division truncates toward zero (D-132).
|
|
242
|
+
*/
|
|
243
|
+
export type Arithmetic = {
|
|
244
|
+
readonly operation: 'increment' | 'decrement' | 'multiply' | 'divide'
|
|
245
|
+
readonly by: number
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* A list update computed on each row the write changes (D-149): `push`
|
|
250
|
+
* appends, `pushUnique` appends each element the list lacks, once, and
|
|
251
|
+
* `remove` drops every occurrence.
|
|
252
|
+
*/
|
|
253
|
+
export type ListUpdate = {
|
|
254
|
+
readonly operation: 'push' | 'pushUnique' | 'remove'
|
|
255
|
+
readonly elements: readonly unknown[]
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/** In a change, a stored `one` key is the target's id or `null`. */
|
|
259
|
+
export type Change =
|
|
260
|
+
| { readonly kind: 'insert'; readonly model: string; readonly row: Row }
|
|
261
|
+
| {
|
|
262
|
+
readonly kind: 'update'
|
|
263
|
+
readonly model: string
|
|
264
|
+
readonly where: Filter
|
|
265
|
+
readonly set: { readonly [field: string]: unknown }
|
|
266
|
+
readonly compute?: {
|
|
267
|
+
readonly [field: string]: Arithmetic | ListUpdate
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
| { readonly kind: 'delete'; readonly model: string; readonly where: Filter }
|
|
271
|
+
| {
|
|
272
|
+
readonly kind: 'link' | 'unlink'
|
|
273
|
+
readonly model: string
|
|
274
|
+
/** A `many` relation facing a `many`. */
|
|
275
|
+
readonly field: string
|
|
276
|
+
readonly id: string
|
|
277
|
+
readonly targets: readonly string[]
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/** A count of rows a write needs before it changes anything (D-99). */
|
|
281
|
+
export type Check = {
|
|
282
|
+
readonly model: string
|
|
283
|
+
readonly where: Filter
|
|
284
|
+
readonly count: number
|
|
285
|
+
/** Locks the rows it counts until the transaction ends, as `Read.lock` (D-99). */
|
|
286
|
+
readonly lock?: boolean
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* One whole write: its checks first, which write nothing when one fails,
|
|
291
|
+
* then its changes, then `read`, in the same write. With `before`, the read
|
|
292
|
+
* selects among the rows of its model that the write's delete removed, as
|
|
293
|
+
* they were (D-102, D-104); when the write deletes none of them, among the
|
|
294
|
+
* rows its first update of that model changed, as it left them (D-133).
|
|
295
|
+
*/
|
|
296
|
+
export type Write = {
|
|
297
|
+
readonly checks?: readonly Check[]
|
|
298
|
+
readonly changes: readonly Change[]
|
|
299
|
+
readonly read?: Read
|
|
300
|
+
readonly before?: boolean
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* What a committed write changed (D-154): `ids` is absent when they were
|
|
305
|
+
* more than `feedIds`, `fields` when they were every field or longer than
|
|
306
|
+
* `feedFields`. A delete's links go with its rows, unlisted. How changes
|
|
307
|
+
* group into entries and calls is the adapter's.
|
|
308
|
+
*/
|
|
309
|
+
export type Changed =
|
|
310
|
+
| {
|
|
311
|
+
readonly kind: 'insert' | 'update' | 'delete'
|
|
312
|
+
readonly model: string
|
|
313
|
+
readonly ids?: readonly string[]
|
|
314
|
+
/** The fields an update set, `updatedAt` included. */
|
|
315
|
+
readonly fields?: readonly string[]
|
|
316
|
+
}
|
|
317
|
+
| {
|
|
318
|
+
readonly kind: 'link' | 'unlink'
|
|
319
|
+
readonly model: string
|
|
320
|
+
/** A `many` relation facing a `many`. */
|
|
321
|
+
readonly field: string
|
|
322
|
+
/** The model's id, then the target's. */
|
|
323
|
+
readonly pairs?: readonly (readonly [string, string])[]
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/** The most ids or pairs a change lists (D-154). */
|
|
327
|
+
export const feedIds = 1000
|
|
328
|
+
/** The longest list of fields, as JSON, an update lists (D-154). */
|
|
329
|
+
export const feedFields = 1500
|
|
330
|
+
|
|
331
|
+
/** Where an adapter sends the changes each commit makes, on any server. */
|
|
332
|
+
export type Feed = {
|
|
333
|
+
readonly changed: (changes: readonly Changed[]) => void
|
|
334
|
+
/** Changes may have been lost, as when a listener reconnects. */
|
|
335
|
+
readonly missed: () => void
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export interface Transaction {
|
|
339
|
+
find(read: Read): Promise<Row[]>
|
|
340
|
+
count(read: CountRead): Promise<number>
|
|
341
|
+
/**
|
|
342
|
+
* One list per group: its keys' values, then its aggregates'; without
|
|
343
|
+
* `by`, one list, even without rows (D-146).
|
|
344
|
+
*/
|
|
345
|
+
aggregate(read: AggregateRead): Promise<unknown[][]>
|
|
346
|
+
write(write: Write): Promise<Row[]>
|
|
347
|
+
commit(): Promise<void>
|
|
348
|
+
rollback(): Promise<void>
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/** A storage adapter: its own slot, not a plugin (D-02, D-73). */
|
|
352
|
+
export interface Adapter extends Omit<Transaction, 'commit' | 'rollback'> {
|
|
353
|
+
/**
|
|
354
|
+
* Connects; the kernel then syncs or checks the tables (D-105). `logger`
|
|
355
|
+
* is the kernel's, for what the adapter reports (D-140). With `feed`, each
|
|
356
|
+
* commit's changes reach it, this server's and the others' (D-154).
|
|
357
|
+
*/
|
|
358
|
+
start(schema: Schema, logger: Logger, feed?: Feed): Promise<void>
|
|
359
|
+
stop(): Promise<void>
|
|
360
|
+
begin(): Promise<Transaction>
|
|
361
|
+
/** None for a database that starts empty every time, as `memory()`. */
|
|
362
|
+
readonly migrations?: Migrations
|
|
363
|
+
}
|
package/src/aggregate.ts
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// `aggregate` (D-143): counts, sums, averages, minimums and maximums of the
|
|
2
|
+
// rows the caller reads, on scalar fields it may filter on.
|
|
3
|
+
import type { Aggregate } from './adapter.ts'
|
|
4
|
+
import { InvalidQuery } from './errors.ts'
|
|
5
|
+
import type { Context } from './query-context.ts'
|
|
6
|
+
import { filtered, given } from './query-context.ts'
|
|
7
|
+
import { entries, systemFields, unknownKey } from './query-where.ts'
|
|
8
|
+
import type { ModelInfo } from './schema.ts'
|
|
9
|
+
import type { Store } from './transaction.ts'
|
|
10
|
+
|
|
11
|
+
const operations = {
|
|
12
|
+
_count: 'count',
|
|
13
|
+
_sum: 'sum',
|
|
14
|
+
_avg: 'avg',
|
|
15
|
+
_min: 'min',
|
|
16
|
+
_max: 'max',
|
|
17
|
+
} as const
|
|
18
|
+
export type Key = keyof typeof operations
|
|
19
|
+
export const keys: readonly Key[] = ['_count', '_sum', '_avg', '_min', '_max']
|
|
20
|
+
|
|
21
|
+
/** The types each aggregate takes; `_count` takes every scalar. */
|
|
22
|
+
const takes: { readonly [K in Key]?: readonly string[] } = {
|
|
23
|
+
_sum: ['number', 'decimal'],
|
|
24
|
+
_avg: ['number', 'decimal'],
|
|
25
|
+
_min: ['number', 'decimal', 'string', 'enum', 'dateTime', 'date'],
|
|
26
|
+
_max: ['number', 'decimal', 'string', 'enum', 'dateTime', 'date'],
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** The field's type, which fails on a field an aggregate cannot take. */
|
|
30
|
+
export function typeOf(
|
|
31
|
+
model: ModelInfo,
|
|
32
|
+
field: string,
|
|
33
|
+
path: string,
|
|
34
|
+
verb = 'aggregated',
|
|
35
|
+
): string {
|
|
36
|
+
const refuse = (kind: string): never => {
|
|
37
|
+
throw new InvalidQuery(path, `${path} is ${kind}, which cannot be ${verb}.`)
|
|
38
|
+
}
|
|
39
|
+
const known = model.fields.get(field)
|
|
40
|
+
if (known === undefined) {
|
|
41
|
+
if (!systemFields.includes(field)) throw unknownKey(path, model.name)
|
|
42
|
+
return field === 'id' ? 'string' : 'dateTime'
|
|
43
|
+
}
|
|
44
|
+
if (known.kind !== 'scalar') return refuse('a relation')
|
|
45
|
+
if (known.list) return refuse('a list')
|
|
46
|
+
if (known.type === 'json') return refuse('json')
|
|
47
|
+
if (known.codec !== undefined) return refuse('a plugin field')
|
|
48
|
+
return known.type
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export type Asked = { readonly key: Key; readonly field: string | undefined }
|
|
52
|
+
|
|
53
|
+
/** Aggregate `key` of `field`, checked; `_all` counts the rows. */
|
|
54
|
+
export function checked(
|
|
55
|
+
{ model, scope }: Context,
|
|
56
|
+
key: Key,
|
|
57
|
+
field: string,
|
|
58
|
+
path: string,
|
|
59
|
+
): Asked {
|
|
60
|
+
if (key === '_count' && field === '_all') return { key, field: undefined }
|
|
61
|
+
const type = typeOf(model, field, path)
|
|
62
|
+
const types = takes[key]
|
|
63
|
+
if (types !== undefined && !types.includes(type)) {
|
|
64
|
+
throw new InvalidQuery(
|
|
65
|
+
path,
|
|
66
|
+
`${path} is a ${type} field; ${key} takes ${types.join(', ')} fields.`,
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
scope.check(model, field, path, 'aggregates')
|
|
70
|
+
return { key, field }
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** The aggregates `key` asks for, each checked. */
|
|
74
|
+
function asked(context: Context, key: Key, value: unknown): readonly Asked[] {
|
|
75
|
+
if (key === '_count' && value === true) return [{ key, field: undefined }]
|
|
76
|
+
return entries(value, key).map(([field, flag]): Asked => {
|
|
77
|
+
const path = `${key}.${field}`
|
|
78
|
+
if (flag !== true) {
|
|
79
|
+
throw new InvalidQuery(path, `${path} must be true.`)
|
|
80
|
+
}
|
|
81
|
+
return checked(context, key, field, path)
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** The aggregates the arguments ask for, in the order of `keys`. */
|
|
86
|
+
export const wanted = (
|
|
87
|
+
context: Context,
|
|
88
|
+
found: ReadonlyMap<string, unknown>,
|
|
89
|
+
): readonly Asked[] =>
|
|
90
|
+
keys.flatMap((key) =>
|
|
91
|
+
found.has(key) ? asked(context, key, found.get(key)) : [],
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
export const toAggregate = ({ key, field }: Asked): Aggregate => ({
|
|
95
|
+
operation: operations[key],
|
|
96
|
+
...(field !== undefined && { field }),
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
/** The aggregates' values under the keys the arguments ask for. */
|
|
100
|
+
export function shaped(
|
|
101
|
+
found: ReadonlyMap<string, unknown>,
|
|
102
|
+
list: readonly Asked[],
|
|
103
|
+
values: readonly unknown[],
|
|
104
|
+
): { [key: string]: unknown } {
|
|
105
|
+
const result: { [key: string]: unknown } = {}
|
|
106
|
+
for (const [index, { key, field }] of list.entries()) {
|
|
107
|
+
const value = values[index]
|
|
108
|
+
if (key === '_count' && found.get(key) === true) {
|
|
109
|
+
result[key] = value
|
|
110
|
+
continue
|
|
111
|
+
}
|
|
112
|
+
const fields = result[key] ?? {}
|
|
113
|
+
result[key] = { ...fields, [field ?? '_all']: value }
|
|
114
|
+
}
|
|
115
|
+
for (const key of keys) {
|
|
116
|
+
if (found.has(key)) result[key] ??= {}
|
|
117
|
+
}
|
|
118
|
+
return result
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export async function aggregate(
|
|
122
|
+
context: Context,
|
|
123
|
+
store: Store,
|
|
124
|
+
args: unknown,
|
|
125
|
+
): Promise<unknown> {
|
|
126
|
+
const { model } = context
|
|
127
|
+
const found = given(args, model.name, ['where', ...keys], [])
|
|
128
|
+
const list = wanted(context, found)
|
|
129
|
+
const where = await filtered(context, found, 'read')
|
|
130
|
+
const [values = []] = await store.aggregate({
|
|
131
|
+
model: model.name,
|
|
132
|
+
...(where && { where }),
|
|
133
|
+
aggregates: list.map(toAggregate),
|
|
134
|
+
})
|
|
135
|
+
return shaped(found, list, values)
|
|
136
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// What the `ultimabase` commands read from an application (D-105): its
|
|
2
|
+
// options and its lifecycle, kept off its public surface.
|
|
3
|
+
import type { Lifecycle, LifecycleOptions } from './lifecycle.ts'
|
|
4
|
+
|
|
5
|
+
export type Internals = {
|
|
6
|
+
readonly options: LifecycleOptions
|
|
7
|
+
readonly app: Lifecycle
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const internals = new WeakMap<object, Internals>()
|
|
11
|
+
|
|
12
|
+
/** Remembers the options `defineApp` built `app` from. */
|
|
13
|
+
export function remember<T extends Lifecycle>(
|
|
14
|
+
app: T,
|
|
15
|
+
options: LifecycleOptions,
|
|
16
|
+
): T {
|
|
17
|
+
internals.set(app, { options, app })
|
|
18
|
+
return app
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** What `defineApp` kept of a value it returned, or `undefined`. */
|
|
22
|
+
export function internalsOf(value: unknown): Internals | undefined {
|
|
23
|
+
return typeof value === 'object' && value !== null
|
|
24
|
+
? internals.get(value)
|
|
25
|
+
: undefined
|
|
26
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// What `defineApp` takes beside its database, plugins and models (D-49,
|
|
2
|
+
// D-58).
|
|
3
|
+
|
|
4
|
+
type LogFunction = {
|
|
5
|
+
(message: string): void
|
|
6
|
+
(bindings: object, message?: string): void
|
|
7
|
+
}
|
|
8
|
+
/** Pino's interface (D-58); without one, the kernel writes JSON lines. */
|
|
9
|
+
export interface Logger {
|
|
10
|
+
readonly info: LogFunction
|
|
11
|
+
readonly warn: LogFunction
|
|
12
|
+
readonly error: LogFunction
|
|
13
|
+
child(bindings: object): Logger
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Refused in production unless written `{ key, production: true }`, with 32
|
|
18
|
+
* characters at least (D-49).
|
|
19
|
+
* `undefined` leaves it off, so an unset environment variable passes as is.
|
|
20
|
+
*/
|
|
21
|
+
export type MasterKey =
|
|
22
|
+
| string
|
|
23
|
+
| undefined
|
|
24
|
+
| { readonly key: string | undefined; readonly production: true }
|