cloesce 0.0.4-unstable.9 → 0.0.5-unstable.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/dist/ast.d.ts +141 -0
- package/dist/ast.d.ts.map +1 -0
- package/dist/ast.js +30 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +375 -279
- package/dist/extractor/err.d.ts +32 -0
- package/dist/extractor/err.d.ts.map +1 -0
- package/dist/extractor/err.js +138 -0
- package/dist/extractor/extract.d.ts +62 -15
- package/dist/extractor/extract.d.ts.map +1 -1
- package/dist/extractor/extract.js +835 -647
- package/dist/generator.wasm +0 -0
- package/dist/orm.wasm +0 -0
- package/dist/router/crud.d.ts +5 -20
- package/dist/router/crud.d.ts.map +1 -1
- package/dist/router/crud.js +53 -64
- package/dist/router/router.d.ts +153 -95
- package/dist/router/router.d.ts.map +1 -1
- package/dist/router/router.js +451 -407
- package/dist/router/validator.d.ts +32 -0
- package/dist/router/validator.d.ts.map +1 -0
- package/dist/router/validator.js +193 -0
- package/dist/router/wasm.d.ts +59 -24
- package/dist/router/wasm.d.ts.map +1 -1
- package/dist/router/wasm.js +93 -79
- package/dist/ui/backend.d.ts +224 -180
- package/dist/ui/backend.d.ts.map +1 -1
- package/dist/ui/backend.js +264 -250
- package/dist/ui/client.d.ts +7 -5
- package/dist/ui/client.d.ts.map +1 -1
- package/dist/ui/client.js +2 -7
- package/dist/ui/common.d.ts +120 -0
- package/dist/ui/common.d.ts.map +1 -0
- package/dist/ui/common.js +210 -0
- package/package.json +4 -3
- package/README.md +0 -632
- package/dist/common.d.ts +0 -237
- package/dist/common.d.ts.map +0 -1
- package/dist/common.js +0 -169
package/dist/ui/backend.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import { Either } from "
|
|
1
|
+
import { Either, u8ToB64 } from "./common.js";
|
|
2
2
|
import { RuntimeContainer } from "../router/router.js";
|
|
3
|
-
import { WasmResource, mapSql
|
|
4
|
-
|
|
3
|
+
import { WasmResource, mapSql, invokeOrmWasm } from "../router/wasm.js";
|
|
4
|
+
/**
|
|
5
|
+
* cloesce/backend
|
|
6
|
+
*/
|
|
7
|
+
export { CloesceApp } from "../router/router.js";
|
|
8
|
+
export { HttpResult, Either } from "./common.js";
|
|
5
9
|
/**
|
|
6
10
|
* Marks a class as a D1-backed SQL model.
|
|
7
11
|
*
|
|
@@ -22,7 +26,8 @@ export { CloesceApp, } from "../router/router.js";
|
|
|
22
26
|
* }
|
|
23
27
|
* ```
|
|
24
28
|
*/
|
|
25
|
-
export const D1 = () => {
|
|
29
|
+
export const D1 = () => {};
|
|
30
|
+
export const Service = () => {};
|
|
26
31
|
/**
|
|
27
32
|
* Marks a class as a plain serializable object.
|
|
28
33
|
*
|
|
@@ -49,7 +54,7 @@ export const D1 = () => { };
|
|
|
49
54
|
* async function foo(): Promise<HttpResult<CatStuff>> { ... }
|
|
50
55
|
* ```
|
|
51
56
|
*/
|
|
52
|
-
export const PlainOldObject = () => {
|
|
57
|
+
export const PlainOldObject = () => {};
|
|
53
58
|
/**
|
|
54
59
|
* Declares a Wrangler environment definition.
|
|
55
60
|
*
|
|
@@ -71,7 +76,7 @@ export const PlainOldObject = () => { };
|
|
|
71
76
|
* foo(@Inject env: WranglerEnv) {...}
|
|
72
77
|
* ```
|
|
73
78
|
*/
|
|
74
|
-
export const WranglerEnv = () => {
|
|
79
|
+
export const WranglerEnv = () => {};
|
|
75
80
|
/**
|
|
76
81
|
* Marks a property as the SQL primary key for a model.
|
|
77
82
|
*
|
|
@@ -88,32 +93,32 @@ export const WranglerEnv = () => { };
|
|
|
88
93
|
* }
|
|
89
94
|
* ```
|
|
90
95
|
*/
|
|
91
|
-
export const PrimaryKey = () => {
|
|
96
|
+
export const PrimaryKey = () => {};
|
|
92
97
|
/**
|
|
93
98
|
* Exposes a class method as an HTTP GET endpoint.
|
|
94
99
|
* The method will appear in both backend and generated client APIs.
|
|
95
100
|
*/
|
|
96
|
-
export const GET = () => {
|
|
101
|
+
export const GET = () => {};
|
|
97
102
|
/**
|
|
98
103
|
* Exposes a class method as an HTTP POST endpoint.
|
|
99
104
|
* The method will appear in both backend and generated client APIs.
|
|
100
105
|
*/
|
|
101
|
-
export const POST = () => {
|
|
106
|
+
export const POST = () => {};
|
|
102
107
|
/**
|
|
103
108
|
* Exposes a class method as an HTTP PUT endpoint.
|
|
104
109
|
* The method will appear in both backend and generated client APIs.
|
|
105
110
|
*/
|
|
106
|
-
export const PUT = () => {
|
|
111
|
+
export const PUT = () => {};
|
|
107
112
|
/**
|
|
108
113
|
* Exposes a class method as an HTTP PATCH endpoint.
|
|
109
114
|
* The method will appear in both backend and generated client APIs.
|
|
110
115
|
*/
|
|
111
|
-
export const PATCH = () => {
|
|
116
|
+
export const PATCH = () => {};
|
|
112
117
|
/**
|
|
113
118
|
* Exposes a class method as an HTTP DEL endpoint.
|
|
114
119
|
* The method will appear in both backend and generated client APIs.
|
|
115
120
|
*/
|
|
116
|
-
export const DELETE = () => {
|
|
121
|
+
export const DELETE = () => {};
|
|
117
122
|
/**
|
|
118
123
|
* Declares a static property as a data source.
|
|
119
124
|
*
|
|
@@ -154,7 +159,7 @@ export const DELETE = () => { };
|
|
|
154
159
|
* // => Person { id: 1, dogId: 2, dog: { id: 2, name: "Fido" } }[]
|
|
155
160
|
* ```
|
|
156
161
|
*/
|
|
157
|
-
export const DataSource = () => {
|
|
162
|
+
export const DataSource = () => {};
|
|
158
163
|
/**
|
|
159
164
|
* Declares a one-to-many relationship between models.
|
|
160
165
|
*
|
|
@@ -167,7 +172,7 @@ export const DataSource = () => { };
|
|
|
167
172
|
* dogs: Dog[];
|
|
168
173
|
* ```
|
|
169
174
|
*/
|
|
170
|
-
export const OneToMany = (_foreignKeyColumn) => () => {
|
|
175
|
+
export const OneToMany = (_foreignKeyColumn) => () => {};
|
|
171
176
|
/**
|
|
172
177
|
* Declares a one-to-one relationship between models.
|
|
173
178
|
*
|
|
@@ -180,7 +185,7 @@ export const OneToMany = (_foreignKeyColumn) => () => { };
|
|
|
180
185
|
* dog: Dog | undefined;
|
|
181
186
|
* ```
|
|
182
187
|
*/
|
|
183
|
-
export const OneToOne = (_foreignKeyColumn) => () => {
|
|
188
|
+
export const OneToOne = (_foreignKeyColumn) => () => {};
|
|
184
189
|
/**
|
|
185
190
|
* Declares a many-to-many relationship between models.
|
|
186
191
|
*
|
|
@@ -193,7 +198,7 @@ export const OneToOne = (_foreignKeyColumn) => () => { };
|
|
|
193
198
|
* courses: Course[];
|
|
194
199
|
* ```
|
|
195
200
|
*/
|
|
196
|
-
export const ManyToMany = (_uniqueId) => () => {
|
|
201
|
+
export const ManyToMany = (_uniqueId) => () => {};
|
|
197
202
|
/**
|
|
198
203
|
* Declares a foreign key relationship between models.
|
|
199
204
|
* Directly translates to a SQLite foreign key.
|
|
@@ -208,7 +213,7 @@ export const ManyToMany = (_uniqueId) => () => { };
|
|
|
208
213
|
* dogId: number;
|
|
209
214
|
* ```
|
|
210
215
|
*/
|
|
211
|
-
export const ForeignKey = (_Model) => () => {
|
|
216
|
+
export const ForeignKey = (_Model) => () => {};
|
|
212
217
|
/**
|
|
213
218
|
* Marks a method parameter for dependency injection.
|
|
214
219
|
*
|
|
@@ -226,7 +231,7 @@ export const ForeignKey = (_Model) => () => { };
|
|
|
226
231
|
* }
|
|
227
232
|
* ```
|
|
228
233
|
*/
|
|
229
|
-
export const Inject = () => {
|
|
234
|
+
export const Inject = () => {};
|
|
230
235
|
/**
|
|
231
236
|
* Enables automatic CRUD method generation for a model.
|
|
232
237
|
*
|
|
@@ -255,247 +260,256 @@ export const Inject = () => { };
|
|
|
255
260
|
* }
|
|
256
261
|
* ```
|
|
257
262
|
*/
|
|
258
|
-
export const CRUD = (_kinds) => () => {
|
|
263
|
+
export const CRUD = (_kinds) => () => {};
|
|
259
264
|
/**
|
|
260
265
|
* Exposes the ORM primitives Cloesce uses to interact with D1 databases.
|
|
261
266
|
*/
|
|
262
267
|
export class Orm {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
268
|
+
db;
|
|
269
|
+
constructor(db) {
|
|
270
|
+
this.db = db;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Creates an instance of an `Orm`
|
|
274
|
+
* @param db The database to use for ORM calls.
|
|
275
|
+
*/
|
|
276
|
+
static fromD1(db) {
|
|
277
|
+
return new Orm(db);
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Maps SQL records to an instantiated Model. The records must be flat
|
|
281
|
+
* (e.g., of the form "id, name, address") or derive from a Cloesce data source view
|
|
282
|
+
* (e.g., of the form "Horse.id, Horse.name, Horse.address")
|
|
283
|
+
*
|
|
284
|
+
* Assumes the data is formatted correctly, throwing an error otherwise.
|
|
285
|
+
*
|
|
286
|
+
* @param ctor The model constructor
|
|
287
|
+
* @param records D1 Result records
|
|
288
|
+
* @param includeTree Include tree to define the relationships to join.
|
|
289
|
+
*/
|
|
290
|
+
static mapSql(ctor, records, includeTree = null) {
|
|
291
|
+
return mapSql(ctor, records, includeTree).unwrap();
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Executes an "upsert" query, adding or augmenting a model in the database.
|
|
295
|
+
*
|
|
296
|
+
* If a model's primary key is not defined in `newModel`, the query is assumed to be an insert.
|
|
297
|
+
*
|
|
298
|
+
* If a model's primary key _is_ defined, but some attributes are missing, the query is assumed to be an update.
|
|
299
|
+
*
|
|
300
|
+
* Finally, if the primary key is defined, but all attributes are included, a SQLite upsert will be performed.
|
|
301
|
+
*
|
|
302
|
+
* In any other case, an error string will be returned.
|
|
303
|
+
*
|
|
304
|
+
* ### Inserting a new Model
|
|
305
|
+
* ```ts
|
|
306
|
+
* const model = {name: "julio", lastname: "pumpkin"};
|
|
307
|
+
* const idRes = await orm.upsert(Person, model, null);
|
|
308
|
+
* ```
|
|
309
|
+
*
|
|
310
|
+
* ### Updating an existing model
|
|
311
|
+
* ```ts
|
|
312
|
+
* const model = {id: 1, name: "timothy"};
|
|
313
|
+
* const idRes = await orm.upsert(Person, model, null);
|
|
314
|
+
* // (in db)=> {id: 1, name: "timothy", lastname: "pumpkin"}
|
|
315
|
+
* ```
|
|
316
|
+
*
|
|
317
|
+
* ### Upserting a model
|
|
318
|
+
* ```ts
|
|
319
|
+
* // (assume a Person already exists)
|
|
320
|
+
* const model = {
|
|
321
|
+
* id: 1,
|
|
322
|
+
* lastname: "burger", // updates last name
|
|
323
|
+
* dog: {
|
|
324
|
+
* name: "fido" // insert dog relationship
|
|
325
|
+
* }
|
|
326
|
+
* };
|
|
327
|
+
* const idRes = await orm.upsert(Person, model, null);
|
|
328
|
+
* // (in db)=> Person: {id: 1, dogId: 1 ...} ; Dog: {id: 1, name: "fido"}
|
|
329
|
+
* ```
|
|
330
|
+
*
|
|
331
|
+
* @param ctor A model constructor.
|
|
332
|
+
* @param newModel The new or augmented model.
|
|
333
|
+
* @param includeTree An include tree describing which foreign keys to join.
|
|
334
|
+
* @returns An error string, or the primary key of the inserted model.
|
|
335
|
+
*/
|
|
336
|
+
async upsert(ctor, newModel, includeTree = null) {
|
|
337
|
+
const { wasm } = RuntimeContainer.get();
|
|
338
|
+
const args = [
|
|
339
|
+
WasmResource.fromString(ctor.name, wasm),
|
|
340
|
+
WasmResource.fromString(
|
|
341
|
+
JSON.stringify(newModel, (k, v) =>
|
|
342
|
+
v instanceof Uint8Array ? u8ToB64(v) : v,
|
|
343
|
+
),
|
|
344
|
+
wasm,
|
|
345
|
+
),
|
|
346
|
+
WasmResource.fromString(JSON.stringify(includeTree), wasm),
|
|
347
|
+
];
|
|
348
|
+
const upsertQueryRes = invokeOrmWasm(wasm.upsert_model, args, wasm);
|
|
349
|
+
if (upsertQueryRes.isLeft()) {
|
|
350
|
+
return upsertQueryRes;
|
|
273
351
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
static mapSql(ctor, records, includeTree = null) {
|
|
283
|
-
return mapSql(ctor, records, includeTree);
|
|
352
|
+
const statements = JSON.parse(upsertQueryRes.unwrap());
|
|
353
|
+
// One of these statements is a "SELECT", which is the root model id stmt.
|
|
354
|
+
let selectIndex;
|
|
355
|
+
for (let i = statements.length - 1; i >= 0; i--) {
|
|
356
|
+
if (/^SELECT/i.test(statements[i].query)) {
|
|
357
|
+
selectIndex = i;
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
284
360
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
* In any other case, an error string will be returned.
|
|
295
|
-
*
|
|
296
|
-
* ### Inserting a new Model
|
|
297
|
-
* ```ts
|
|
298
|
-
* const model = {name: "julio", lastname: "pumpkin"};
|
|
299
|
-
* const idRes = await orm.upsert(Person, model, null);
|
|
300
|
-
* ```
|
|
301
|
-
*
|
|
302
|
-
* ### Updating an existing model
|
|
303
|
-
* ```ts
|
|
304
|
-
* const model = {id: 1, name: "timothy"};
|
|
305
|
-
* const idRes = await orm.upsert(Person, model, null);
|
|
306
|
-
* // (in db)=> {id: 1, name: "timothy", lastname: "pumpkin"}
|
|
307
|
-
* ```
|
|
308
|
-
*
|
|
309
|
-
* ### Upserting a model
|
|
310
|
-
* ```ts
|
|
311
|
-
* // (assume a Person already exists)
|
|
312
|
-
* const model = {
|
|
313
|
-
* id: 1,
|
|
314
|
-
* lastname: "burger", // updates last name
|
|
315
|
-
* dog: {
|
|
316
|
-
* name: "fido" // insert dog relationship
|
|
317
|
-
* }
|
|
318
|
-
* };
|
|
319
|
-
* const idRes = await orm.upsert(Person, model, null);
|
|
320
|
-
* // (in db)=> Person: {id: 1, dogId: 1 ...} ; Dog: {id: 1, name: "fido"}
|
|
321
|
-
* ```
|
|
322
|
-
*
|
|
323
|
-
* @param ctor A model constructor.
|
|
324
|
-
* @param newModel The new or augmented model.
|
|
325
|
-
* @param includeTree An include tree describing which foreign keys to join.
|
|
326
|
-
* @returns An error string, or the primary key of the inserted model.
|
|
327
|
-
*/
|
|
328
|
-
async upsert(ctor, newModel, includeTree = null) {
|
|
329
|
-
const { wasm } = RuntimeContainer.get();
|
|
330
|
-
const args = [
|
|
331
|
-
WasmResource.fromString(ctor.name, wasm),
|
|
332
|
-
WasmResource.fromString(JSON.stringify(newModel), wasm),
|
|
333
|
-
WasmResource.fromString(JSON.stringify(includeTree), wasm),
|
|
334
|
-
];
|
|
335
|
-
const upsertQueryRes = invokeOrmWasm(wasm.upsert_model, args, wasm);
|
|
336
|
-
if (upsertQueryRes.isLeft()) {
|
|
337
|
-
return upsertQueryRes;
|
|
338
|
-
}
|
|
339
|
-
const statements = JSON.parse(upsertQueryRes.unwrap());
|
|
340
|
-
// One of these statements is a "SELECT", which is the root model id stmt.
|
|
341
|
-
let selectIndex;
|
|
342
|
-
for (let i = statements.length - 1; i >= 0; i--) {
|
|
343
|
-
if (/^SELECT/i.test(statements[i].query)) {
|
|
344
|
-
selectIndex = i;
|
|
345
|
-
break;
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
// Execute all statements in a batch.
|
|
349
|
-
const batchRes = await this.db.batch(statements.map((s) => this.db.prepare(s.query).bind(...s.values)));
|
|
350
|
-
if (!batchRes.every((r) => r.success)) {
|
|
351
|
-
const failed = batchRes.find((r) => !r.success);
|
|
352
|
-
return Either.left(failed?.error ?? "D1 batch failed, but no error was returned.");
|
|
353
|
-
}
|
|
354
|
-
// Return the result of the SELECT statement
|
|
355
|
-
const selectResult = batchRes[selectIndex].results[0];
|
|
356
|
-
return Either.right(selectResult.id);
|
|
361
|
+
// Execute all statements in a batch.
|
|
362
|
+
const batchRes = await this.db.batch(
|
|
363
|
+
statements.map((s) => this.db.prepare(s.query).bind(...s.values)),
|
|
364
|
+
);
|
|
365
|
+
if (!batchRes.every((r) => r.success)) {
|
|
366
|
+
const failed = batchRes.find((r) => !r.success);
|
|
367
|
+
return Either.left(
|
|
368
|
+
failed?.error ?? "D1 batch failed, but no error was returned.",
|
|
369
|
+
);
|
|
357
370
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
371
|
+
const rootModelId = batchRes[selectIndex].results[0];
|
|
372
|
+
return Either.right(rootModelId.id);
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Returns a select query, creating a CTE view for the model using the provided include tree.
|
|
376
|
+
*
|
|
377
|
+
* @param ctor The model constructor.
|
|
378
|
+
* @param includeTree An include tree describing which related models to join.
|
|
379
|
+
* @param from An optional custom `FROM` clause to use instead of the base table.
|
|
380
|
+
* @param tagCte An optional CTE name to tag the query with. Defaults to "Model.view".
|
|
381
|
+
*
|
|
382
|
+
* ### Example:
|
|
383
|
+
* ```ts
|
|
384
|
+
* // Using a data source
|
|
385
|
+
* const query = Orm.listQuery(Person, "default");
|
|
386
|
+
*
|
|
387
|
+
* // Using a custom from statement
|
|
388
|
+
* const query = Orm.listQuery(Person, null, "SELECT * FROM Person WHERE age > 18");
|
|
389
|
+
* ```
|
|
390
|
+
*
|
|
391
|
+
* ### Example SQL output:
|
|
392
|
+
* ```sql
|
|
393
|
+
* WITH Person_view AS (
|
|
394
|
+
* SELECT
|
|
395
|
+
* "Person"."id" AS "id",
|
|
396
|
+
* ...
|
|
397
|
+
* FROM "Person"
|
|
398
|
+
* LEFT JOIN ...
|
|
399
|
+
* )
|
|
400
|
+
* SELECT * FROM Person_view
|
|
401
|
+
* ```
|
|
402
|
+
*/
|
|
403
|
+
static listQuery(ctor, opts) {
|
|
404
|
+
const { wasm } = RuntimeContainer.get();
|
|
405
|
+
const args = [
|
|
406
|
+
WasmResource.fromString(ctor.name, wasm),
|
|
407
|
+
WasmResource.fromString(JSON.stringify(opts.includeTree ?? null), wasm),
|
|
408
|
+
WasmResource.fromString(JSON.stringify(opts.tagCte ?? null), wasm),
|
|
409
|
+
WasmResource.fromString(JSON.stringify(opts.from ?? null), wasm),
|
|
410
|
+
];
|
|
411
|
+
const res = invokeOrmWasm(wasm.list_models, args, wasm);
|
|
412
|
+
if (res.isLeft()) {
|
|
413
|
+
throw new Error(`Error invoking the Cloesce WASM Binary: ${res.value}`);
|
|
400
414
|
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
415
|
+
return res.unwrap();
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Returns a select query for a single model by primary key, creating a CTE view using the provided include tree.
|
|
419
|
+
*
|
|
420
|
+
* @param ctor The model constructor.
|
|
421
|
+
* @param includeTree An include tree describing which related models to join.
|
|
422
|
+
*
|
|
423
|
+
* ### Example:
|
|
424
|
+
* ```ts
|
|
425
|
+
* // Using a data source
|
|
426
|
+
* const query = Orm.getQuery(Person, "default");
|
|
427
|
+
* ```
|
|
428
|
+
*
|
|
429
|
+
* ### Example SQL output:
|
|
430
|
+
*
|
|
431
|
+
* ```sql
|
|
432
|
+
* WITH Person_view AS (
|
|
433
|
+
* SELECT
|
|
434
|
+
* "Person"."id" AS "id",
|
|
435
|
+
* ...
|
|
436
|
+
* FROM "Person"
|
|
437
|
+
* LEFT JOIN ...
|
|
438
|
+
* )
|
|
439
|
+
* SELECT * FROM Person_view WHERE [Person].[id] = ?
|
|
440
|
+
* ```
|
|
441
|
+
*/
|
|
442
|
+
static getQuery(ctor, includeTree) {
|
|
443
|
+
const { ast } = RuntimeContainer.get();
|
|
444
|
+
return `${this.listQuery(ctor, { includeTree })} WHERE [${ast.models[ctor.name].primary_key.name}] = ?`;
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Retrieves all instances of a model from the database.
|
|
448
|
+
* @param ctor The model constructor.
|
|
449
|
+
* @param includeTree An include tree describing which related models to join.
|
|
450
|
+
* @param from An optional custom `FROM` clause to use instead of the base table.
|
|
451
|
+
* @returns Either an error string, or an array of model instances.
|
|
452
|
+
*
|
|
453
|
+
* ### Example:
|
|
454
|
+
* ```ts
|
|
455
|
+
* const orm = Orm.fromD1(env.db);
|
|
456
|
+
* const horses = await orm.list(Horse, Horse.default);
|
|
457
|
+
* ```
|
|
458
|
+
*
|
|
459
|
+
* ### Example with custom from:
|
|
460
|
+
* ```ts
|
|
461
|
+
* const orm = Orm.fromD1(env.db);
|
|
462
|
+
* const adultHorses = await orm.list(Horse, Horse.default, "SELECT * FROM Horse ORDER BY age DESC LIMIT 10");
|
|
463
|
+
* ```
|
|
464
|
+
*
|
|
465
|
+
* =>
|
|
466
|
+
*
|
|
467
|
+
* ```sql
|
|
468
|
+
* SELECT
|
|
469
|
+
* "Horse"."id" AS "id",
|
|
470
|
+
* ...
|
|
471
|
+
* FROM (SELECT * FROM Horse ORDER BY age DESC LIMIT 10)
|
|
472
|
+
* LEFT JOIN ...
|
|
473
|
+
* ```
|
|
474
|
+
*
|
|
475
|
+
*/
|
|
476
|
+
async list(ctor, opts) {
|
|
477
|
+
const sql = Orm.listQuery(ctor, opts);
|
|
478
|
+
const stmt = this.db.prepare(sql);
|
|
479
|
+
const records = await stmt.all();
|
|
480
|
+
if (!records.success) {
|
|
481
|
+
return Either.left(
|
|
482
|
+
records.error ?? "D1 query failed, but no error was returned.",
|
|
483
|
+
);
|
|
429
484
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
* "Horse"."id" AS "id",
|
|
454
|
-
* ...
|
|
455
|
-
* FROM (SELECT * FROM Horse ORDER BY age DESC LIMIT 10)
|
|
456
|
-
* LEFT JOIN ...
|
|
457
|
-
* ```
|
|
458
|
-
*
|
|
459
|
-
*/
|
|
460
|
-
async list(ctor, opts) {
|
|
461
|
-
const sql = Orm.listQuery(ctor, opts);
|
|
462
|
-
const stmt = this.db.prepare(sql);
|
|
463
|
-
const records = await stmt.all();
|
|
464
|
-
if (!records.success) {
|
|
465
|
-
return Either.left(records.error ?? "D1 query failed, but no error was returned.");
|
|
466
|
-
}
|
|
467
|
-
const mapRes = Orm.mapSql(ctor, records.results, opts.includeTree ?? null);
|
|
468
|
-
if (mapRes.isLeft()) {
|
|
469
|
-
return Either.left(mapRes.value);
|
|
470
|
-
}
|
|
471
|
-
return Either.right(mapRes.value);
|
|
485
|
+
const mapped = Orm.mapSql(ctor, records.results, opts.includeTree ?? null);
|
|
486
|
+
return Either.right(mapped);
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Retrieves a single model by primary key.
|
|
490
|
+
* @param ctor The model constructor.
|
|
491
|
+
* @param id The primary key value.
|
|
492
|
+
* @param includeTree An include tree describing which related models to join.
|
|
493
|
+
* @returns Either an error string, or the model instance (null if not found).
|
|
494
|
+
*
|
|
495
|
+
* ### Example:
|
|
496
|
+
* ```ts
|
|
497
|
+
* const orm = Orm.fromD1(env.db);
|
|
498
|
+
* const horse = await orm.get(Horse, 1, Horse.default);
|
|
499
|
+
* ```
|
|
500
|
+
*/
|
|
501
|
+
async get(ctor, id, includeTree) {
|
|
502
|
+
const sql = Orm.getQuery(ctor, includeTree);
|
|
503
|
+
const record = await this.db.prepare(sql).bind(id).run();
|
|
504
|
+
if (!record.success) {
|
|
505
|
+
return Either.left(
|
|
506
|
+
record.error ?? "D1 query failed, but no error was returned.",
|
|
507
|
+
);
|
|
472
508
|
}
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
* @param ctor The model constructor.
|
|
476
|
-
* @param id The primary key value.
|
|
477
|
-
* @param includeTree An include tree describing which related models to join.
|
|
478
|
-
* @returns Either an error string, or the model instance (null if not found).
|
|
479
|
-
*
|
|
480
|
-
* ### Example:
|
|
481
|
-
* ```ts
|
|
482
|
-
* const orm = Orm.fromD1(env.db);
|
|
483
|
-
* const horse = await orm.get(Horse, 1, Horse.default);
|
|
484
|
-
* ```
|
|
485
|
-
*/
|
|
486
|
-
async get(ctor, id, includeTree) {
|
|
487
|
-
const sql = Orm.getQuery(ctor, includeTree);
|
|
488
|
-
const record = await this.db.prepare(sql).bind(id).run();
|
|
489
|
-
if (!record.success) {
|
|
490
|
-
return Either.left(record.error ?? "D1 query failed, but no error was returned.");
|
|
491
|
-
}
|
|
492
|
-
if (record.results.length === 0) {
|
|
493
|
-
return Either.right(null);
|
|
494
|
-
}
|
|
495
|
-
const mapRes = Orm.mapSql(ctor, record.results, includeTree);
|
|
496
|
-
if (mapRes.isLeft()) {
|
|
497
|
-
return Either.left(mapRes.value);
|
|
498
|
-
}
|
|
499
|
-
return Either.right(mapRes.value[0]);
|
|
509
|
+
if (record.results.length === 0) {
|
|
510
|
+
return Either.right(null);
|
|
500
511
|
}
|
|
512
|
+
const mapped = Orm.mapSql(ctor, record.results, includeTree);
|
|
513
|
+
return Either.right(mapped[0]);
|
|
514
|
+
}
|
|
501
515
|
}
|
package/dist/ui/client.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
}
|
|
5
|
-
|
|
1
|
+
/**
|
|
2
|
+
* cloesce/client
|
|
3
|
+
*/
|
|
4
|
+
export type { DeepPartial, Stream } from "./common.js";
|
|
5
|
+
export { HttpResult, Either, requestBody, b64ToU8 } from "./common.js";
|
|
6
|
+
export { MediaType } from "../ast.js";
|
|
7
|
+
//# sourceMappingURL=client.d.ts.map
|
package/dist/ui/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/ui/client.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/ui/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/ui/client.js
CHANGED
|
@@ -1,7 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
if (Array.isArray(data)) {
|
|
4
|
-
return data.map((x) => instantiateObjectArray(x, ctor)).flat();
|
|
5
|
-
}
|
|
6
|
-
return [Object.assign(new ctor(), data)];
|
|
7
|
-
}
|
|
1
|
+
export { HttpResult, Either, requestBody, b64ToU8 } from "./common.js";
|
|
2
|
+
export { MediaType } from "../ast.js";
|