@relations-dil/relations 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/LICENSE +21 -0
- package/README.md +824 -0
- package/dist/dynamic.d.ts +122 -0
- package/dist/dynamic.js +164 -0
- package/dist/errors.d.ts +31 -0
- package/dist/errors.js +50 -0
- package/dist/field.d.ts +157 -0
- package/dist/field.js +660 -0
- package/dist/index.d.ts +59 -0
- package/dist/index.js +75 -0
- package/dist/kinds.d.ts +99 -0
- package/dist/kinds.js +169 -0
- package/dist/migrations.d.ts +62 -0
- package/dist/migrations.js +293 -0
- package/dist/mock.d.ts +88 -0
- package/dist/mock.js +511 -0
- package/dist/model.d.ts +277 -0
- package/dist/model.js +1159 -0
- package/dist/overscore.d.ts +66 -0
- package/dist/overscore.js +226 -0
- package/dist/record.d.ts +58 -0
- package/dist/record.js +246 -0
- package/dist/registry.d.ts +24 -0
- package/dist/registry.js +27 -0
- package/dist/relation.d.ts +114 -0
- package/dist/relation.js +145 -0
- package/dist/source.d.ts +147 -0
- package/dist/source.js +409 -0
- package/dist/titles.d.ts +43 -0
- package/dist/titles.js +115 -0
- package/dist/typed.d.ts +99 -0
- package/dist/typed.js +44 -0
- package/dist/util.d.ts +16 -0
- package/dist/util.js +117 -0
- package/package.json +68 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Models from data.
|
|
3
|
+
*
|
|
4
|
+
* `identity.define()` turns a model class into a plain, backend-neutral object. This
|
|
5
|
+
* module goes the other way: it turns that object back into a working model class. The
|
|
6
|
+
* round trip means a set of models can be written as data - JSON, YAML, a database row,
|
|
7
|
+
* a form in a UI - saved, shipped, and loaded somewhere that has never seen the code.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { modelsFrom } from '@relations-dil/relations'
|
|
11
|
+
* import { parse } from 'yaml' // any YAML parser; relations has no opinion
|
|
12
|
+
*
|
|
13
|
+
* const app = parse(await readFile('app.yaml', 'utf8'))
|
|
14
|
+
* const { Unit, Test } = modelsFrom(app.models, { relations: app.relations })
|
|
15
|
+
*
|
|
16
|
+
* await new Unit('yep').create()
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* The YAML for that looks like:
|
|
20
|
+
*
|
|
21
|
+
* ```yaml
|
|
22
|
+
* models:
|
|
23
|
+
* unit:
|
|
24
|
+
* source: example
|
|
25
|
+
* name: unit
|
|
26
|
+
* fields:
|
|
27
|
+
* - {kind: int, name: id, store: id, auto: true}
|
|
28
|
+
* - {kind: str, name: name, store: name, none: false}
|
|
29
|
+
* test:
|
|
30
|
+
* source: example
|
|
31
|
+
* name: test
|
|
32
|
+
* fields:
|
|
33
|
+
* - {kind: int, name: id, store: id, auto: true}
|
|
34
|
+
* - {kind: int, name: unit_id, store: unit_id}
|
|
35
|
+
* - {kind: str, name: name, store: name, none: false}
|
|
36
|
+
* relations:
|
|
37
|
+
* - {kind: OneToMany, parent: unit, child: test}
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
import { type ModelClass } from './model.js';
|
|
41
|
+
import { type ManyToManyOptions, type OneToOptions } from './relation.js';
|
|
42
|
+
/** A model definition, as `identity.define()` emits it. */
|
|
43
|
+
export interface Definition {
|
|
44
|
+
/** Name of the source the model lives in. */
|
|
45
|
+
source?: string;
|
|
46
|
+
/** Name of the model in the source. */
|
|
47
|
+
name: string;
|
|
48
|
+
/** Human-facing title. */
|
|
49
|
+
title?: string;
|
|
50
|
+
/** Whether this model is a many-to-many tie table. */
|
|
51
|
+
tie?: boolean;
|
|
52
|
+
/** Field definitions, in order. */
|
|
53
|
+
fields: globalThis.Record<string, any>[];
|
|
54
|
+
/** Which field is the id. */
|
|
55
|
+
id?: string | null;
|
|
56
|
+
/** Which fields make up a title. Optional; derived when absent. */
|
|
57
|
+
titles?: string | string[];
|
|
58
|
+
/** Which fields to show in a listing. Optional; derived when absent. */
|
|
59
|
+
list?: string | string[];
|
|
60
|
+
/** Unique indexes. */
|
|
61
|
+
unique?: globalThis.Record<string, string[]>;
|
|
62
|
+
/** Regular indexes. */
|
|
63
|
+
index?: globalThis.Record<string, string[]>;
|
|
64
|
+
/** Default sort order. */
|
|
65
|
+
order?: string | string[];
|
|
66
|
+
/** Default chunk size. */
|
|
67
|
+
chunk?: number;
|
|
68
|
+
}
|
|
69
|
+
/** A relation between two definitions, by model name. */
|
|
70
|
+
export interface RelationDefinition {
|
|
71
|
+
/** Which kind of relation. */
|
|
72
|
+
kind: 'OneToMany' | 'OneToOne' | 'ManyToMany';
|
|
73
|
+
/** The one side, for a one-to-* relation. */
|
|
74
|
+
parent?: string;
|
|
75
|
+
/** The many side, for a one-to-* relation. */
|
|
76
|
+
child?: string;
|
|
77
|
+
/** The first side of a many-to-many. */
|
|
78
|
+
sister?: string;
|
|
79
|
+
/** The second side of a many-to-many. */
|
|
80
|
+
brother?: string;
|
|
81
|
+
/** The joining model of a many-to-many. */
|
|
82
|
+
tie?: string;
|
|
83
|
+
/** Anything the relation lets you spell out instead of inferring. */
|
|
84
|
+
options?: OneToOptions & ManyToManyOptions;
|
|
85
|
+
}
|
|
86
|
+
/** What `modelsFrom` gives you back. */
|
|
87
|
+
export type Built = globalThis.Record<string, ModelClass>;
|
|
88
|
+
/**
|
|
89
|
+
* A model class built from a definition. Extend the result, or use it as it is.
|
|
90
|
+
*
|
|
91
|
+
* ```ts
|
|
92
|
+
* const Unit = modelFrom({
|
|
93
|
+
* source: 'example',
|
|
94
|
+
* name: 'unit',
|
|
95
|
+
* fields: [
|
|
96
|
+
* { kind: 'int', name: 'id', store: 'id', auto: true },
|
|
97
|
+
* { kind: 'str', name: 'name', store: 'name', none: false }
|
|
98
|
+
* ],
|
|
99
|
+
* id: 'id',
|
|
100
|
+
* unique: { name: ['name'] }
|
|
101
|
+
* })
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
export declare function modelFrom(definition: Definition, base?: ModelClass): ModelClass;
|
|
105
|
+
/**
|
|
106
|
+
* Every model in a set of definitions, wired up. Pass `relations` to connect them; the
|
|
107
|
+
* names in each relation refer to the keys of `definitions`, or to a definition's `name`.
|
|
108
|
+
*
|
|
109
|
+
* ```ts
|
|
110
|
+
* const { unit, test } = modelsFrom(
|
|
111
|
+
* { unit: unitDefinition, test: testDefinition },
|
|
112
|
+
* { relations: [{ kind: 'OneToMany', parent: 'unit', child: 'test' }] }
|
|
113
|
+
* )
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export declare function modelsFrom(definitions: globalThis.Record<string, Definition> | Definition[], options?: {
|
|
117
|
+
relations?: RelationDefinition[];
|
|
118
|
+
base?: ModelClass;
|
|
119
|
+
}): Built;
|
|
120
|
+
/** The definitions for a set of model classes, keyed by model name - the way back out. */
|
|
121
|
+
export declare function definitionsOf(models: ModelClass[]): globalThis.Record<string, Definition>;
|
|
122
|
+
//# sourceMappingURL=dynamic.d.ts.map
|
package/dist/dynamic.js
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Models from data.
|
|
3
|
+
*
|
|
4
|
+
* `identity.define()` turns a model class into a plain, backend-neutral object. This
|
|
5
|
+
* module goes the other way: it turns that object back into a working model class. The
|
|
6
|
+
* round trip means a set of models can be written as data - JSON, YAML, a database row,
|
|
7
|
+
* a form in a UI - saved, shipped, and loaded somewhere that has never seen the code.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { modelsFrom } from '@relations-dil/relations'
|
|
11
|
+
* import { parse } from 'yaml' // any YAML parser; relations has no opinion
|
|
12
|
+
*
|
|
13
|
+
* const app = parse(await readFile('app.yaml', 'utf8'))
|
|
14
|
+
* const { Unit, Test } = modelsFrom(app.models, { relations: app.relations })
|
|
15
|
+
*
|
|
16
|
+
* await new Unit('yep').create()
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* The YAML for that looks like:
|
|
20
|
+
*
|
|
21
|
+
* ```yaml
|
|
22
|
+
* models:
|
|
23
|
+
* unit:
|
|
24
|
+
* source: example
|
|
25
|
+
* name: unit
|
|
26
|
+
* fields:
|
|
27
|
+
* - {kind: int, name: id, store: id, auto: true}
|
|
28
|
+
* - {kind: str, name: name, store: name, none: false}
|
|
29
|
+
* test:
|
|
30
|
+
* source: example
|
|
31
|
+
* name: test
|
|
32
|
+
* fields:
|
|
33
|
+
* - {kind: int, name: id, store: id, auto: true}
|
|
34
|
+
* - {kind: int, name: unit_id, store: unit_id}
|
|
35
|
+
* - {kind: str, name: name, store: name, none: false}
|
|
36
|
+
* relations:
|
|
37
|
+
* - {kind: OneToMany, parent: unit, child: test}
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
import { ModelError } from './errors.js';
|
|
41
|
+
import { kindOf, str } from './kinds.js';
|
|
42
|
+
import { Model } from './model.js';
|
|
43
|
+
import { ManyToMany, OneToMany, OneToOne } from './relation.js';
|
|
44
|
+
function fieldFrom(definition) {
|
|
45
|
+
const { kind: kindName, name, ...options } = definition;
|
|
46
|
+
const kind = kindOf(kindName);
|
|
47
|
+
if (kind === undefined) {
|
|
48
|
+
throw new ModelError(null, `unknown kind '${kindName}' for field '${name}' - expected one of bool, int, float, str, set, list, dict`);
|
|
49
|
+
}
|
|
50
|
+
if (options.extract) {
|
|
51
|
+
options.extract = Object.fromEntries(Object.entries(options.extract).map(([path, each]) => [
|
|
52
|
+
path,
|
|
53
|
+
kindOf(each) ?? str
|
|
54
|
+
]));
|
|
55
|
+
}
|
|
56
|
+
return [name, { kind, ...options }];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* A model class built from a definition. Extend the result, or use it as it is.
|
|
60
|
+
*
|
|
61
|
+
* ```ts
|
|
62
|
+
* const Unit = modelFrom({
|
|
63
|
+
* source: 'example',
|
|
64
|
+
* name: 'unit',
|
|
65
|
+
* fields: [
|
|
66
|
+
* { kind: 'int', name: 'id', store: 'id', auto: true },
|
|
67
|
+
* { kind: 'str', name: 'name', store: 'name', none: false }
|
|
68
|
+
* ],
|
|
69
|
+
* id: 'id',
|
|
70
|
+
* unique: { name: ['name'] }
|
|
71
|
+
* })
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export function modelFrom(definition, base = Model) {
|
|
75
|
+
const spec = {};
|
|
76
|
+
for (const field of definition.fields ?? []) {
|
|
77
|
+
const [name, made] = fieldFrom(field);
|
|
78
|
+
spec[name] = made;
|
|
79
|
+
}
|
|
80
|
+
class Defined extends base {
|
|
81
|
+
static fields = spec;
|
|
82
|
+
}
|
|
83
|
+
const cls = Defined;
|
|
84
|
+
cls.store = definition.name;
|
|
85
|
+
cls.source = definition.source ?? base.source;
|
|
86
|
+
cls.id = definition.id ?? null;
|
|
87
|
+
if (definition.title !== undefined) {
|
|
88
|
+
cls.title = definition.title;
|
|
89
|
+
}
|
|
90
|
+
if (definition.titles !== undefined) {
|
|
91
|
+
cls.titles = definition.titles;
|
|
92
|
+
}
|
|
93
|
+
if (definition.list !== undefined) {
|
|
94
|
+
cls.list = definition.list;
|
|
95
|
+
}
|
|
96
|
+
if (definition.unique !== undefined) {
|
|
97
|
+
cls.unique = definition.unique;
|
|
98
|
+
}
|
|
99
|
+
if (definition.index !== undefined) {
|
|
100
|
+
cls.index = definition.index;
|
|
101
|
+
}
|
|
102
|
+
if (definition.order !== undefined) {
|
|
103
|
+
cls.order = definition.order;
|
|
104
|
+
}
|
|
105
|
+
if (definition.chunk !== undefined) {
|
|
106
|
+
cls.chunk = definition.chunk;
|
|
107
|
+
}
|
|
108
|
+
if (definition.tie !== undefined) {
|
|
109
|
+
cls.TIE = definition.tie;
|
|
110
|
+
}
|
|
111
|
+
Object.defineProperty(cls, 'name', { value: definition.title ?? definition.name, configurable: true });
|
|
112
|
+
return cls;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Every model in a set of definitions, wired up. Pass `relations` to connect them; the
|
|
116
|
+
* names in each relation refer to the keys of `definitions`, or to a definition's `name`.
|
|
117
|
+
*
|
|
118
|
+
* ```ts
|
|
119
|
+
* const { unit, test } = modelsFrom(
|
|
120
|
+
* { unit: unitDefinition, test: testDefinition },
|
|
121
|
+
* { relations: [{ kind: 'OneToMany', parent: 'unit', child: 'test' }] }
|
|
122
|
+
* )
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
export function modelsFrom(definitions, options = {}) {
|
|
126
|
+
const entries = Array.isArray(definitions)
|
|
127
|
+
? definitions.map((definition) => [definition.name, definition])
|
|
128
|
+
: Object.entries(definitions).map(([key, definition]) => [definition.name ?? key, definition]);
|
|
129
|
+
const built = {};
|
|
130
|
+
for (const [name, definition] of entries) {
|
|
131
|
+
built[name] = modelFrom({ ...definition, name: definition.name ?? name }, options.base);
|
|
132
|
+
}
|
|
133
|
+
const need = (name, relation) => {
|
|
134
|
+
if (name === undefined || built[name] === undefined) {
|
|
135
|
+
throw new ModelError(null, `relation ${relation.kind} refers to unknown model '${name}'`);
|
|
136
|
+
}
|
|
137
|
+
return built[name];
|
|
138
|
+
};
|
|
139
|
+
for (const relation of options.relations ?? []) {
|
|
140
|
+
if (relation.kind === 'OneToMany') {
|
|
141
|
+
new OneToMany(need(relation.parent, relation), need(relation.child, relation), relation.options);
|
|
142
|
+
}
|
|
143
|
+
else if (relation.kind === 'OneToOne') {
|
|
144
|
+
new OneToOne(need(relation.parent, relation), need(relation.child, relation), relation.options);
|
|
145
|
+
}
|
|
146
|
+
else if (relation.kind === 'ManyToMany') {
|
|
147
|
+
new ManyToMany(need(relation.sister, relation), need(relation.brother, relation), need(relation.tie, relation), relation.options);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
throw new ModelError(null, `unknown relation kind '${relation.kind}'`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return built;
|
|
154
|
+
}
|
|
155
|
+
/** The definitions for a set of model classes, keyed by model name - the way back out. */
|
|
156
|
+
export function definitionsOf(models) {
|
|
157
|
+
const definitions = {};
|
|
158
|
+
for (const model of models) {
|
|
159
|
+
const definition = model.thy().define();
|
|
160
|
+
definitions[definition.name] = definition;
|
|
161
|
+
}
|
|
162
|
+
return definitions;
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=dynamic.js.map
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error classes. Each one carries the thing that went wrong, not just a message,
|
|
3
|
+
* so callers can branch on the field or model involved.
|
|
4
|
+
*/
|
|
5
|
+
/** Something invalid about a field's definition, value, or criteria. */
|
|
6
|
+
export declare class FieldError extends Error {
|
|
7
|
+
field: any;
|
|
8
|
+
constructor(field: any, message: string);
|
|
9
|
+
}
|
|
10
|
+
/** Something invalid about a record - usually an unknown field name. */
|
|
11
|
+
export declare class RecordError extends Error {
|
|
12
|
+
record: any;
|
|
13
|
+
constructor(record: any, message: string);
|
|
14
|
+
}
|
|
15
|
+
/** Something invalid about a model, its identity, or the action being attempted. */
|
|
16
|
+
export declare class ModelError extends Error {
|
|
17
|
+
/** The model the error is about. */
|
|
18
|
+
model: any;
|
|
19
|
+
/** The message on its own, without the model name in front. */
|
|
20
|
+
detail: string;
|
|
21
|
+
constructor(model: any, message: string);
|
|
22
|
+
}
|
|
23
|
+
/** A unique index was violated. Sources throw this and roll back. */
|
|
24
|
+
export declare class UniqueError extends ModelError {
|
|
25
|
+
constructor(model: any, message: string);
|
|
26
|
+
}
|
|
27
|
+
/** Something went wrong diffing or applying migrations. */
|
|
28
|
+
export declare class MigrationsError extends Error {
|
|
29
|
+
constructor(message: string);
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=errors.d.ts.map
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error classes. Each one carries the thing that went wrong, not just a message,
|
|
3
|
+
* so callers can branch on the field or model involved.
|
|
4
|
+
*/
|
|
5
|
+
/** Something invalid about a field's definition, value, or criteria. */
|
|
6
|
+
export class FieldError extends Error {
|
|
7
|
+
field;
|
|
8
|
+
constructor(field, message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = 'FieldError';
|
|
11
|
+
this.field = field;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/** Something invalid about a record - usually an unknown field name. */
|
|
15
|
+
export class RecordError extends Error {
|
|
16
|
+
record;
|
|
17
|
+
constructor(record, message) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = 'RecordError';
|
|
20
|
+
this.record = record;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/** Something invalid about a model, its identity, or the action being attempted. */
|
|
24
|
+
export class ModelError extends Error {
|
|
25
|
+
/** The model the error is about. */
|
|
26
|
+
model;
|
|
27
|
+
/** The message on its own, without the model name in front. */
|
|
28
|
+
detail;
|
|
29
|
+
constructor(model, message) {
|
|
30
|
+
super(`${model?.NAME ?? 'model'}: ${message}`);
|
|
31
|
+
this.name = 'ModelError';
|
|
32
|
+
this.model = model;
|
|
33
|
+
this.detail = message;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/** A unique index was violated. Sources throw this and roll back. */
|
|
37
|
+
export class UniqueError extends ModelError {
|
|
38
|
+
constructor(model, message) {
|
|
39
|
+
super(model, message);
|
|
40
|
+
this.name = 'UniqueError';
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** Something went wrong diffing or applying migrations. */
|
|
44
|
+
export class MigrationsError extends Error {
|
|
45
|
+
constructor(message) {
|
|
46
|
+
super(message);
|
|
47
|
+
this.name = 'MigrationsError';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=errors.js.map
|
package/dist/field.d.ts
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fields: the typed, validating, filterable units a record is made of.
|
|
3
|
+
*/
|
|
4
|
+
import * as overscore from './overscore.js';
|
|
5
|
+
import { type FieldKind, type Kind } from './kinds.js';
|
|
6
|
+
/** How values map onto a class kind's properties, or a function that writes them. */
|
|
7
|
+
export type Attr = string | string[] | Record<string, string> | ((values: Record<string, any>, value: any) => void);
|
|
8
|
+
/** How a stored value maps back onto a class kind's constructor. */
|
|
9
|
+
export type Init = string | string[] | Record<string, string> | ((value: any) => any);
|
|
10
|
+
/** How a value is checked beyond its kind: a regular expression or a predicate. */
|
|
11
|
+
export type Validation = string | RegExp | ((value: any) => boolean);
|
|
12
|
+
/** Everything you can say about a field beyond its kind. */
|
|
13
|
+
export interface FieldOptions {
|
|
14
|
+
/** Name in the model. Set for you from the key in `static fields`. */
|
|
15
|
+
name?: string;
|
|
16
|
+
/** Name used when reading and writing to the source. Defaults to `name`. Set `false` to never store. */
|
|
17
|
+
store?: string | false;
|
|
18
|
+
/** Whether this field carries a many-to-many tie. Managed by relations. */
|
|
19
|
+
tied?: boolean;
|
|
20
|
+
/** How to flatten a class-kind value into storable values. Required for class kinds. */
|
|
21
|
+
attr?: Attr;
|
|
22
|
+
/** How to build a class-kind value back from stored values. Defaults to `attr`. */
|
|
23
|
+
init?: Init;
|
|
24
|
+
/** Which attributes make up this field's titles. Defaults to `attr`. */
|
|
25
|
+
titles?: string | string[];
|
|
26
|
+
/** Interior values to pull out into their own stored columns, keyed by path. */
|
|
27
|
+
extract?: string | string[] | Record<string, Kind>;
|
|
28
|
+
/** Store this field inside another list or dict field, at the given path. */
|
|
29
|
+
inject?: string;
|
|
30
|
+
/** Default value, or a function returning one. */
|
|
31
|
+
default?: any;
|
|
32
|
+
/** Whether null is allowed. Inferred when not set. */
|
|
33
|
+
none?: boolean;
|
|
34
|
+
/** The complete set of allowed values. */
|
|
35
|
+
options?: any[];
|
|
36
|
+
/** A regular expression or predicate the value must satisfy. */
|
|
37
|
+
validation?: Validation;
|
|
38
|
+
/** Length of the value, for sources that need it. */
|
|
39
|
+
length?: number;
|
|
40
|
+
/** How to format the value, one entry per title. */
|
|
41
|
+
format?: any;
|
|
42
|
+
/** Whether the field can't be written by the caller. */
|
|
43
|
+
readonly?: boolean;
|
|
44
|
+
/** Whether the source generates this value (an auto increment id, say). */
|
|
45
|
+
auto?: boolean;
|
|
46
|
+
/** Whether to reset to the default on update when untouched. */
|
|
47
|
+
refresh?: boolean;
|
|
48
|
+
/** Anything else a source wants to hang off the field. */
|
|
49
|
+
[option: string]: any;
|
|
50
|
+
}
|
|
51
|
+
/** Which comparison operators exist, and whether each takes multiple values. */
|
|
52
|
+
export declare const OPERATORS: Record<string, boolean>;
|
|
53
|
+
/**
|
|
54
|
+
* Names a field can't have, because the model already uses them. Use `store` when the
|
|
55
|
+
* source column really is called one of these.
|
|
56
|
+
*/
|
|
57
|
+
export declare const RESERVED: string[];
|
|
58
|
+
/**
|
|
59
|
+
* A single typed value on a model, with everything needed to validate it, filter on it,
|
|
60
|
+
* and move it in and out of a source.
|
|
61
|
+
*/
|
|
62
|
+
export declare class Field {
|
|
63
|
+
/** Extra attributes a source hung off this field. */
|
|
64
|
+
[option: string]: any;
|
|
65
|
+
/** Data kind to cast values as, or validate against. */
|
|
66
|
+
kind: FieldKind;
|
|
67
|
+
/** Name used in models. */
|
|
68
|
+
private _name;
|
|
69
|
+
/** Name used when reading and writing. `false` means never stored. */
|
|
70
|
+
store: string | false | null;
|
|
71
|
+
/** Whether this field is used for a many-to-many tie. */
|
|
72
|
+
tied: boolean | null;
|
|
73
|
+
/** Attributes to store, for class kinds. */
|
|
74
|
+
attr: Record<string, string> | ((values: Record<string, any>, value: any) => void) | null;
|
|
75
|
+
/** Attributes to construct with, for class kinds. */
|
|
76
|
+
init: Record<string, string> | ((value: any) => any) | null;
|
|
77
|
+
/** Attributes that make up the titles. */
|
|
78
|
+
titles: string[] | null;
|
|
79
|
+
/** Interior values to pull out into their own stored columns. */
|
|
80
|
+
extract: Record<string, Kind> | null;
|
|
81
|
+
/** Path in another field to store this value at. */
|
|
82
|
+
inject: string | null;
|
|
83
|
+
/** Default value, or a factory for one. */
|
|
84
|
+
default: any;
|
|
85
|
+
/** Whether null is allowed. */
|
|
86
|
+
none: boolean;
|
|
87
|
+
/** What `none` was before it got inferred. */
|
|
88
|
+
_none: boolean | null;
|
|
89
|
+
/** The complete set of allowed values. */
|
|
90
|
+
options: any[] | null;
|
|
91
|
+
/** A regular expression or predicate. */
|
|
92
|
+
validation: Validation | null;
|
|
93
|
+
/** Length of the value. */
|
|
94
|
+
length: number | null;
|
|
95
|
+
/** Formatting instructions, one per title. */
|
|
96
|
+
format: any[] | null;
|
|
97
|
+
/** Whether the caller may write this field. */
|
|
98
|
+
readonly: boolean | null;
|
|
99
|
+
/** Whether the source generates the value. */
|
|
100
|
+
auto: boolean | null;
|
|
101
|
+
/** Whether to reset to the default on an untouched update. */
|
|
102
|
+
refresh: boolean | null;
|
|
103
|
+
/** Current value. */
|
|
104
|
+
private _value;
|
|
105
|
+
/** Value as last read from or written to the source, in exported form. */
|
|
106
|
+
original: any;
|
|
107
|
+
/** Criteria to search by, keyed by criterion. */
|
|
108
|
+
criteria: Record<string, any> | null;
|
|
109
|
+
/** Whether the value has been set since the record was built. */
|
|
110
|
+
changed: boolean | null;
|
|
111
|
+
constructor(kind: FieldKind, options?: FieldOptions | boolean | null);
|
|
112
|
+
/** Name used in models. Setting it validates the name and fills in `store`. */
|
|
113
|
+
get name(): string | null;
|
|
114
|
+
set name(value: string | null);
|
|
115
|
+
/** Current value. Setting it validates and casts, and marks the field changed. */
|
|
116
|
+
get value(): any;
|
|
117
|
+
set value(value: any);
|
|
118
|
+
/** Set the value without marking the field changed. */
|
|
119
|
+
load(value: any): void;
|
|
120
|
+
/** Whether a value is already of this field's kind. */
|
|
121
|
+
private check;
|
|
122
|
+
/** An independent copy, used when a model builds a record from its fields. */
|
|
123
|
+
copy(): Field;
|
|
124
|
+
/** The definition of this field, for schemas and migrations. */
|
|
125
|
+
define(): Record<string, any>;
|
|
126
|
+
/** The valid form of a value, throwing when it can't be made valid. */
|
|
127
|
+
valid(value: any): any;
|
|
128
|
+
/** Add a criterion to this field's criteria. */
|
|
129
|
+
filter(value: any, criterion?: string): void;
|
|
130
|
+
/** The storable form of this field's value. */
|
|
131
|
+
export(): any;
|
|
132
|
+
/** Store a value at a path inside this field. */
|
|
133
|
+
apply(path: overscore.Path, value: any): void;
|
|
134
|
+
/** Read the value at a path inside this field. */
|
|
135
|
+
access(path: overscore.Path): any;
|
|
136
|
+
/** Whether the value differs from what was last read or written. */
|
|
137
|
+
delta(): boolean;
|
|
138
|
+
/** Write this field's value into a values object for storage. */
|
|
139
|
+
write(values: Record<string, any>): void;
|
|
140
|
+
/** Write this field's value for a create. */
|
|
141
|
+
create(values: Record<string, any>): void;
|
|
142
|
+
/** Whether a stored record satisfies this field's criteria. */
|
|
143
|
+
retrieve(values: Record<string, any>): boolean;
|
|
144
|
+
/** Whether a stored record matches a fuzzy `like`, or is one of a parent's matches. */
|
|
145
|
+
like(values: Record<string, any>, like: any, parents: Record<string, any[]>, path?: overscore.Path): boolean;
|
|
146
|
+
/** Load this field's value from a stored record. */
|
|
147
|
+
read(values: Record<string, any>): void;
|
|
148
|
+
/** The title values for this field, optionally at a path. */
|
|
149
|
+
title(path?: overscore.Path): any[];
|
|
150
|
+
/** Write this field's value for an update, if it changed. */
|
|
151
|
+
update(values: Record<string, any>): void;
|
|
152
|
+
/** Write this field's value for a mass update, if it was set. */
|
|
153
|
+
mass(values: Record<string, any>): void;
|
|
154
|
+
/** Write this field's value for a many-to-many tie update, if it was set. */
|
|
155
|
+
tie(values: Record<string, any>): void;
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=field.d.ts.map
|