cloesce 0.0.5-unstable.3 → 0.0.5-unstable.4
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 +80 -100
- package/dist/ast.js +12 -12
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +331 -368
- package/dist/extractor/err.d.ts +26 -26
- package/dist/extractor/err.js +100 -129
- package/dist/extractor/extract.d.ts +17 -60
- package/dist/extractor/extract.js +764 -826
- package/dist/generator.wasm +0 -0
- package/dist/router/crud.d.ts +1 -1
- package/dist/router/crud.js +43 -42
- package/dist/router/router.d.ts +98 -135
- package/dist/router/router.js +381 -424
- package/dist/router/validator.d.ts +6 -11
- package/dist/router/validator.d.ts.map +1 -1
- package/dist/router/validator.js +145 -158
- package/dist/router/wasm.d.ts +22 -56
- package/dist/router/wasm.js +79 -91
- package/dist/ui/backend.d.ts +181 -214
- package/dist/ui/backend.js +245 -258
- package/dist/ui/client.d.ts +1 -1
- package/dist/ui/common.d.ts +31 -54
- package/dist/ui/common.d.ts.map +1 -1
- package/dist/ui/common.js +159 -171
- package/package.json +1 -1
package/dist/ui/backend.js
CHANGED
|
@@ -4,7 +4,7 @@ import { WasmResource, mapSql, invokeOrmWasm } from "../router/wasm.js";
|
|
|
4
4
|
/**
|
|
5
5
|
* cloesce/backend
|
|
6
6
|
*/
|
|
7
|
-
export { CloesceApp } from "../router/router.js";
|
|
7
|
+
export { CloesceApp, } from "../router/router.js";
|
|
8
8
|
export { HttpResult, Either } from "./common.js";
|
|
9
9
|
/**
|
|
10
10
|
* Marks a class as a D1-backed SQL model.
|
|
@@ -26,8 +26,8 @@ export { HttpResult, Either } from "./common.js";
|
|
|
26
26
|
* }
|
|
27
27
|
* ```
|
|
28
28
|
*/
|
|
29
|
-
export const D1 = () => {};
|
|
30
|
-
export const Service = () => {};
|
|
29
|
+
export const D1 = () => { };
|
|
30
|
+
export const Service = () => { };
|
|
31
31
|
/**
|
|
32
32
|
* Marks a class as a plain serializable object.
|
|
33
33
|
*
|
|
@@ -54,7 +54,7 @@ export const Service = () => {};
|
|
|
54
54
|
* async function foo(): Promise<HttpResult<CatStuff>> { ... }
|
|
55
55
|
* ```
|
|
56
56
|
*/
|
|
57
|
-
export const PlainOldObject = () => {};
|
|
57
|
+
export const PlainOldObject = () => { };
|
|
58
58
|
/**
|
|
59
59
|
* Declares a Wrangler environment definition.
|
|
60
60
|
*
|
|
@@ -76,7 +76,7 @@ export const PlainOldObject = () => {};
|
|
|
76
76
|
* foo(@Inject env: WranglerEnv) {...}
|
|
77
77
|
* ```
|
|
78
78
|
*/
|
|
79
|
-
export const WranglerEnv = () => {};
|
|
79
|
+
export const WranglerEnv = () => { };
|
|
80
80
|
/**
|
|
81
81
|
* Marks a property as the SQL primary key for a model.
|
|
82
82
|
*
|
|
@@ -93,32 +93,32 @@ export const WranglerEnv = () => {};
|
|
|
93
93
|
* }
|
|
94
94
|
* ```
|
|
95
95
|
*/
|
|
96
|
-
export const PrimaryKey = () => {};
|
|
96
|
+
export const PrimaryKey = () => { };
|
|
97
97
|
/**
|
|
98
98
|
* Exposes a class method as an HTTP GET endpoint.
|
|
99
99
|
* The method will appear in both backend and generated client APIs.
|
|
100
100
|
*/
|
|
101
|
-
export const GET = () => {};
|
|
101
|
+
export const GET = () => { };
|
|
102
102
|
/**
|
|
103
103
|
* Exposes a class method as an HTTP POST endpoint.
|
|
104
104
|
* The method will appear in both backend and generated client APIs.
|
|
105
105
|
*/
|
|
106
|
-
export const POST = () => {};
|
|
106
|
+
export const POST = () => { };
|
|
107
107
|
/**
|
|
108
108
|
* Exposes a class method as an HTTP PUT endpoint.
|
|
109
109
|
* The method will appear in both backend and generated client APIs.
|
|
110
110
|
*/
|
|
111
|
-
export const PUT = () => {};
|
|
111
|
+
export const PUT = () => { };
|
|
112
112
|
/**
|
|
113
113
|
* Exposes a class method as an HTTP PATCH endpoint.
|
|
114
114
|
* The method will appear in both backend and generated client APIs.
|
|
115
115
|
*/
|
|
116
|
-
export const PATCH = () => {};
|
|
116
|
+
export const PATCH = () => { };
|
|
117
117
|
/**
|
|
118
118
|
* Exposes a class method as an HTTP DEL endpoint.
|
|
119
119
|
* The method will appear in both backend and generated client APIs.
|
|
120
120
|
*/
|
|
121
|
-
export const DELETE = () => {};
|
|
121
|
+
export const DELETE = () => { };
|
|
122
122
|
/**
|
|
123
123
|
* Declares a static property as a data source.
|
|
124
124
|
*
|
|
@@ -159,7 +159,7 @@ export const DELETE = () => {};
|
|
|
159
159
|
* // => Person { id: 1, dogId: 2, dog: { id: 2, name: "Fido" } }[]
|
|
160
160
|
* ```
|
|
161
161
|
*/
|
|
162
|
-
export const DataSource = () => {};
|
|
162
|
+
export const DataSource = () => { };
|
|
163
163
|
/**
|
|
164
164
|
* Declares a one-to-many relationship between models.
|
|
165
165
|
*
|
|
@@ -172,7 +172,7 @@ export const DataSource = () => {};
|
|
|
172
172
|
* dogs: Dog[];
|
|
173
173
|
* ```
|
|
174
174
|
*/
|
|
175
|
-
export const OneToMany = (_foreignKeyColumn) => () => {};
|
|
175
|
+
export const OneToMany = (_foreignKeyColumn) => () => { };
|
|
176
176
|
/**
|
|
177
177
|
* Declares a one-to-one relationship between models.
|
|
178
178
|
*
|
|
@@ -185,7 +185,7 @@ export const OneToMany = (_foreignKeyColumn) => () => {};
|
|
|
185
185
|
* dog: Dog | undefined;
|
|
186
186
|
* ```
|
|
187
187
|
*/
|
|
188
|
-
export const OneToOne = (_foreignKeyColumn) => () => {};
|
|
188
|
+
export const OneToOne = (_foreignKeyColumn) => () => { };
|
|
189
189
|
/**
|
|
190
190
|
* Declares a many-to-many relationship between models.
|
|
191
191
|
*
|
|
@@ -198,7 +198,7 @@ export const OneToOne = (_foreignKeyColumn) => () => {};
|
|
|
198
198
|
* courses: Course[];
|
|
199
199
|
* ```
|
|
200
200
|
*/
|
|
201
|
-
export const ManyToMany = (_uniqueId) => () => {};
|
|
201
|
+
export const ManyToMany = (_uniqueId) => () => { };
|
|
202
202
|
/**
|
|
203
203
|
* Declares a foreign key relationship between models.
|
|
204
204
|
* Directly translates to a SQLite foreign key.
|
|
@@ -213,7 +213,7 @@ export const ManyToMany = (_uniqueId) => () => {};
|
|
|
213
213
|
* dogId: number;
|
|
214
214
|
* ```
|
|
215
215
|
*/
|
|
216
|
-
export const ForeignKey = (_Model) => () => {};
|
|
216
|
+
export const ForeignKey = (_Model) => () => { };
|
|
217
217
|
/**
|
|
218
218
|
* Marks a method parameter for dependency injection.
|
|
219
219
|
*
|
|
@@ -231,7 +231,7 @@ export const ForeignKey = (_Model) => () => {};
|
|
|
231
231
|
* }
|
|
232
232
|
* ```
|
|
233
233
|
*/
|
|
234
|
-
export const Inject = () => {};
|
|
234
|
+
export const Inject = () => { };
|
|
235
235
|
/**
|
|
236
236
|
* Enables automatic CRUD method generation for a model.
|
|
237
237
|
*
|
|
@@ -260,256 +260,243 @@ export const Inject = () => {};
|
|
|
260
260
|
* }
|
|
261
261
|
* ```
|
|
262
262
|
*/
|
|
263
|
-
export const CRUD = (_kinds) => () => {};
|
|
263
|
+
export const CRUD = (_kinds) => () => { };
|
|
264
264
|
/**
|
|
265
265
|
* Exposes the ORM primitives Cloesce uses to interact with D1 databases.
|
|
266
266
|
*/
|
|
267
267
|
export class Orm {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
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;
|
|
268
|
+
db;
|
|
269
|
+
constructor(db) {
|
|
270
|
+
this.db = db;
|
|
351
271
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
break;
|
|
359
|
-
}
|
|
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);
|
|
360
278
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
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();
|
|
370
292
|
}
|
|
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
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
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(JSON.stringify(newModel, (k, v) => v instanceof Uint8Array ? u8ToB64(v) : v), wasm),
|
|
341
|
+
WasmResource.fromString(JSON.stringify(includeTree), wasm),
|
|
342
|
+
];
|
|
343
|
+
const upsertQueryRes = invokeOrmWasm(wasm.upsert_model, args, wasm);
|
|
344
|
+
if (upsertQueryRes.isLeft()) {
|
|
345
|
+
return upsertQueryRes;
|
|
346
|
+
}
|
|
347
|
+
const statements = JSON.parse(upsertQueryRes.unwrap());
|
|
348
|
+
// One of these statements is a "SELECT", which is the root model id stmt.
|
|
349
|
+
let selectIndex;
|
|
350
|
+
for (let i = statements.length - 1; i >= 0; i--) {
|
|
351
|
+
if (/^SELECT/i.test(statements[i].query)) {
|
|
352
|
+
selectIndex = i;
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
// Execute all statements in a batch.
|
|
357
|
+
const batchRes = await this.db.batch(statements.map((s) => this.db.prepare(s.query).bind(...s.values)));
|
|
358
|
+
if (!batchRes.every((r) => r.success)) {
|
|
359
|
+
const failed = batchRes.find((r) => !r.success);
|
|
360
|
+
return Either.left(failed?.error ?? "D1 batch failed, but no error was returned.");
|
|
361
|
+
}
|
|
362
|
+
const rootModelId = batchRes[selectIndex].results[0];
|
|
363
|
+
return Either.right(rootModelId.id);
|
|
414
364
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
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
|
-
);
|
|
365
|
+
/**
|
|
366
|
+
* Returns a select query, creating a CTE view for the model using the provided include tree.
|
|
367
|
+
*
|
|
368
|
+
* @param ctor The model constructor.
|
|
369
|
+
* @param includeTree An include tree describing which related models to join.
|
|
370
|
+
* @param from An optional custom `FROM` clause to use instead of the base table.
|
|
371
|
+
* @param tagCte An optional CTE name to tag the query with. Defaults to "Model.view".
|
|
372
|
+
*
|
|
373
|
+
* ### Example:
|
|
374
|
+
* ```ts
|
|
375
|
+
* // Using a data source
|
|
376
|
+
* const query = Orm.listQuery(Person, "default");
|
|
377
|
+
*
|
|
378
|
+
* // Using a custom from statement
|
|
379
|
+
* const query = Orm.listQuery(Person, null, "SELECT * FROM Person WHERE age > 18");
|
|
380
|
+
* ```
|
|
381
|
+
*
|
|
382
|
+
* ### Example SQL output:
|
|
383
|
+
* ```sql
|
|
384
|
+
* WITH Person_view AS (
|
|
385
|
+
* SELECT
|
|
386
|
+
* "Person"."id" AS "id",
|
|
387
|
+
* ...
|
|
388
|
+
* FROM "Person"
|
|
389
|
+
* LEFT JOIN ...
|
|
390
|
+
* )
|
|
391
|
+
* SELECT * FROM Person_view
|
|
392
|
+
* ```
|
|
393
|
+
*/
|
|
394
|
+
static listQuery(ctor, opts) {
|
|
395
|
+
const { wasm } = RuntimeContainer.get();
|
|
396
|
+
const args = [
|
|
397
|
+
WasmResource.fromString(ctor.name, wasm),
|
|
398
|
+
WasmResource.fromString(JSON.stringify(opts.includeTree ?? null), wasm),
|
|
399
|
+
WasmResource.fromString(JSON.stringify(opts.tagCte ?? null), wasm),
|
|
400
|
+
WasmResource.fromString(JSON.stringify(opts.from ?? null), wasm),
|
|
401
|
+
];
|
|
402
|
+
const res = invokeOrmWasm(wasm.list_models, args, wasm);
|
|
403
|
+
if (res.isLeft()) {
|
|
404
|
+
throw new Error(`Error invoking the Cloesce WASM Binary: ${res.value}`);
|
|
405
|
+
}
|
|
406
|
+
return res.unwrap();
|
|
484
407
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
408
|
+
/**
|
|
409
|
+
* Returns a select query for a single model by primary key, creating a CTE view using the provided include tree.
|
|
410
|
+
*
|
|
411
|
+
* @param ctor The model constructor.
|
|
412
|
+
* @param includeTree An include tree describing which related models to join.
|
|
413
|
+
*
|
|
414
|
+
* ### Example:
|
|
415
|
+
* ```ts
|
|
416
|
+
* // Using a data source
|
|
417
|
+
* const query = Orm.getQuery(Person, "default");
|
|
418
|
+
* ```
|
|
419
|
+
*
|
|
420
|
+
* ### Example SQL output:
|
|
421
|
+
*
|
|
422
|
+
* ```sql
|
|
423
|
+
* WITH Person_view AS (
|
|
424
|
+
* SELECT
|
|
425
|
+
* "Person"."id" AS "id",
|
|
426
|
+
* ...
|
|
427
|
+
* FROM "Person"
|
|
428
|
+
* LEFT JOIN ...
|
|
429
|
+
* )
|
|
430
|
+
* SELECT * FROM Person_view WHERE [Person].[id] = ?
|
|
431
|
+
* ```
|
|
432
|
+
*/
|
|
433
|
+
static getQuery(ctor, includeTree) {
|
|
434
|
+
const { ast } = RuntimeContainer.get();
|
|
435
|
+
return `${this.listQuery(ctor, { includeTree })} WHERE [${ast.models[ctor.name].primary_key.name}] = ?`;
|
|
508
436
|
}
|
|
509
|
-
|
|
510
|
-
|
|
437
|
+
/**
|
|
438
|
+
* Retrieves all instances of a model from the database.
|
|
439
|
+
* @param ctor The model constructor.
|
|
440
|
+
* @param includeTree An include tree describing which related models to join.
|
|
441
|
+
* @param from An optional custom `FROM` clause to use instead of the base table.
|
|
442
|
+
* @returns Either an error string, or an array of model instances.
|
|
443
|
+
*
|
|
444
|
+
* ### Example:
|
|
445
|
+
* ```ts
|
|
446
|
+
* const orm = Orm.fromD1(env.db);
|
|
447
|
+
* const horses = await orm.list(Horse, Horse.default);
|
|
448
|
+
* ```
|
|
449
|
+
*
|
|
450
|
+
* ### Example with custom from:
|
|
451
|
+
* ```ts
|
|
452
|
+
* const orm = Orm.fromD1(env.db);
|
|
453
|
+
* const adultHorses = await orm.list(Horse, Horse.default, "SELECT * FROM Horse ORDER BY age DESC LIMIT 10");
|
|
454
|
+
* ```
|
|
455
|
+
*
|
|
456
|
+
* =>
|
|
457
|
+
*
|
|
458
|
+
* ```sql
|
|
459
|
+
* SELECT
|
|
460
|
+
* "Horse"."id" AS "id",
|
|
461
|
+
* ...
|
|
462
|
+
* FROM (SELECT * FROM Horse ORDER BY age DESC LIMIT 10)
|
|
463
|
+
* LEFT JOIN ...
|
|
464
|
+
* ```
|
|
465
|
+
*
|
|
466
|
+
*/
|
|
467
|
+
async list(ctor, opts) {
|
|
468
|
+
const sql = Orm.listQuery(ctor, opts);
|
|
469
|
+
const stmt = this.db.prepare(sql);
|
|
470
|
+
const records = await stmt.all();
|
|
471
|
+
if (!records.success) {
|
|
472
|
+
return Either.left(records.error ?? "D1 query failed, but no error was returned.");
|
|
473
|
+
}
|
|
474
|
+
const mapped = Orm.mapSql(ctor, records.results, opts.includeTree ?? null);
|
|
475
|
+
return Either.right(mapped);
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Retrieves a single model by primary key.
|
|
479
|
+
* @param ctor The model constructor.
|
|
480
|
+
* @param id The primary key value.
|
|
481
|
+
* @param includeTree An include tree describing which related models to join.
|
|
482
|
+
* @returns Either an error string, or the model instance (null if not found).
|
|
483
|
+
*
|
|
484
|
+
* ### Example:
|
|
485
|
+
* ```ts
|
|
486
|
+
* const orm = Orm.fromD1(env.db);
|
|
487
|
+
* const horse = await orm.get(Horse, 1, Horse.default);
|
|
488
|
+
* ```
|
|
489
|
+
*/
|
|
490
|
+
async get(ctor, id, includeTree) {
|
|
491
|
+
const sql = Orm.getQuery(ctor, includeTree);
|
|
492
|
+
const record = await this.db.prepare(sql).bind(id).run();
|
|
493
|
+
if (!record.success) {
|
|
494
|
+
return Either.left(record.error ?? "D1 query failed, but no error was returned.");
|
|
495
|
+
}
|
|
496
|
+
if (record.results.length === 0) {
|
|
497
|
+
return Either.right(null);
|
|
498
|
+
}
|
|
499
|
+
const mapped = Orm.mapSql(ctor, record.results, includeTree);
|
|
500
|
+
return Either.right(mapped[0]);
|
|
511
501
|
}
|
|
512
|
-
const mapped = Orm.mapSql(ctor, record.results, includeTree);
|
|
513
|
-
return Either.right(mapped[0]);
|
|
514
|
-
}
|
|
515
502
|
}
|
package/dist/ui/client.d.ts
CHANGED