@centia-io/sdk 0.0.29 → 0.0.31
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 +262 -1
- package/dist/centia-io-sdk.cjs +810 -9
- package/dist/centia-io-sdk.d.cts +111 -1
- package/dist/centia-io-sdk.d.cts.map +1 -1
- package/dist/centia-io-sdk.d.ts +111 -1
- package/dist/centia-io-sdk.d.ts.map +1 -1
- package/dist/centia-io-sdk.js +809 -9
- package/dist/centia-io-sdk.js.map +1 -1
- package/dist/centia-io-sdk.umd.js +809 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ Requirements:
|
|
|
30
30
|
|
|
31
31
|
ESM import:
|
|
32
32
|
```ts
|
|
33
|
-
import { CodeFlow, PasswordFlow, Sql, Rpc, createApi, SignUp } from "@centia-io/sdk";
|
|
33
|
+
import { CodeFlow, PasswordFlow, Sql, Rpc, createApi, SignUp, createSqlBuilder } from "@centia-io/sdk";
|
|
34
34
|
import type { RpcRequest, RpcResponse, PgTypes } from "@centia-io/sdk";
|
|
35
35
|
```
|
|
36
36
|
|
|
@@ -205,6 +205,76 @@ interface Row extends PgTypes.DataRow {
|
|
|
205
205
|
const res = await sql.exec({ q: "...", params: payload }) as PgTypes.SQLResponse<Row>;
|
|
206
206
|
```
|
|
207
207
|
|
|
208
|
+
## SQL Builder
|
|
209
|
+
|
|
210
|
+
Build strongly typed SQL requests from a DB schema so you don't write raw SQL.
|
|
211
|
+
|
|
212
|
+
- Function: `createSqlBuilder(schema)`
|
|
213
|
+
- Types: `DBSchema`, `TableDef`, `ColumnDef`
|
|
214
|
+
- Supports: `select` (andWhere/orWhere, andWhereOp/orWhereOp, grouped predicates, orderBy, limit, offset, join, selectFrom), `insert(returning)`, `update(where, returning)`, `delete(where, returning)`
|
|
215
|
+
- Produces an object with `toSql(): SqlRequest` which you pass to `new Sql().exec()`
|
|
216
|
+
|
|
217
|
+
Example:
|
|
218
|
+
```ts
|
|
219
|
+
import { createSqlBuilder, Sql } from "@centia-io/sdk";
|
|
220
|
+
import type { DBSchema } from "@centia-io/sdk";
|
|
221
|
+
|
|
222
|
+
// Minimal schema (compatible with schema/schema.json).
|
|
223
|
+
const schema = {
|
|
224
|
+
name: "public",
|
|
225
|
+
tables: [
|
|
226
|
+
{
|
|
227
|
+
name: "items",
|
|
228
|
+
columns: [
|
|
229
|
+
{ name: "id", _typname: "int4", _is_array: false, is_nullable: false },
|
|
230
|
+
{ name: "name", _typname: "varchar", _is_array: false, is_nullable: true },
|
|
231
|
+
{ name: "type", _typname: "int4", _is_array: false, is_nullable: true }
|
|
232
|
+
]
|
|
233
|
+
}
|
|
234
|
+
]
|
|
235
|
+
} as const satisfies DBSchema;
|
|
236
|
+
|
|
237
|
+
const b = createSqlBuilder(schema);
|
|
238
|
+
|
|
239
|
+
// SELECT with where/order/limit
|
|
240
|
+
const selectReq = b.table("items")
|
|
241
|
+
.select(["id", "name"]) // or omit to select all: .select()
|
|
242
|
+
.andWhere({ type: [1, 2, 3] }) // => "type" = ANY(:param)
|
|
243
|
+
.orderBy([["id","desc"]])
|
|
244
|
+
.limit(10)
|
|
245
|
+
.toSql();
|
|
246
|
+
|
|
247
|
+
const sql = new Sql();
|
|
248
|
+
const rows = (await sql.exec(selectReq)).data;
|
|
249
|
+
|
|
250
|
+
// INSERT
|
|
251
|
+
const insertReq = b.table("items")
|
|
252
|
+
.insert({ id: 10, name: "Thing", type: 1 })
|
|
253
|
+
.returning(["id"])
|
|
254
|
+
.toSql();
|
|
255
|
+
await sql.exec(insertReq);
|
|
256
|
+
|
|
257
|
+
// UPDATE
|
|
258
|
+
const updateReq = b.table("items")
|
|
259
|
+
.update({ name: "Updated" })
|
|
260
|
+
.where({ id: 10 })
|
|
261
|
+
.returning(["id","name"])
|
|
262
|
+
.toSql();
|
|
263
|
+
await sql.exec(updateReq);
|
|
264
|
+
|
|
265
|
+
// DELETE
|
|
266
|
+
const deleteReq = b.table("items")
|
|
267
|
+
.delete()
|
|
268
|
+
.where({ id: 10 })
|
|
269
|
+
.toSql();
|
|
270
|
+
await sql.exec(deleteReq);
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Notes:
|
|
274
|
+
- The builder automatically adds `type_hints` for array parameters (e.g., `int4[]`), as arrays are not inferred by default by the server.
|
|
275
|
+
- Value types are inferred from `_typname` and `_is_array`. For `numeric/decimal`, use strings (`NumericString`).
|
|
276
|
+
- You can pass the same `SqlRequest` object to `Sql.exec`.
|
|
277
|
+
|
|
208
278
|
## RPC
|
|
209
279
|
|
|
210
280
|
Call JSON‑RPC methods exposed by GC2.
|
|
@@ -307,3 +377,194 @@ Notes:
|
|
|
307
377
|
## License
|
|
308
378
|
|
|
309
379
|
The SDK is licensed under [The MIT License](https://opensource.org/license/mit)
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## Advanced SqlBuilder examples (developer guide)
|
|
385
|
+
|
|
386
|
+
Below are practical, copy/paste‑ready snippets that demonstrate the SqlBuilder API in real scenarios. These mirror and condense the exhaustive examples in examples/test_builder.ts.
|
|
387
|
+
|
|
388
|
+
Setup (minimal schema with a foreign key for joins):
|
|
389
|
+
```ts
|
|
390
|
+
import { createSqlBuilder } from "@centia-io/sdk";
|
|
391
|
+
import type { DBSchema } from "@centia-io/sdk";
|
|
392
|
+
|
|
393
|
+
const schema = {
|
|
394
|
+
name: "public",
|
|
395
|
+
tables: [
|
|
396
|
+
{
|
|
397
|
+
name: "items",
|
|
398
|
+
columns: [
|
|
399
|
+
{ name: "id", _typname: "int4", _is_array: false, is_nullable: false },
|
|
400
|
+
{ name: "name", _typname: "varchar", _is_array: false, is_nullable: false },
|
|
401
|
+
{ name: "type", _typname: "int4", _is_array: false, is_nullable: false },
|
|
402
|
+
],
|
|
403
|
+
constraints: [
|
|
404
|
+
{ name: "items-pk", constraint: "primary", columns: ["id"] },
|
|
405
|
+
{
|
|
406
|
+
name: "items-type-fk",
|
|
407
|
+
constraint: "foreign",
|
|
408
|
+
columns: ["type"],
|
|
409
|
+
referenced_table: "item_types",
|
|
410
|
+
referenced_columns: ["id"],
|
|
411
|
+
},
|
|
412
|
+
],
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
name: "item_types",
|
|
416
|
+
columns: [
|
|
417
|
+
{ name: "id", _typname: "int4", _is_array: false, is_nullable: false },
|
|
418
|
+
{ name: "type", _typname: "varchar", _is_array: false, is_nullable: true },
|
|
419
|
+
],
|
|
420
|
+
constraints: [{ name: "item_types-pk", constraint: "primary", columns: ["id"] }],
|
|
421
|
+
},
|
|
422
|
+
],
|
|
423
|
+
} as const satisfies DBSchema;
|
|
424
|
+
|
|
425
|
+
const b = createSqlBuilder(schema);
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
- Selecting all or specific columns
|
|
429
|
+
```ts
|
|
430
|
+
b.table("items").select().toSql();
|
|
431
|
+
// select "items".* from "public"."items"
|
|
432
|
+
|
|
433
|
+
b.table("items").select(["id", "name"]).toSql();
|
|
434
|
+
// select "items"."id", "items"."name" from "public"."items"
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
- AND filters (equality and arrays -> ANY)
|
|
438
|
+
```ts
|
|
439
|
+
b.table("items").select()
|
|
440
|
+
.andWhere({ id: 3, type: [1,2,3] })
|
|
441
|
+
.toSql();
|
|
442
|
+
// where "items"."id" = :items_id_1 and "items"."type" = ANY(:items_type_2)
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
- OR filters (object groups)
|
|
446
|
+
```ts
|
|
447
|
+
b.table("items").select()
|
|
448
|
+
.orWhere({ id: 1 })
|
|
449
|
+
.orWhere({ id: 2 })
|
|
450
|
+
.toSql();
|
|
451
|
+
// where ("items"."id" = :items_id_1) or ("items"."id" = :items_id_2)
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
- Operator predicates: comparisons, LIKE variants, IN/NOT IN, NULL checks
|
|
455
|
+
```ts
|
|
456
|
+
b.table("items").select()
|
|
457
|
+
.andWhereOp("id", ">", 10)
|
|
458
|
+
.andWhereOp("name", "ilike", "%foo%")
|
|
459
|
+
.andWhereOp("type", "in", [1,2])
|
|
460
|
+
.andWhereOp("name", "isnull")
|
|
461
|
+
.toSql();
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
- Grouped predicates and OR chains
|
|
465
|
+
```ts
|
|
466
|
+
b.table("items").select()
|
|
467
|
+
.andWhereOpGroup([
|
|
468
|
+
["type", "in", [1,2]],
|
|
469
|
+
["id", ">=", 10],
|
|
470
|
+
])
|
|
471
|
+
.orWhereOpGroup([["name", "ilike", "%foo%"]])
|
|
472
|
+
.orWhereOpGroup([["name", "ilike", "%bar%"], ["id", "<", 50]])
|
|
473
|
+
.toSql();
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
- JOIN by foreign key + selecting from the joined table
|
|
477
|
+
```ts
|
|
478
|
+
// Auto-detects ON using FK items.type -> item_types.id
|
|
479
|
+
b.table("items").select(["id","name"]).join("item_types").toSql();
|
|
480
|
+
// select ... from "public"."items" inner join "public"."item_types" on "items"."type" = "item_types"."id"
|
|
481
|
+
|
|
482
|
+
// Select specific columns from joined table
|
|
483
|
+
b.table("items")
|
|
484
|
+
.select(["id"]) // base table columns
|
|
485
|
+
.join("item_types", "left") // join type: inner|left|right|full
|
|
486
|
+
.selectFrom("item_types", ["type"]) // joined table columns
|
|
487
|
+
.toSql();
|
|
488
|
+
|
|
489
|
+
// Select all columns from the joined table
|
|
490
|
+
b.table("items").select(["id"]).join("item_types").selectFrom("item_types").toSql();
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
- ORDER BY, LIMIT, OFFSET
|
|
494
|
+
```ts
|
|
495
|
+
b.table("items").select().orderBy("id").toSql();
|
|
496
|
+
// order by "items"."id" asc
|
|
497
|
+
|
|
498
|
+
b.table("items").select().orderBy([["type","desc"],["id","asc"]]).toSql();
|
|
499
|
+
|
|
500
|
+
b.table("items").select().limit(25).offset(50).toSql();
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
- INSERT, UPDATE, DELETE
|
|
504
|
+
```ts
|
|
505
|
+
b.table("items").insert({ id: 1, name: "A", type: 1 }).returning(["id"]).toSql();
|
|
506
|
+
|
|
507
|
+
b.table("items").update({ name: "B" }).where({ id: 1 }).returning(["id","name"]).toSql();
|
|
508
|
+
|
|
509
|
+
b.table("items").delete().where({ id: 1 }).toSql();
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
- Special value types (ranges, intervals, geometry) – supported at compile‑time and runtime
|
|
513
|
+
```ts
|
|
514
|
+
// Ranges (e.g., tstzrange)
|
|
515
|
+
const events = {
|
|
516
|
+
name: "public",
|
|
517
|
+
tables: [{
|
|
518
|
+
name: "events",
|
|
519
|
+
columns: [
|
|
520
|
+
{ name: "id", _typname: "int4", _is_array: false, is_nullable: false },
|
|
521
|
+
{ name: "period", _typname: "tstzrange", _is_array: false, is_nullable: true },
|
|
522
|
+
]
|
|
523
|
+
}]
|
|
524
|
+
} as const satisfies DBSchema;
|
|
525
|
+
|
|
526
|
+
createSqlBuilder(events).table("events").select().andWhere({
|
|
527
|
+
period: {
|
|
528
|
+
lower: "2024-01-01T00:00:00+00:00",
|
|
529
|
+
upper: "2024-12-31T23:59:59+00:00",
|
|
530
|
+
lowerInclusive: true,
|
|
531
|
+
upperInclusive: false,
|
|
532
|
+
}
|
|
533
|
+
}).toSql();
|
|
534
|
+
|
|
535
|
+
// Interval
|
|
536
|
+
const durations = {
|
|
537
|
+
name: "public",
|
|
538
|
+
tables: [{
|
|
539
|
+
name: "durations",
|
|
540
|
+
columns: [
|
|
541
|
+
{ name: "id", _typname: "int4", _is_array: false, is_nullable: false },
|
|
542
|
+
{ name: "duration", _typname: "interval", _is_array: false, is_nullable: true },
|
|
543
|
+
]
|
|
544
|
+
}]
|
|
545
|
+
} as const satisfies DBSchema;
|
|
546
|
+
|
|
547
|
+
createSqlBuilder(durations).table("durations").select().andWhere({
|
|
548
|
+
duration: { y: 0, m: 1, d: 0, h: 2, i: 0, s: 0 }
|
|
549
|
+
}).toSql();
|
|
550
|
+
|
|
551
|
+
// Geometry (point example)
|
|
552
|
+
const shapes = {
|
|
553
|
+
name: "public",
|
|
554
|
+
tables: [{
|
|
555
|
+
name: "shapes",
|
|
556
|
+
columns: [
|
|
557
|
+
{ name: "id", _typname: "int4", _is_array: false, is_nullable: false },
|
|
558
|
+
{ name: "pt", _typname: "point", _is_array: false, is_nullable: true },
|
|
559
|
+
]
|
|
560
|
+
}]
|
|
561
|
+
} as const satisfies DBSchema;
|
|
562
|
+
|
|
563
|
+
createSqlBuilder(shapes).table("shapes").select().andWhere({ pt: { x: 1, y: 2 } }).toSql();
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
Notes and tips:
|
|
567
|
+
- All SQL is schema‑qualified: from "schema"."table" and in JOINs.
|
|
568
|
+
- Type hints are added automatically for all parameters (scalars and arrays). Arrays are hinted as e.g. int4[], scalars as their base type (e.g., int4, varchar, jsonb).
|
|
569
|
+
- Runtime validation mirrors the editor’s type checks: invalid column names, wrong orderBy direction, bad join type, negative limit/offset, wrong where/whereOp value shapes (including range/interval/geometry), and nulls on non‑nullable columns produce clear errors.
|
|
570
|
+
- For more, see the full script in examples/test_builder.ts which prints the generated SQL and parameters for dozens of cases.
|