@phis/contracts 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +111 -11
- package/dist/access.d.ts +50 -0
- package/dist/access.js +65 -0
- package/dist/addon-index.d.ts +1 -0
- package/dist/addon-index.js +1 -0
- package/dist/addon.d.ts +130 -57
- package/dist/addon.js +2 -2
- package/dist/assets.d.ts +165 -0
- package/dist/assets.js +1 -0
- package/dist/capabilities.d.ts +205 -30
- package/dist/capabilities.js +2 -2
- package/dist/catalog.d.ts +104 -0
- package/dist/catalog.js +116 -0
- package/dist/cms.d.ts +120 -0
- package/dist/cms.js +270 -0
- package/dist/core.d.ts +14 -6
- package/dist/core.js +16 -8
- package/dist/http.d.ts +33 -0
- package/dist/http.js +33 -0
- package/dist/locale.d.ts +14 -0
- package/dist/locale.js +14 -0
- package/dist/logging.d.ts +49 -0
- package/dist/logging.js +17 -0
- package/dist/media-storage.d.ts +129 -0
- package/dist/media-storage.js +56 -0
- package/dist/media.d.ts +228 -0
- package/dist/media.js +362 -0
- package/dist/queries.d.ts +280 -48
- package/dist/queries.js +10 -1
- package/dist/schema.d.ts +160 -26
- package/dist/schema.js +11 -2
- package/dist/server-capabilities.d.ts +37 -0
- package/dist/server-capabilities.js +17 -0
- package/dist/signals.d.ts +58 -0
- package/dist/signals.js +118 -0
- package/dist/site-groups.d.ts +38 -0
- package/dist/site-groups.js +54 -0
- package/package.json +43 -3
- package/dist/index.d.ts +0 -6
- package/dist/index.js +0 -6
package/dist/queries.d.ts
CHANGED
|
@@ -12,13 +12,36 @@
|
|
|
12
12
|
* and a join between two Add-ons' tables is already forbidden. A query that needs one is either cut
|
|
13
13
|
* wrong or wants a Core service.
|
|
14
14
|
*/
|
|
15
|
-
/**
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
/**
|
|
16
|
+
* What a declared parameter holds. Narrower than the column vocabulary: these travel as values.
|
|
17
|
+
*
|
|
18
|
+
* `json` is the one that is not a scalar, and it is deliberately the one that cannot be compared. It
|
|
19
|
+
* may be assigned to a `json` column and used nowhere else -- not in `compare`, not in `contains`, not
|
|
20
|
+
* in `in`, not in `whenPresent`. A document one could filter on would need paths, operators and an
|
|
21
|
+
* index vocabulary to go with them, and that is a second query language growing inside the one this
|
|
22
|
+
* file exists to keep small. What it is for is the other half: a column declared `json` had no way to
|
|
23
|
+
* be written at all, so an Add-on could store a document only by never storing one.
|
|
24
|
+
*/
|
|
25
|
+
export type PhisAddonQueryParameterType = "integer" | "bigInteger" | "text" | "boolean" | "instant" | "uuid" | "json";
|
|
26
|
+
export type PhisAddonQueryParameter = {
|
|
18
27
|
name: string;
|
|
19
|
-
type:
|
|
28
|
+
type: PhisAddonQueryParameterType;
|
|
20
29
|
/** Whether the caller may pass null. Absent means it may not. */
|
|
21
30
|
nullable?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Whether this parameter carries many values rather than one.
|
|
33
|
+
*
|
|
34
|
+
* Only usable by `in`, and the reason `in` is worth having at all. Its other form takes values fixed
|
|
35
|
+
* in the descriptor, which answers "one of these three states" and nothing a caller brings -- and the
|
|
36
|
+
* commonest need is exactly that: the rows belonging to the page that was just read, whose keys are
|
|
37
|
+
* known only at request time.
|
|
38
|
+
*
|
|
39
|
+
* It stays one binding. Core writes `= ANY($n::TYPE[])` rather than expanding the list into the
|
|
40
|
+
* statement, so the query has one shape however many values arrive; a statement whose text grew with
|
|
41
|
+
* its arguments would be assembled at request time, which is the thing this file exists to prevent.
|
|
42
|
+
* Core caps the length, because a list is an unbounded read wearing a parameter.
|
|
43
|
+
*/
|
|
44
|
+
list?: boolean;
|
|
22
45
|
};
|
|
23
46
|
/**
|
|
24
47
|
* Where a value in a query comes from.
|
|
@@ -28,7 +51,7 @@ export type PhiServerAddonQueryParameter = {
|
|
|
28
51
|
* bound actor, so the query cannot be aimed at somebody else -- the same reason the capability closes
|
|
29
52
|
* over the Site instead of taking it as an argument.
|
|
30
53
|
*/
|
|
31
|
-
export type
|
|
54
|
+
export type PhisAddonQueryValue = {
|
|
32
55
|
kind: "parameter";
|
|
33
56
|
name: string;
|
|
34
57
|
} | {
|
|
@@ -41,59 +64,160 @@ export type PhiServerAddonQueryValue = {
|
|
|
41
64
|
} | {
|
|
42
65
|
kind: "now";
|
|
43
66
|
};
|
|
44
|
-
export type
|
|
67
|
+
export type PhisAddonQueryComparison = "=" | "<>" | "<" | "<=" | ">" | ">=";
|
|
45
68
|
/**
|
|
46
69
|
* A condition, as a tree of a closed set of shapes.
|
|
47
70
|
*
|
|
48
|
-
* No expressions, no functions, no
|
|
71
|
+
* No expressions, no functions, no patterns an Add-on writes. `LIKE` is absent for the reason regular
|
|
49
72
|
* expressions are absent from the schema descriptor: its escaping and collation behaviour differ
|
|
50
|
-
* between database systems, and taking it would buy back the dependency this exists to remove.
|
|
51
|
-
*
|
|
73
|
+
* between database systems, and taking it would buy back the dependency this exists to remove. What
|
|
74
|
+
* replaces it is `contains`, an operator: the Add-on names a column and a value, and Core decides how
|
|
75
|
+
* that is spelled and escaped.
|
|
52
76
|
*/
|
|
53
|
-
export type
|
|
77
|
+
export type PhisAddonQueryCondition = {
|
|
54
78
|
kind: "compare";
|
|
55
79
|
column: string;
|
|
56
|
-
operator:
|
|
57
|
-
value:
|
|
80
|
+
operator: PhisAddonQueryComparison;
|
|
81
|
+
value: PhisAddonQueryValue;
|
|
58
82
|
} | {
|
|
59
83
|
kind: "isNull";
|
|
60
84
|
column: string;
|
|
61
85
|
negated?: boolean;
|
|
62
|
-
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Whether a text column contains this fragment, case-insensitively.
|
|
89
|
+
*
|
|
90
|
+
* The one search the vocabulary offers, and it is an operator rather than a pattern: the Add-on says
|
|
91
|
+
* what it wants and Core writes the statement, so there is no `LIKE` syntax in a manifest and no
|
|
92
|
+
* escaping for an author to get wrong. A `%` or a `_` in the value is a character to look for, not a
|
|
93
|
+
* wildcard.
|
|
94
|
+
*
|
|
95
|
+
* It wants a `text` index on the column. Without one it still works and reads the whole table to do
|
|
96
|
+
* it, which `phis addon check` reports at install rather than leaving to be discovered in production.
|
|
97
|
+
*/
|
|
98
|
+
| {
|
|
99
|
+
kind: "contains";
|
|
100
|
+
column: string;
|
|
101
|
+
value: PhisAddonQueryValue;
|
|
102
|
+
}
|
|
103
|
+
/** One of a set fixed in the descriptor: a state, a kind, a handful of names the Add-on knows. */
|
|
104
|
+
| {
|
|
105
|
+
kind: "in";
|
|
106
|
+
column: string;
|
|
107
|
+
values: PhisAddonQueryValue[];
|
|
108
|
+
parameter?: never;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* One of a set the caller brings, named by a `list` parameter.
|
|
112
|
+
*
|
|
113
|
+
* What makes a second query about the same rows possible: read a page, then ask something else about
|
|
114
|
+
* exactly those keys. Without it the second question can only be asked one row at a time or about the
|
|
115
|
+
* whole table, and neither is a page.
|
|
116
|
+
*/
|
|
117
|
+
| {
|
|
63
118
|
kind: "in";
|
|
64
119
|
column: string;
|
|
65
|
-
|
|
120
|
+
parameter: string;
|
|
121
|
+
values?: never;
|
|
66
122
|
} | {
|
|
67
123
|
kind: "all";
|
|
68
|
-
conditions:
|
|
124
|
+
conditions: PhisAddonQueryCondition[];
|
|
69
125
|
} | {
|
|
70
126
|
kind: "any";
|
|
71
|
-
conditions:
|
|
127
|
+
conditions: PhisAddonQueryCondition[];
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* A condition that applies only when its parameter was given.
|
|
131
|
+
*
|
|
132
|
+
* A listing has filters the caller may or may not set, and a declared query has one fixed `where`.
|
|
133
|
+
* Without this, every combination is its own query -- three optional filters are eight of them, four
|
|
134
|
+
* are sixteen, each declared, validated and kept in step by hand. The parameter must be nullable, and
|
|
135
|
+
* null means the condition is not there rather than that it matched nothing.
|
|
136
|
+
*/
|
|
137
|
+
| {
|
|
138
|
+
kind: "whenPresent";
|
|
139
|
+
parameter: string;
|
|
140
|
+
condition: PhisAddonQueryCondition;
|
|
72
141
|
};
|
|
73
|
-
export type
|
|
142
|
+
export type PhisAddonQueryOrdering = {
|
|
74
143
|
column: string;
|
|
75
144
|
direction: "asc" | "desc";
|
|
76
145
|
};
|
|
77
|
-
export type
|
|
146
|
+
export type PhisAddonQueryAssignment = {
|
|
78
147
|
column: string;
|
|
79
|
-
value:
|
|
148
|
+
value: PhisAddonQueryValue;
|
|
80
149
|
};
|
|
81
150
|
/**
|
|
82
151
|
* Reading rows of one of this Add-on's tables.
|
|
83
152
|
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
153
|
+
* Every select is paged, whether or not it was written as a listing. There is no unpaged form to reach
|
|
154
|
+
* for: an unbounded read is how an Add-on takes an instance down with a table that grew, and "the
|
|
155
|
+
* caller will pass a sensible one" is not a bound.
|
|
156
|
+
*
|
|
157
|
+
* `orderBy` is completed by Core with the primary key, so the order is total. Without that a cursor is
|
|
158
|
+
* quietly wrong: two rows sharing a sort value may come back in either order, and a row then appears on
|
|
159
|
+
* two pages while another appears on none. It is the kind of fault that stays invisible until the table
|
|
160
|
+
* is large, and no Add-on author has to think about it.
|
|
161
|
+
*
|
|
162
|
+
* Every column named in `orderBy` must be declared `NOT NULL`. Where nulls sort is a decision the
|
|
163
|
+
* descriptor cannot express, so an order over a nullable column is underdetermined -- and a keyset
|
|
164
|
+
* comparison against a null value matches nothing at all, which would end the paging early rather than
|
|
165
|
+
* loudly.
|
|
166
|
+
*/
|
|
167
|
+
/**
|
|
168
|
+
* A role the acting user must hold for this query to run at all.
|
|
169
|
+
*
|
|
170
|
+
* The one thing Core does with an Add-on's role vocabulary, and it is deliberately the smallest thing
|
|
171
|
+
* that is useful: it compares a name against what is stored. Core does not learn that `curator` may
|
|
172
|
+
* moderate -- that meaning stays here, as the pairing of a role with a query, which is the Add-on's own
|
|
173
|
+
* statement about its own vocabulary.
|
|
174
|
+
*
|
|
175
|
+
* It is what makes a table nobody owns writable. Without an owner and without a group, Core has no way
|
|
176
|
+
* to judge a row and answers no to every update and delete -- correct for a row that should belong to
|
|
177
|
+
* somebody, wrong for a catalogue, a rate table, or a moderation note, which belong to the Add-on. A
|
|
178
|
+
* declared role is the missing authority, and being declared is what makes it unforgettable: the check
|
|
179
|
+
* is in the descriptor rather than at the top of a handler, where it is one refactor from gone.
|
|
180
|
+
*
|
|
181
|
+
* On a table that is owned or grouped it narrows rather than replaces: both the role and the ladder
|
|
182
|
+
* have to be satisfied.
|
|
86
183
|
*/
|
|
87
|
-
|
|
184
|
+
type PhisAddonRoleGuarded = {
|
|
185
|
+
/** Names a role this Add-on's manifest declares. Absent means the query needs none. */
|
|
186
|
+
requiresRole?: string;
|
|
187
|
+
/**
|
|
188
|
+
* A role that stands in for the row's own authority, where the ladder alone would say no.
|
|
189
|
+
*
|
|
190
|
+
* The other direction, and the one moderation needs. `requiresRole` narrows: it asks for the role on
|
|
191
|
+
* top of the ladder, and on an owned table that means role *and* owner -- which nobody moderating a
|
|
192
|
+
* stranger's row can ever be. This one widens: the row is judged first, and a caller the ladder turned
|
|
193
|
+
* down is let through on the role instead. The owner keeps reaching their own row without any role at
|
|
194
|
+
* all.
|
|
195
|
+
*
|
|
196
|
+
* It is a bypass, and it is named so that writing it down feels like declaring one. An Add-on that
|
|
197
|
+
* hands a role the run of a table is making a real statement about that role, and it should be visible
|
|
198
|
+
* in the descriptor rather than inferred from the absence of something.
|
|
199
|
+
*
|
|
200
|
+
* Only on `update` and `delete`, which are the only places a row is judged, and only on a table that
|
|
201
|
+
* has authority to bypass. Not combined with `requiresRole`: a query needing both a narrowing and a
|
|
202
|
+
* widening role is two queries wearing one name.
|
|
203
|
+
*/
|
|
204
|
+
alsoAllowedByRole?: string;
|
|
205
|
+
};
|
|
206
|
+
export type PhisAddonSelectQueryDescriptor = PhisAddonRoleGuarded & {
|
|
88
207
|
kind: "select";
|
|
89
208
|
name: string;
|
|
90
209
|
table: string;
|
|
91
210
|
/** Absent means every declared column. Core's scope columns are never among them. */
|
|
92
211
|
columns?: string[];
|
|
93
|
-
where?:
|
|
94
|
-
orderBy?:
|
|
212
|
+
where?: PhisAddonQueryCondition;
|
|
213
|
+
orderBy?: PhisAddonQueryOrdering[];
|
|
214
|
+
/**
|
|
215
|
+
* The largest page this query will ever serve, whatever the caller asks for.
|
|
216
|
+
*
|
|
217
|
+
* The Add-on's own ceiling, not the page size: a call may ask for less, and Core takes the smallest of
|
|
218
|
+
* the request, this, and `PHIS_ADDON_QUERY_MAX_LIMIT`.
|
|
219
|
+
*/
|
|
95
220
|
limit: number;
|
|
96
|
-
offsetParameter?: string;
|
|
97
221
|
};
|
|
98
222
|
/**
|
|
99
223
|
* Adding a row.
|
|
@@ -103,11 +227,11 @@ export type PhiServerAddonSelectQueryDescriptor = {
|
|
|
103
227
|
* context; the group comes from a declared parameter because a row can belong to any group the actor is
|
|
104
228
|
* in, and Core refuses one they are not.
|
|
105
229
|
*/
|
|
106
|
-
export type
|
|
230
|
+
export type PhisAddonInsertQueryDescriptor = PhisAddonRoleGuarded & {
|
|
107
231
|
kind: "insert";
|
|
108
232
|
name: string;
|
|
109
233
|
table: string;
|
|
110
|
-
values:
|
|
234
|
+
values: PhisAddonQueryAssignment[];
|
|
111
235
|
/** Names the parameter carrying the group id, and is required for a group-scoped table. */
|
|
112
236
|
groupParameter?: string;
|
|
113
237
|
};
|
|
@@ -119,29 +243,112 @@ export type PhiServerAddonInsertQueryDescriptor = {
|
|
|
119
243
|
* unskippable rather than the discipline. An Add-on that needs to rewrite many rows at once is doing
|
|
120
244
|
* something Core should be doing for it.
|
|
121
245
|
*/
|
|
122
|
-
export type
|
|
246
|
+
export type PhisAddonUpdateQueryDescriptor = PhisAddonRoleGuarded & {
|
|
123
247
|
kind: "update";
|
|
124
248
|
name: string;
|
|
125
249
|
table: string;
|
|
126
|
-
set:
|
|
250
|
+
set: PhisAddonQueryAssignment[];
|
|
127
251
|
/** Names the parameter carrying the row's primary key value. */
|
|
128
252
|
idParameter: string;
|
|
129
253
|
};
|
|
130
|
-
export type
|
|
254
|
+
export type PhisAddonDeleteQueryDescriptor = PhisAddonRoleGuarded & {
|
|
131
255
|
kind: "delete";
|
|
132
256
|
name: string;
|
|
133
257
|
table: string;
|
|
134
258
|
idParameter: string;
|
|
135
259
|
};
|
|
136
|
-
|
|
260
|
+
/**
|
|
261
|
+
* `count` without a column counts rows; every other function names one.
|
|
262
|
+
*
|
|
263
|
+
* `sum` and `avg` want an integer column, and validation says so rather than letting PostgreSQL raise it
|
|
264
|
+
* at the first call: a manifest that averages a text column is wrong when it is written, not when it is
|
|
265
|
+
* run. `avg` comes back as a string, because it is `numeric` and a JavaScript number is not.
|
|
266
|
+
*/
|
|
267
|
+
export type PhisAddonAggregateFunction = "count" | "sum" | "avg" | "min" | "max";
|
|
268
|
+
export type PhisAddonQueryAggregate = {
|
|
269
|
+
function: PhisAddonAggregateFunction;
|
|
270
|
+
column?: string;
|
|
271
|
+
/** What the value is called in the answer. Must not collide with a grouping column. */
|
|
272
|
+
as: string;
|
|
273
|
+
};
|
|
274
|
+
/**
|
|
275
|
+
* Counting and summarising rows instead of returning them.
|
|
276
|
+
*
|
|
277
|
+
* The question a select cannot answer: "how many" and "what on average", per something. Without it an
|
|
278
|
+
* Add-on reads every row to count them, which is the unbounded read paging exists to prevent, or keeps a
|
|
279
|
+
* running total in a column of its own -- a number Core cannot hold true and that drifts the first time
|
|
280
|
+
* a write is lost.
|
|
281
|
+
*
|
|
282
|
+
* It reads no row a select could not have read. The ladder is not consulted for either: what a query may
|
|
283
|
+
* see is what the query says, `actor` and all, and an aggregate over rows the caller may not read one by
|
|
284
|
+
* one is an aggregate the Add-on wrote that way deliberately. What changes here is arithmetic, not
|
|
285
|
+
* reach.
|
|
286
|
+
*
|
|
287
|
+
* `groupBy` decides the shape of the answer. Without it there is exactly one row and no paging. With it
|
|
288
|
+
* there is one row per group, paged like a select -- and the grouping columns are the ordering, which is
|
|
289
|
+
* total by construction, since `GROUP BY` yields each combination once. That is also why they must be
|
|
290
|
+
* `NOT NULL`, and why there is no ordering by an aggregated value: ranking by an average would page on a
|
|
291
|
+
* key that is neither unique nor known before the group is computed.
|
|
292
|
+
*/
|
|
293
|
+
export type PhisAddonAggregateQueryDescriptor = PhisAddonRoleGuarded & {
|
|
294
|
+
kind: "aggregate";
|
|
295
|
+
name: string;
|
|
296
|
+
table: string;
|
|
297
|
+
aggregates: PhisAddonQueryAggregate[];
|
|
298
|
+
where?: PhisAddonQueryCondition;
|
|
299
|
+
groupBy?: string[];
|
|
300
|
+
/** The Add-on's ceiling on groups per page. Required with `groupBy`, meaningless without it. */
|
|
301
|
+
limit?: number;
|
|
302
|
+
};
|
|
303
|
+
export type PhisAddonQueryDescriptor = PhisAddonSelectQueryDescriptor | PhisAddonInsertQueryDescriptor | PhisAddonUpdateQueryDescriptor | PhisAddonDeleteQueryDescriptor | PhisAddonAggregateQueryDescriptor;
|
|
137
304
|
/** The most rows one declared `select` may return, whatever it asks for. */
|
|
138
|
-
export declare const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
305
|
+
export declare const PHIS_ADDON_QUERY_MAX_LIMIT: 500;
|
|
306
|
+
/**
|
|
307
|
+
* The most values one `list` parameter may carry.
|
|
308
|
+
*
|
|
309
|
+
* A page's worth, because that is what it is for: the keys just read, asked about again. Larger, and it
|
|
310
|
+
* is the unbounded read paging removed, arriving through the one door that still accepts a caller's
|
|
311
|
+
* count. Exceeding it is refused rather than truncated -- a silently shortened list answers about some
|
|
312
|
+
* of the rows and says it answered about all of them.
|
|
313
|
+
*/
|
|
314
|
+
export declare const PHIS_ADDON_QUERY_MAX_LIST: 500;
|
|
315
|
+
export type PhisAddonQueryCatalog = {
|
|
316
|
+
parameters: Readonly<Record<string, PhisAddonQueryParameter[]>>;
|
|
317
|
+
queries: PhisAddonQueryDescriptor[];
|
|
318
|
+
};
|
|
319
|
+
/**
|
|
320
|
+
* A document a `json` parameter carries, which is whatever survives a round trip through JSON.
|
|
321
|
+
*
|
|
322
|
+
* Not narrowed further, because the column is not narrowed either: a `json` column takes any document,
|
|
323
|
+
* and a type here that took less would describe a restriction the store does not have.
|
|
324
|
+
*/
|
|
325
|
+
export type PhisAddonQueryJson = {
|
|
326
|
+
readonly [key: string]: unknown;
|
|
327
|
+
} | readonly unknown[];
|
|
328
|
+
export type PhisAddonQueryArguments = Readonly<Record<string, string | number | boolean | null | readonly (string | number)[] | PhisAddonQueryJson>>;
|
|
329
|
+
export type PhisAddonQueryRow = Readonly<Record<string, unknown>>;
|
|
330
|
+
/**
|
|
331
|
+
* One page of a select, and whether there is another.
|
|
332
|
+
*
|
|
333
|
+
* `cursor` present means there is more; absent means that was everything. It is the one promise a
|
|
334
|
+
* consumer can neither detect nor repair on its own -- a truncated answer is indistinguishable from a
|
|
335
|
+
* complete one unless the answer says so -- and Core keeps it by reading one row more than it returns,
|
|
336
|
+
* which costs a row and no count.
|
|
337
|
+
*
|
|
338
|
+
* The cursor is opaque. It encodes the ordering it was made for and is refused by a query with a
|
|
339
|
+
* different one, because paging on somebody else's order silently skips and repeats rows.
|
|
340
|
+
*/
|
|
341
|
+
export type PhisAddonQueryPage = {
|
|
342
|
+
rows: PhisAddonQueryRow[];
|
|
343
|
+
cursor: string | null;
|
|
344
|
+
};
|
|
345
|
+
/** What a caller asks for a page, beside the query's own parameters. */
|
|
346
|
+
export type PhisAddonQueryPageRequest = {
|
|
347
|
+
/** A wish. Core takes the smallest of this, the descriptor's `limit`, and the hard maximum. */
|
|
348
|
+
limit?: number;
|
|
349
|
+
/** From a previous page. Absent starts at the beginning. */
|
|
350
|
+
cursor?: string | null;
|
|
142
351
|
};
|
|
143
|
-
export type PhiServerAddonQueryArguments = Readonly<Record<string, string | number | boolean | null>>;
|
|
144
|
-
export type PhiServerAddonQueryRow = Readonly<Record<string, unknown>>;
|
|
145
352
|
/**
|
|
146
353
|
* Running the declared queries: `@phis/server/data:v1`.
|
|
147
354
|
*
|
|
@@ -149,23 +356,48 @@ export type PhiServerAddonQueryRow = Readonly<Record<string, unknown>>;
|
|
|
149
356
|
* condition, because an Add-on that could pass one of those at request time would be holding a
|
|
150
357
|
* database handle with extra steps.
|
|
151
358
|
*
|
|
152
|
-
*
|
|
153
|
-
* there or was not the caller's to change, and the two are deliberately the same answer: telling
|
|
154
|
-
* apart would report the existence of a row the caller may not have.
|
|
359
|
+
* Every mutation answers with the row it wrote and `null` where it wrote none. `null` means the row was
|
|
360
|
+
* not there or was not the caller's to change, and the two are deliberately the same answer: telling
|
|
361
|
+
* them apart would report the existence of a row the caller may not have. The row itself withholds
|
|
362
|
+
* nothing further, because it comes back only when the write it describes actually happened.
|
|
363
|
+
*
|
|
364
|
+
* A select answers with a page. There is no method that returns everything, because the caller who
|
|
365
|
+
* wanted everything is the one who brings the instance down.
|
|
155
366
|
*/
|
|
156
|
-
export type
|
|
157
|
-
select(name: string, args?:
|
|
367
|
+
export type PhisDataCapabilityV1 = {
|
|
368
|
+
select(name: string, args?: PhisAddonQueryArguments, page?: PhisAddonQueryPageRequest): Promise<PhisAddonQueryPage>;
|
|
369
|
+
/**
|
|
370
|
+
* Counting and summarising, as a page for the same reason a select is one.
|
|
371
|
+
*
|
|
372
|
+
* A grouped aggregate has as many rows as there are groups, which is a number the Add-on does not know
|
|
373
|
+
* either. Ungrouped, the page holds one row and carries no cursor.
|
|
374
|
+
*/
|
|
375
|
+
aggregate(name: string, args?: PhisAddonQueryArguments, page?: PhisAddonQueryPageRequest): Promise<PhisAddonQueryPage>;
|
|
158
376
|
/** Returns the inserted row, with the scope columns Core filled in. */
|
|
159
|
-
insert(name: string, args?:
|
|
160
|
-
|
|
161
|
-
|
|
377
|
+
insert(name: string, args?: PhisAddonQueryArguments): Promise<PhisAddonQueryRow | null>;
|
|
378
|
+
/**
|
|
379
|
+
* Returns the row as it stands after the write, or `null` when nothing was written.
|
|
380
|
+
*
|
|
381
|
+
* The row rather than a count, because what was sent and what is now stored are not the same thing
|
|
382
|
+
* wherever a default, a constraint, or a column the query did not name had a say.
|
|
383
|
+
*/
|
|
384
|
+
update(name: string, args?: PhisAddonQueryArguments): Promise<PhisAddonQueryRow | null>;
|
|
385
|
+
/**
|
|
386
|
+
* Returns the row that was removed, or `null` when nothing was.
|
|
387
|
+
*
|
|
388
|
+
* The row is the only thing a delete can give that a count cannot, and it is needed: a row naming an
|
|
389
|
+
* object in the Add-on's store is the last record of that object, and once the statement has run there
|
|
390
|
+
* is nothing left to ask. The bytes would stay, counted against the quota, belonging to nobody.
|
|
391
|
+
*/
|
|
392
|
+
delete(name: string, args?: PhisAddonQueryArguments): Promise<PhisAddonQueryRow | null>;
|
|
162
393
|
/**
|
|
163
394
|
* One unit of work. Everything inside commits together or not at all.
|
|
164
395
|
*
|
|
165
|
-
* The handle offers the same
|
|
396
|
+
* The handle offers the same five operations and nothing else -- no commit, no rollback, no
|
|
166
397
|
* savepoint. Returning ends the transaction; throwing rolls it back. An Add-on cannot leave one
|
|
167
398
|
* open, because it never holds the thing that would stay open.
|
|
168
399
|
*/
|
|
169
|
-
transaction<T>(body: (tx:
|
|
400
|
+
transaction<T>(body: (tx: PhisDataTransactionV1) => Promise<T>): Promise<T>;
|
|
170
401
|
};
|
|
171
|
-
export type
|
|
402
|
+
export type PhisDataTransactionV1 = Omit<PhisDataCapabilityV1, "transaction">;
|
|
403
|
+
export {};
|
package/dist/queries.js
CHANGED
|
@@ -13,4 +13,13 @@
|
|
|
13
13
|
* wrong or wants a Core service.
|
|
14
14
|
*/
|
|
15
15
|
/** The most rows one declared `select` may return, whatever it asks for. */
|
|
16
|
-
export const
|
|
16
|
+
export const PHIS_ADDON_QUERY_MAX_LIMIT = 500;
|
|
17
|
+
/**
|
|
18
|
+
* The most values one `list` parameter may carry.
|
|
19
|
+
*
|
|
20
|
+
* A page's worth, because that is what it is for: the keys just read, asked about again. Larger, and it
|
|
21
|
+
* is the unbounded read paging removed, arriving through the one door that still accepts a caller's
|
|
22
|
+
* count. Exceeding it is refused rather than truncated -- a silently shortened list answers about some
|
|
23
|
+
* of the rows and says it answered about all of them.
|
|
24
|
+
*/
|
|
25
|
+
export const PHIS_ADDON_QUERY_MAX_LIST = 500;
|