cloesce 0.0.4-unstable.8 → 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 -280
- 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 +824 -623
- 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 +159 -45
- package/dist/router/router.d.ts.map +1 -1
- package/dist/router/router.js +434 -297
- 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 -181
- package/dist/ui/backend.d.ts.map +1 -1
- package/dist/ui/backend.js +264 -255
- 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 -619
- package/dist/common.d.ts +0 -330
- package/dist/common.d.ts.map +0 -1
- package/dist/common.js +0 -274
package/dist/ui/backend.js
CHANGED
|
@@ -1,8 +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
|
-
|
|
5
|
-
|
|
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";
|
|
6
9
|
/**
|
|
7
10
|
* Marks a class as a D1-backed SQL model.
|
|
8
11
|
*
|
|
@@ -23,7 +26,8 @@ export { CloesceApp } from "../common.js";
|
|
|
23
26
|
* }
|
|
24
27
|
* ```
|
|
25
28
|
*/
|
|
26
|
-
export const D1 = () => {
|
|
29
|
+
export const D1 = () => {};
|
|
30
|
+
export const Service = () => {};
|
|
27
31
|
/**
|
|
28
32
|
* Marks a class as a plain serializable object.
|
|
29
33
|
*
|
|
@@ -50,7 +54,7 @@ export const D1 = () => { };
|
|
|
50
54
|
* async function foo(): Promise<HttpResult<CatStuff>> { ... }
|
|
51
55
|
* ```
|
|
52
56
|
*/
|
|
53
|
-
export const PlainOldObject = () => {
|
|
57
|
+
export const PlainOldObject = () => {};
|
|
54
58
|
/**
|
|
55
59
|
* Declares a Wrangler environment definition.
|
|
56
60
|
*
|
|
@@ -72,7 +76,7 @@ export const PlainOldObject = () => { };
|
|
|
72
76
|
* foo(@Inject env: WranglerEnv) {...}
|
|
73
77
|
* ```
|
|
74
78
|
*/
|
|
75
|
-
export const WranglerEnv = () => {
|
|
79
|
+
export const WranglerEnv = () => {};
|
|
76
80
|
/**
|
|
77
81
|
* Marks a property as the SQL primary key for a model.
|
|
78
82
|
*
|
|
@@ -89,32 +93,32 @@ export const WranglerEnv = () => { };
|
|
|
89
93
|
* }
|
|
90
94
|
* ```
|
|
91
95
|
*/
|
|
92
|
-
export const PrimaryKey = () => {
|
|
96
|
+
export const PrimaryKey = () => {};
|
|
93
97
|
/**
|
|
94
98
|
* Exposes a class method as an HTTP GET endpoint.
|
|
95
99
|
* The method will appear in both backend and generated client APIs.
|
|
96
100
|
*/
|
|
97
|
-
export const GET = () => {
|
|
101
|
+
export const GET = () => {};
|
|
98
102
|
/**
|
|
99
103
|
* Exposes a class method as an HTTP POST endpoint.
|
|
100
104
|
* The method will appear in both backend and generated client APIs.
|
|
101
105
|
*/
|
|
102
|
-
export const POST = () => {
|
|
106
|
+
export const POST = () => {};
|
|
103
107
|
/**
|
|
104
108
|
* Exposes a class method as an HTTP PUT endpoint.
|
|
105
109
|
* The method will appear in both backend and generated client APIs.
|
|
106
110
|
*/
|
|
107
|
-
export const PUT = () => {
|
|
111
|
+
export const PUT = () => {};
|
|
108
112
|
/**
|
|
109
113
|
* Exposes a class method as an HTTP PATCH endpoint.
|
|
110
114
|
* The method will appear in both backend and generated client APIs.
|
|
111
115
|
*/
|
|
112
|
-
export const PATCH = () => {
|
|
116
|
+
export const PATCH = () => {};
|
|
113
117
|
/**
|
|
114
118
|
* Exposes a class method as an HTTP DEL endpoint.
|
|
115
119
|
* The method will appear in both backend and generated client APIs.
|
|
116
120
|
*/
|
|
117
|
-
export const DELETE = () => {
|
|
121
|
+
export const DELETE = () => {};
|
|
118
122
|
/**
|
|
119
123
|
* Declares a static property as a data source.
|
|
120
124
|
*
|
|
@@ -155,7 +159,7 @@ export const DELETE = () => { };
|
|
|
155
159
|
* // => Person { id: 1, dogId: 2, dog: { id: 2, name: "Fido" } }[]
|
|
156
160
|
* ```
|
|
157
161
|
*/
|
|
158
|
-
export const DataSource = () => {
|
|
162
|
+
export const DataSource = () => {};
|
|
159
163
|
/**
|
|
160
164
|
* Declares a one-to-many relationship between models.
|
|
161
165
|
*
|
|
@@ -168,7 +172,7 @@ export const DataSource = () => { };
|
|
|
168
172
|
* dogs: Dog[];
|
|
169
173
|
* ```
|
|
170
174
|
*/
|
|
171
|
-
export const OneToMany = (_foreignKeyColumn) => () => {
|
|
175
|
+
export const OneToMany = (_foreignKeyColumn) => () => {};
|
|
172
176
|
/**
|
|
173
177
|
* Declares a one-to-one relationship between models.
|
|
174
178
|
*
|
|
@@ -181,7 +185,7 @@ export const OneToMany = (_foreignKeyColumn) => () => { };
|
|
|
181
185
|
* dog: Dog | undefined;
|
|
182
186
|
* ```
|
|
183
187
|
*/
|
|
184
|
-
export const OneToOne = (_foreignKeyColumn) => () => {
|
|
188
|
+
export const OneToOne = (_foreignKeyColumn) => () => {};
|
|
185
189
|
/**
|
|
186
190
|
* Declares a many-to-many relationship between models.
|
|
187
191
|
*
|
|
@@ -194,7 +198,7 @@ export const OneToOne = (_foreignKeyColumn) => () => { };
|
|
|
194
198
|
* courses: Course[];
|
|
195
199
|
* ```
|
|
196
200
|
*/
|
|
197
|
-
export const ManyToMany = (_uniqueId) => () => {
|
|
201
|
+
export const ManyToMany = (_uniqueId) => () => {};
|
|
198
202
|
/**
|
|
199
203
|
* Declares a foreign key relationship between models.
|
|
200
204
|
* Directly translates to a SQLite foreign key.
|
|
@@ -209,7 +213,7 @@ export const ManyToMany = (_uniqueId) => () => { };
|
|
|
209
213
|
* dogId: number;
|
|
210
214
|
* ```
|
|
211
215
|
*/
|
|
212
|
-
export const ForeignKey = (_Model) => () => {
|
|
216
|
+
export const ForeignKey = (_Model) => () => {};
|
|
213
217
|
/**
|
|
214
218
|
* Marks a method parameter for dependency injection.
|
|
215
219
|
*
|
|
@@ -227,7 +231,7 @@ export const ForeignKey = (_Model) => () => { };
|
|
|
227
231
|
* }
|
|
228
232
|
* ```
|
|
229
233
|
*/
|
|
230
|
-
export const Inject = () => {
|
|
234
|
+
export const Inject = () => {};
|
|
231
235
|
/**
|
|
232
236
|
* Enables automatic CRUD method generation for a model.
|
|
233
237
|
*
|
|
@@ -256,251 +260,256 @@ export const Inject = () => { };
|
|
|
256
260
|
* }
|
|
257
261
|
* ```
|
|
258
262
|
*/
|
|
259
|
-
export const CRUD = (_kinds) => () => {
|
|
263
|
+
export const CRUD = (_kinds) => () => {};
|
|
260
264
|
/**
|
|
261
265
|
* Exposes the ORM primitives Cloesce uses to interact with D1 databases.
|
|
262
266
|
*/
|
|
263
267
|
export class Orm {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
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;
|
|
274
351
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
static mapSql(ctor, records, includeTree = null) {
|
|
284
|
-
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
|
+
}
|
|
285
360
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
* In any other case, an error string will be returned.
|
|
296
|
-
*
|
|
297
|
-
* ### Inserting a new Model
|
|
298
|
-
* ```ts
|
|
299
|
-
* const model = {name: "julio", lastname: "pumpkin"};
|
|
300
|
-
* const idRes = await orm.upsert(Person, model, null);
|
|
301
|
-
* ```
|
|
302
|
-
*
|
|
303
|
-
* ### Updating an existing model
|
|
304
|
-
* ```ts
|
|
305
|
-
* const model = {id: 1, name: "timothy"};
|
|
306
|
-
* const idRes = await orm.upsert(Person, model, null);
|
|
307
|
-
* // (in db)=> {id: 1, name: "timothy", lastname: "pumpkin"}
|
|
308
|
-
* ```
|
|
309
|
-
*
|
|
310
|
-
* ### Upserting a model
|
|
311
|
-
* ```ts
|
|
312
|
-
* // (assume a Person already exists)
|
|
313
|
-
* const model = {
|
|
314
|
-
* id: 1,
|
|
315
|
-
* lastname: "burger", // updates last name
|
|
316
|
-
* dog: {
|
|
317
|
-
* name: "fido" // insert dog relationship
|
|
318
|
-
* }
|
|
319
|
-
* };
|
|
320
|
-
* const idRes = await orm.upsert(Person, model, null);
|
|
321
|
-
* // (in db)=> Person: {id: 1, dogId: 1 ...} ; Dog: {id: 1, name: "fido"}
|
|
322
|
-
* ```
|
|
323
|
-
*
|
|
324
|
-
* @param ctor A model constructor.
|
|
325
|
-
* @param newModel The new or augmented model.
|
|
326
|
-
* @param includeTree An include tree describing which foreign keys to join.
|
|
327
|
-
* @returns An error string, or the primary key of the inserted model.
|
|
328
|
-
*/
|
|
329
|
-
async upsert(ctor, newModel, includeTree = null) {
|
|
330
|
-
const { wasm } = RuntimeContainer.get();
|
|
331
|
-
const args = [
|
|
332
|
-
WasmResource.fromString(ctor.name, wasm),
|
|
333
|
-
WasmResource.fromString(JSON.stringify(newModel), wasm),
|
|
334
|
-
WasmResource.fromString(JSON.stringify(includeTree), wasm),
|
|
335
|
-
];
|
|
336
|
-
const upsertQueryRes = invokeOrmWasm(wasm.upsert_model, args, wasm);
|
|
337
|
-
if (upsertQueryRes.isLeft()) {
|
|
338
|
-
return upsertQueryRes;
|
|
339
|
-
}
|
|
340
|
-
const statements = JSON.parse(upsertQueryRes.unwrap());
|
|
341
|
-
// One of these statements is a "SELECT", which is the root model id stmt.
|
|
342
|
-
let selectIndex;
|
|
343
|
-
for (let i = statements.length - 1; i >= 0; i--) {
|
|
344
|
-
if (/^SELECT/i.test(statements[i].query)) {
|
|
345
|
-
selectIndex = i;
|
|
346
|
-
break;
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
// Execute all statements in a batch.
|
|
350
|
-
const batchRes = await this.db.batch(statements.map((s) => this.db.prepare(s.query).bind(...s.values)));
|
|
351
|
-
if (!batchRes.every((r) => r.success)) {
|
|
352
|
-
const failed = batchRes.find((r) => !r.success);
|
|
353
|
-
return Either.left(failed?.error ?? "D1 batch failed, but no error was returned.");
|
|
354
|
-
}
|
|
355
|
-
// Return the result of the SELECT statement
|
|
356
|
-
const selectResult = batchRes[selectIndex].results[0];
|
|
357
|
-
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
|
+
);
|
|
358
370
|
}
|
|
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
|
-
|
|
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}`);
|
|
397
414
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
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
|
-
|
|
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
|
+
);
|
|
428
484
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
* "Horse"."id" AS "id",
|
|
453
|
-
* ...
|
|
454
|
-
* FROM (SELECT * FROM Horse ORDER BY age DESC LIMIT 10)
|
|
455
|
-
* LEFT JOIN ...
|
|
456
|
-
* ```
|
|
457
|
-
*
|
|
458
|
-
*/
|
|
459
|
-
async list(ctor, opts) {
|
|
460
|
-
const queryRes = Orm.listQuery(ctor, opts);
|
|
461
|
-
if (queryRes.isLeft()) {
|
|
462
|
-
return Either.left(queryRes.value);
|
|
463
|
-
}
|
|
464
|
-
const stmt = this.db.prepare(queryRes.value);
|
|
465
|
-
const records = await stmt.all();
|
|
466
|
-
if (!records.success) {
|
|
467
|
-
return Either.left(records.error ?? "D1 query failed, but no error was returned.");
|
|
468
|
-
}
|
|
469
|
-
const mapRes = Orm.mapSql(ctor, records.results, opts.includeTree ?? null);
|
|
470
|
-
if (mapRes.isLeft()) {
|
|
471
|
-
return Either.left(mapRes.value);
|
|
472
|
-
}
|
|
473
|
-
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
|
+
);
|
|
474
508
|
}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
* @param ctor The model constructor.
|
|
478
|
-
* @param id The primary key value.
|
|
479
|
-
* @param includeTree An include tree describing which related models to join.
|
|
480
|
-
* @returns Either an error string, or the model instance (null if not found).
|
|
481
|
-
*
|
|
482
|
-
* ### Example:
|
|
483
|
-
* ```ts
|
|
484
|
-
* const orm = Orm.fromD1(env.db);
|
|
485
|
-
* const horse = await orm.get(Horse, 1, Horse.default);
|
|
486
|
-
* ```
|
|
487
|
-
*/
|
|
488
|
-
async get(ctor, id, includeTree) {
|
|
489
|
-
const queryRes = Orm.getQuery(ctor, includeTree);
|
|
490
|
-
if (queryRes.isLeft()) {
|
|
491
|
-
return Either.left(queryRes.value);
|
|
492
|
-
}
|
|
493
|
-
const record = await this.db.prepare(queryRes.value).bind(id).run();
|
|
494
|
-
if (!record.success) {
|
|
495
|
-
return Either.left(record.error ?? "D1 query failed, but no error was returned.");
|
|
496
|
-
}
|
|
497
|
-
if (record.results.length === 0) {
|
|
498
|
-
return Either.right(null);
|
|
499
|
-
}
|
|
500
|
-
const mapRes = Orm.mapSql(ctor, record.results, includeTree);
|
|
501
|
-
if (mapRes.isLeft()) {
|
|
502
|
-
return Either.left(mapRes.value);
|
|
503
|
-
}
|
|
504
|
-
return Either.right(mapRes.value[0]);
|
|
509
|
+
if (record.results.length === 0) {
|
|
510
|
+
return Either.right(null);
|
|
505
511
|
}
|
|
512
|
+
const mapped = Orm.mapSql(ctor, record.results, includeTree);
|
|
513
|
+
return Either.right(mapped[0]);
|
|
514
|
+
}
|
|
506
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";
|