@noormdev/sdk 1.0.2 → 1.1.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/README.md +23 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +67 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -71,6 +71,29 @@ await ctx.proc('refresh_cache');
|
|
|
71
71
|
`createContext<DB, Procs, Funcs, Tvfs>` takes a map per routine kind. Plain `void` is shorthand for "no arguments, no meaningful return".
|
|
72
72
|
|
|
73
73
|
|
|
74
|
+
## Schema scoping
|
|
75
|
+
|
|
76
|
+
`ctx.withSchema<SDB>(name)` derives a `Context` scoped to one schema — same connection, pool, and lifecycle as the parent, just qualified generics and query builder.
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
const acct = ctx.withSchema<AcctDB>('accounting');
|
|
80
|
+
|
|
81
|
+
const invoices = await acct.kysely.selectFrom('invoices').selectAll().execute();
|
|
82
|
+
// select * from "accounting"."invoices" — typed against AcctDB
|
|
83
|
+
|
|
84
|
+
await acct.proc('rebuild_ledger', { year: 2026 });
|
|
85
|
+
// CALL "accounting"."rebuild_ledger"("year" => $1)
|
|
86
|
+
|
|
87
|
+
await ctx.kysely.selectFrom('users').execute(); // parent untouched, no prefix
|
|
88
|
+
|
|
89
|
+
await ctx.disconnect(); // one lifecycle closes both
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Calling `withSchema` again replaces the schema instead of stacking it, and a `proc`/`func`/`tvf` name that already contains a `.` passes through unqualified. Raw `` sql`…` `` fragments are not rewritten — they resolve against the connection's default schema regardless of `withSchema`.
|
|
93
|
+
|
|
94
|
+
Non-goals: no config/connection-level schema field (the connection stays schema-agnostic); no schema-defaulting of `ctx.noorm.db.describe*`'s `schema?` arg; no per-dialect gating — the qualifier means whatever the dialect makes of it (a schema on postgres/mssql, a database on mysql, an ATTACHed database on sqlite).
|
|
95
|
+
|
|
96
|
+
|
|
74
97
|
## Requires
|
|
75
98
|
|
|
76
99
|
Node >= 22.13. Supports **PostgreSQL**, **MySQL**, **SQLite**, and **SQL Server**.
|
package/dist/index.d.ts
CHANGED
|
@@ -3820,6 +3820,31 @@ export declare class Context<DB = unknown, Procs = object, Funcs = object, Tvfs
|
|
|
3820
3820
|
get dialect(): Dialect;
|
|
3821
3821
|
get connected(): boolean;
|
|
3822
3822
|
get kysely(): Kysely<DB>;
|
|
3823
|
+
/**
|
|
3824
|
+
* Derive a schema-scoped Context sharing this context's connection,
|
|
3825
|
+
* pool, and #heldConnections — same lifecycle, fresh generics for the
|
|
3826
|
+
* schema's own table/routine shape.
|
|
3827
|
+
*
|
|
3828
|
+
* Replaces rather than stacks: calling withSchema() again on an
|
|
3829
|
+
* already-derived context swaps the schema instead of nesting it,
|
|
3830
|
+
* because every derived context re-derives its `.kysely` from the
|
|
3831
|
+
* shared connection's bare instance, never from another derived
|
|
3832
|
+
* context's already-wrapped one.
|
|
3833
|
+
*
|
|
3834
|
+
* `sql`-tagged raw fragments are not rewritten by this — they resolve
|
|
3835
|
+
* against the connection's default schema regardless of this call.
|
|
3836
|
+
*
|
|
3837
|
+
* @throws Error synchronously if `name` fails identifier validation,
|
|
3838
|
+
* before any connection is borrowed or shared state is touched.
|
|
3839
|
+
*
|
|
3840
|
+
* @example
|
|
3841
|
+
* ```typescript
|
|
3842
|
+
* const acct = ctx.withSchema<AcctDB>('acct');
|
|
3843
|
+
* const rows = await acct.kysely.selectFrom('ledger').selectAll().execute();
|
|
3844
|
+
* await acct.proc('rebuild_ledger', { id: 1 }); // -> acct.rebuild_ledger
|
|
3845
|
+
* ```
|
|
3846
|
+
*/
|
|
3847
|
+
withSchema<SDB = DB, SProcs = Procs, SFuncs = Funcs, STvfs = Tvfs>(name: string): Context<SDB, SProcs, SFuncs, STvfs>;
|
|
3823
3848
|
/**
|
|
3824
3849
|
* Noorm management operations.
|
|
3825
3850
|
*
|
package/dist/index.js
CHANGED
|
@@ -15486,7 +15486,19 @@ function buildScope(db, revertFn, dialect) {
|
|
|
15486
15486
|
}
|
|
15487
15487
|
|
|
15488
15488
|
// src/sdk/context.ts
|
|
15489
|
-
var
|
|
15489
|
+
var VALID_SCHEMA_NAME = /^[a-zA-Z0-9_-]+$/;
|
|
15490
|
+
function validateSchemaName(name) {
|
|
15491
|
+
if (!name || !VALID_SCHEMA_NAME.test(name)) {
|
|
15492
|
+
throw new Error(
|
|
15493
|
+
`Invalid schema name: "${name}". Only alphanumeric characters, underscores, and hyphens are allowed.`
|
|
15494
|
+
);
|
|
15495
|
+
}
|
|
15496
|
+
}
|
|
15497
|
+
function qualifyName(schema, name) {
|
|
15498
|
+
if (!schema || name.includes(".")) return name;
|
|
15499
|
+
return `${schema}.${name}`;
|
|
15500
|
+
}
|
|
15501
|
+
var Context = class _Context {
|
|
15490
15502
|
#state;
|
|
15491
15503
|
#noorm = null;
|
|
15492
15504
|
/**
|
|
@@ -15496,6 +15508,12 @@ var Context = class {
|
|
|
15496
15508
|
* pool can never reclaim, and the context never closes.
|
|
15497
15509
|
*/
|
|
15498
15510
|
#heldConnections = /* @__PURE__ */ new Set();
|
|
15511
|
+
/**
|
|
15512
|
+
* Schema this context is scoped to, or `null` for the root context.
|
|
15513
|
+
* Set once by withSchema() and never mutated afterward — a chained
|
|
15514
|
+
* withSchema() call derives a new Context rather than changing this.
|
|
15515
|
+
*/
|
|
15516
|
+
#schema = null;
|
|
15499
15517
|
constructor(config, settings, identity, options, projectRoot) {
|
|
15500
15518
|
this.#state = {
|
|
15501
15519
|
connection: null,
|
|
@@ -15517,7 +15535,49 @@ var Context = class {
|
|
|
15517
15535
|
return this.#state.connection !== null;
|
|
15518
15536
|
}
|
|
15519
15537
|
get kysely() {
|
|
15520
|
-
|
|
15538
|
+
const db = requireConnection(this.#state).db;
|
|
15539
|
+
return this.#schema === null ? db : db.withSchema(this.#schema);
|
|
15540
|
+
}
|
|
15541
|
+
// ─────────────────────────────────────────────────────────
|
|
15542
|
+
// Schema Scoping
|
|
15543
|
+
// ─────────────────────────────────────────────────────────
|
|
15544
|
+
/**
|
|
15545
|
+
* Derive a schema-scoped Context sharing this context's connection,
|
|
15546
|
+
* pool, and #heldConnections — same lifecycle, fresh generics for the
|
|
15547
|
+
* schema's own table/routine shape.
|
|
15548
|
+
*
|
|
15549
|
+
* Replaces rather than stacks: calling withSchema() again on an
|
|
15550
|
+
* already-derived context swaps the schema instead of nesting it,
|
|
15551
|
+
* because every derived context re-derives its `.kysely` from the
|
|
15552
|
+
* shared connection's bare instance, never from another derived
|
|
15553
|
+
* context's already-wrapped one.
|
|
15554
|
+
*
|
|
15555
|
+
* `sql`-tagged raw fragments are not rewritten by this — they resolve
|
|
15556
|
+
* against the connection's default schema regardless of this call.
|
|
15557
|
+
*
|
|
15558
|
+
* @throws Error synchronously if `name` fails identifier validation,
|
|
15559
|
+
* before any connection is borrowed or shared state is touched.
|
|
15560
|
+
*
|
|
15561
|
+
* @example
|
|
15562
|
+
* ```typescript
|
|
15563
|
+
* const acct = ctx.withSchema<AcctDB>('acct');
|
|
15564
|
+
* const rows = await acct.kysely.selectFrom('ledger').selectAll().execute();
|
|
15565
|
+
* await acct.proc('rebuild_ledger', { id: 1 }); // -> acct.rebuild_ledger
|
|
15566
|
+
* ```
|
|
15567
|
+
*/
|
|
15568
|
+
withSchema(name) {
|
|
15569
|
+
validateSchemaName(name);
|
|
15570
|
+
const derived = new _Context(
|
|
15571
|
+
this.#state.config,
|
|
15572
|
+
this.#state.settings,
|
|
15573
|
+
this.#state.identity,
|
|
15574
|
+
this.#state.options,
|
|
15575
|
+
this.#state.projectRoot
|
|
15576
|
+
);
|
|
15577
|
+
derived.#state = this.#state;
|
|
15578
|
+
derived.#heldConnections = this.#heldConnections;
|
|
15579
|
+
derived.#schema = name;
|
|
15580
|
+
return derived;
|
|
15521
15581
|
}
|
|
15522
15582
|
// ─────────────────────────────────────────────────────────
|
|
15523
15583
|
// Noorm Namespace
|
|
@@ -15622,10 +15682,11 @@ var Context = class {
|
|
|
15622
15682
|
*/
|
|
15623
15683
|
async proc(name, ...args) {
|
|
15624
15684
|
const params = args[0];
|
|
15685
|
+
const qualifiedName4 = qualifyName(this.#schema, name);
|
|
15625
15686
|
if (this.dialect === "postgres") {
|
|
15626
|
-
return this.#executeProcPostgres(
|
|
15687
|
+
return this.#executeProcPostgres(qualifiedName4, params);
|
|
15627
15688
|
}
|
|
15628
|
-
const query = buildProcCall(this.dialect,
|
|
15689
|
+
const query = buildProcCall(this.dialect, qualifiedName4, params);
|
|
15629
15690
|
const result = await query.execute(this.kysely);
|
|
15630
15691
|
return result.rows ?? [];
|
|
15631
15692
|
}
|
|
@@ -15678,7 +15739,7 @@ var Context = class {
|
|
|
15678
15739
|
const hasParams = !(args.length === 1 && typeof args[0] === "string");
|
|
15679
15740
|
const params = hasParams ? args[0] : void 0;
|
|
15680
15741
|
const column = hasParams ? args[1] : args[0];
|
|
15681
|
-
const query = buildFuncCall(this.dialect, name, column, params);
|
|
15742
|
+
const query = buildFuncCall(this.dialect, qualifyName(this.#schema, name), column, params);
|
|
15682
15743
|
const result = await query.execute(this.kysely);
|
|
15683
15744
|
return result.rows?.[0] ?? null;
|
|
15684
15745
|
}
|
|
@@ -15706,7 +15767,7 @@ var Context = class {
|
|
|
15706
15767
|
*/
|
|
15707
15768
|
async tvf(name, ...args) {
|
|
15708
15769
|
const params = args[0];
|
|
15709
|
-
const query = buildTvfCall(this.dialect, name, params);
|
|
15770
|
+
const query = buildTvfCall(this.dialect, qualifyName(this.#schema, name), params);
|
|
15710
15771
|
const result = await query.execute(this.kysely);
|
|
15711
15772
|
return result.rows ?? [];
|
|
15712
15773
|
}
|