@palbase/backend 38.0.15 → 39.0.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/bin/palbase-backend.cjs +46 -1
- package/dist/bin/palbase-backend.cjs.map +1 -1
- package/dist/bin/palbase-backend.js +5 -5
- package/dist/{chunk-LFUNRWUE.js → chunk-4J6I4KVQ.js} +67 -3
- package/dist/{chunk-LFUNRWUE.js.map → chunk-4J6I4KVQ.js.map} +1 -1
- package/dist/{chunk-7WAGQ3VR.js → chunk-AR2I4M7I.js} +497 -17
- package/dist/chunk-AR2I4M7I.js.map +1 -0
- package/dist/{chunk-YANGWAIM.js → chunk-H7EKL6HC.js} +2 -2
- package/dist/{chunk-EHKEMHB4.js → chunk-JJSR4BUX.js} +49 -5
- package/dist/chunk-JJSR4BUX.js.map +1 -0
- package/dist/{chunk-CS6NQ6PO.js → chunk-JPTFYHP3.js} +2 -2
- package/dist/{chunk-CS6NQ6PO.js.map → chunk-JPTFYHP3.js.map} +1 -1
- package/dist/{chunk-X7UR3VXA.js → chunk-XZWOMPD3.js} +3 -2
- package/dist/chunk-XZWOMPD3.js.map +1 -0
- package/dist/{chunk-PDD55QWN.js → chunk-ZNQDL466.js} +2 -2
- package/dist/db/index.cjs +378 -14
- package/dist/db/index.cjs.map +1 -1
- package/dist/db/index.d.cts +1 -1
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.js +3 -3
- package/dist/engine/index.cjs +46 -1
- package/dist/engine/index.cjs.map +1 -1
- package/dist/engine/index.d.cts +3 -3
- package/dist/engine/index.d.ts +3 -3
- package/dist/engine/index.js +5 -5
- package/dist/{index-CI7S0Wqv.d.cts → index-B0mjUnxy.d.cts} +25 -2
- package/dist/{index-CUy50OLU.d.ts → index-eN4KzGa5.d.ts} +555 -29
- package/dist/{index-DRx880KY.d.cts → index-pK2At5Yc.d.cts} +555 -29
- package/dist/{index-Ogi30dbt.d.ts → index-yDno9Ju9.d.ts} +25 -2
- package/dist/index.cjs +628 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +183 -8
- package/dist/index.d.ts +183 -8
- package/dist/index.js +74 -6
- package/dist/index.js.map +1 -1
- package/dist/openapi/index.cjs.map +1 -1
- package/dist/openapi/index.d.cts +2 -2
- package/dist/openapi/index.d.ts +2 -2
- package/dist/openapi/index.js +2 -2
- package/dist/{registry-C7UCkQf0.d.cts → registry-9dNeVN5d.d.cts} +1 -1
- package/dist/{registry-DJcvbomD.d.ts → registry-B8ddZiMY.d.ts} +1 -1
- package/dist/test/index.cjs +19 -0
- package/dist/test/index.cjs.map +1 -1
- package/dist/test/index.d.cts +1 -1
- package/dist/test/index.d.ts +1 -1
- package/dist/test/index.js +20 -2
- package/dist/test/index.js.map +1 -1
- package/docs/README.md +1 -1
- package/docs/database.md +79 -0
- package/docs/llms-full.txt +462 -33
- package/docs/schema.md +382 -32
- package/package.json +1 -1
- package/template/package.json +1 -1
- package/dist/chunk-7WAGQ3VR.js.map +0 -1
- package/dist/chunk-EHKEMHB4.js.map +0 -1
- package/dist/chunk-X7UR3VXA.js.map +0 -1
- /package/dist/{chunk-YANGWAIM.js.map → chunk-H7EKL6HC.js.map} +0 -0
- /package/dist/{chunk-PDD55QWN.js.map → chunk-ZNQDL466.js.map} +0 -0
package/dist/db/index.cjs
CHANGED
|
@@ -24,7 +24,7 @@ __export(db_exports, {
|
|
|
24
24
|
EXTENSION_DEPENDENCIES: () => EXTENSION_DEPENDENCIES,
|
|
25
25
|
PALBASE_EXTENSIONS: () => PALBASE_EXTENSIONS,
|
|
26
26
|
PolicyBuilder: () => PolicyBuilder,
|
|
27
|
-
TABLE_META: () =>
|
|
27
|
+
TABLE_META: () => TABLE_META2,
|
|
28
28
|
TxPlanError: () => TxPlanError,
|
|
29
29
|
TxRefError: () => TxRefError,
|
|
30
30
|
bigint: () => bigint,
|
|
@@ -60,6 +60,184 @@ __name(qualifiedTableKey, "qualifiedTableKey");
|
|
|
60
60
|
|
|
61
61
|
// src/db/policy.ts
|
|
62
62
|
var import_zod = require("zod");
|
|
63
|
+
|
|
64
|
+
// src/db/foreign-key.ts
|
|
65
|
+
var TABLE_META = /* @__PURE__ */ Symbol.for("palbase.table.meta");
|
|
66
|
+
var REF_TARGET = /* @__PURE__ */ Symbol.for("palbase.ref.target");
|
|
67
|
+
var ForeignKeyBuilder = class {
|
|
68
|
+
static {
|
|
69
|
+
__name(this, "ForeignKeyBuilder");
|
|
70
|
+
}
|
|
71
|
+
_def;
|
|
72
|
+
constructor(name) {
|
|
73
|
+
if (name.trim() === "") {
|
|
74
|
+
throw new Error("foreignKey(ad): foreign key'in ad\u0131 bo\u015F olamaz \u2014 Palbase k\u0131s\u0131tlar\u0131 ADA g\xF6re uzla\u015Ft\u0131r\u0131r.");
|
|
75
|
+
}
|
|
76
|
+
this._def = {
|
|
77
|
+
name,
|
|
78
|
+
columns: [],
|
|
79
|
+
refTable: "",
|
|
80
|
+
refColumns: []
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/** Yerel sütunlar. SIRA KORUNUR — hedef sütunlarla birebir eşleşir. */
|
|
84
|
+
on(...cols) {
|
|
85
|
+
this._def.columns = cols.map((c) => {
|
|
86
|
+
const e = c.expr;
|
|
87
|
+
if (e.kind !== "col") {
|
|
88
|
+
throw new Error(`foreignKey(${this._def.name}).on(): yaln\u0131z kolon referans\u0131 al\u0131r \u2014 ifade bir FK'n\u0131n par\xE7as\u0131 olamaz.`);
|
|
89
|
+
}
|
|
90
|
+
return e.name;
|
|
91
|
+
});
|
|
92
|
+
return this;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Hedef tablo ve sütunları. Sütun sayısı `.on()`'unkiyle eşit OLMALI ve bu
|
|
96
|
+
* burada, bildirim yazılırken kontrol edilir — bozuk bir FK wire'a hiç çıkmaz.
|
|
97
|
+
*/
|
|
98
|
+
references(table, ...cols) {
|
|
99
|
+
if (cols.length === 0) {
|
|
100
|
+
throw new Error(`foreignKey(${this._def.name}).references(): en az bir hedef s\xFCtun gerekir.`);
|
|
101
|
+
}
|
|
102
|
+
this._def.refTable = table[TABLE_META].name;
|
|
103
|
+
this._def.refColumns = [
|
|
104
|
+
...cols
|
|
105
|
+
];
|
|
106
|
+
Object.defineProperty(this._def, REF_TARGET, {
|
|
107
|
+
value: table[TABLE_META],
|
|
108
|
+
enumerable: false,
|
|
109
|
+
configurable: true
|
|
110
|
+
});
|
|
111
|
+
return this;
|
|
112
|
+
}
|
|
113
|
+
onUpdate(action) {
|
|
114
|
+
this._def.onUpdate = action;
|
|
115
|
+
return this;
|
|
116
|
+
}
|
|
117
|
+
onDelete(action) {
|
|
118
|
+
this._def.onDelete = action;
|
|
119
|
+
return this;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* `MATCH FULL`: referans veren sütunların HEPSİ NULL olmadıkça kısıt
|
|
123
|
+
* değerlendirilir. Varsayılan `MATCH SIMPLE`'da tek bir NULL kısıtı atlatır —
|
|
124
|
+
* `freeze` bunu bilerek kullanır, sıradan bir FK'da genelde istenmez.
|
|
125
|
+
*/
|
|
126
|
+
match(m) {
|
|
127
|
+
this._def.match = m;
|
|
128
|
+
return this;
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
function toForeignKeyDef(b) {
|
|
132
|
+
const def = b instanceof ForeignKeyBuilder ? b._def : b;
|
|
133
|
+
if (def.columns.length === 0) {
|
|
134
|
+
throw new Error(`foreignKey(${def.name}): en az bir yerel s\xFCtun gerekir \u2014 .on(...) \xE7a\u011F\u0131r\u0131n.`);
|
|
135
|
+
}
|
|
136
|
+
if (def.refColumns.length === 0 || def.refTable === "") {
|
|
137
|
+
throw new Error(`foreignKey(${def.name}): hedef tablo ve s\xFCtunlar gerekir \u2014 .references(...) \xE7a\u011F\u0131r\u0131n.`);
|
|
138
|
+
}
|
|
139
|
+
if (def.columns.length !== def.refColumns.length) {
|
|
140
|
+
throw new Error(`foreignKey(${def.name}): ${def.columns.length} yerel s\xFCtun (${def.columns.join(", ")}) ama ${def.refColumns.length} hedef s\xFCtun (${def.refColumns.join(", ")}) \u2014 iki liste e\u015Fit uzunlukta olmal\u0131.`);
|
|
141
|
+
}
|
|
142
|
+
return def;
|
|
143
|
+
}
|
|
144
|
+
__name(toForeignKeyDef, "toForeignKeyDef");
|
|
145
|
+
var FreezeBuilder = class {
|
|
146
|
+
static {
|
|
147
|
+
__name(this, "FreezeBuilder");
|
|
148
|
+
}
|
|
149
|
+
_def;
|
|
150
|
+
constructor(name) {
|
|
151
|
+
if (name.trim() === "") {
|
|
152
|
+
throw new Error("freeze(ad): freeze k\u0131s\u0131t\u0131n\u0131n ad\u0131 bo\u015F olamaz \u2014 Palbase k\u0131s\u0131tlar\u0131 ADA g\xF6re uzla\u015Ft\u0131r\u0131r.");
|
|
153
|
+
}
|
|
154
|
+
this._def = {
|
|
155
|
+
name,
|
|
156
|
+
columns: [],
|
|
157
|
+
refTable: "",
|
|
158
|
+
refColumns: []
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* DONMA KOŞULU — çocuk satırının kendi kolonları üzerinde bir yüklem.
|
|
163
|
+
*
|
|
164
|
+
* Generated sütunlara `CASE WHEN <koşul> THEN <sütun> END` olarak iner; yani
|
|
165
|
+
* koşul yanlışken sütunlar NULL olur ve FK o satır için hiç değerlendirilmez.
|
|
166
|
+
*/
|
|
167
|
+
when(pred) {
|
|
168
|
+
this._def.when = pred.expr;
|
|
169
|
+
return this;
|
|
170
|
+
}
|
|
171
|
+
/** Çocuğun DONAN sütunları. SIRA KORUNUR — hedef sütunlarla birebir eşleşir. */
|
|
172
|
+
columns(...cols) {
|
|
173
|
+
if (cols.length === 0) {
|
|
174
|
+
throw new Error(`freeze(${this._def.name}).columns(): en az bir donan s\xFCtun gerekir \u2014 hi\xE7birini vermeyen bir freeze hi\xE7bir \u015Feyi dondurmaz.`);
|
|
175
|
+
}
|
|
176
|
+
this._def.columns = [
|
|
177
|
+
...cols
|
|
178
|
+
];
|
|
179
|
+
return this;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Ebeveyn tablo ve donan demetin ORADAKİ karşılığı. Zincirin SON halkası:
|
|
183
|
+
* bildirim burada tamamlanır ve tutarlılığı burada doğrulanır, yani
|
|
184
|
+
* `.references()`'ı unutmuş bir freeze `FreezeDef` üretmediği için tabloya
|
|
185
|
+
* hiç giremez.
|
|
186
|
+
*/
|
|
187
|
+
references(table, ...cols) {
|
|
188
|
+
if (cols.length === 0) {
|
|
189
|
+
throw new Error(`freeze(${this._def.name}).references(): en az bir hedef s\xFCtun gerekir.`);
|
|
190
|
+
}
|
|
191
|
+
this._def.refTable = table[TABLE_META].name;
|
|
192
|
+
this._def.refColumns = [
|
|
193
|
+
...cols
|
|
194
|
+
];
|
|
195
|
+
Object.defineProperty(this._def, REF_TARGET, {
|
|
196
|
+
value: table[TABLE_META],
|
|
197
|
+
enumerable: false,
|
|
198
|
+
configurable: true
|
|
199
|
+
});
|
|
200
|
+
return toFreezeDef(this);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
function toFreezeDef(b) {
|
|
204
|
+
const def = b instanceof FreezeBuilder ? b._def : b;
|
|
205
|
+
if (def.columns.length === 0) {
|
|
206
|
+
throw new Error(`freeze(${def.name}): en az bir donan s\xFCtun gerekir \u2014 .columns(...) \xE7a\u011F\u0131r\u0131n.`);
|
|
207
|
+
}
|
|
208
|
+
if (def.refColumns.length === 0 || def.refTable === "") {
|
|
209
|
+
throw new Error(`freeze(${def.name}): hedef tablo ve s\xFCtunlar gerekir \u2014 .references(...) \xE7a\u011F\u0131r\u0131n.`);
|
|
210
|
+
}
|
|
211
|
+
if (def.columns.length !== def.refColumns.length) {
|
|
212
|
+
throw new Error(`freeze(${def.name}): ${def.columns.length} donan s\xFCtun (${def.columns.join(", ")}) ama ${def.refColumns.length} hedef s\xFCtun (${def.refColumns.join(", ")}) \u2014 iki liste e\u015Fit uzunlukta olmal\u0131.`);
|
|
213
|
+
}
|
|
214
|
+
if (def.when === void 0) {
|
|
215
|
+
throw new Error(`freeze(${def.name}): donma ko\u015Fulu gerekir \u2014 .when(...) \xE7a\u011F\u0131r\u0131n. Ko\u015Fulsuz bir freeze s\u0131radan bir FK'd\u0131r; onun i\xE7in foreignKey(...) var.`);
|
|
216
|
+
}
|
|
217
|
+
const out = {
|
|
218
|
+
name: def.name,
|
|
219
|
+
when: def.when,
|
|
220
|
+
columns: [
|
|
221
|
+
...def.columns
|
|
222
|
+
],
|
|
223
|
+
refTable: def.refTable,
|
|
224
|
+
refColumns: [
|
|
225
|
+
...def.refColumns
|
|
226
|
+
]
|
|
227
|
+
};
|
|
228
|
+
const target = def[REF_TARGET];
|
|
229
|
+
if (target !== void 0) {
|
|
230
|
+
Object.defineProperty(out, REF_TARGET, {
|
|
231
|
+
value: target,
|
|
232
|
+
enumerable: false,
|
|
233
|
+
configurable: true
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
return out;
|
|
237
|
+
}
|
|
238
|
+
__name(toFreezeDef, "toFreezeDef");
|
|
239
|
+
|
|
240
|
+
// src/db/policy.ts
|
|
63
241
|
var PolicyExprRef = class _PolicyExprRef {
|
|
64
242
|
static {
|
|
65
243
|
__name(this, "PolicyExprRef");
|
|
@@ -171,15 +349,21 @@ function exprCtx(_columns, depth = 0, ownTable = "") {
|
|
|
171
349
|
expr: part.expr
|
|
172
350
|
}), "not"),
|
|
173
351
|
existsIn: /* @__PURE__ */ __name((table, predicate) => {
|
|
174
|
-
const meta = table[
|
|
352
|
+
const meta = table[TABLE_META2];
|
|
175
353
|
const inner = exprCtx(Object.keys(meta.columns), depth + 1, ownTable);
|
|
176
|
-
|
|
354
|
+
const node = {
|
|
177
355
|
kind: "exists",
|
|
178
356
|
table: meta.name,
|
|
179
357
|
alias: `pb_e${depth + 1}`,
|
|
180
358
|
outer: ownTable,
|
|
181
359
|
predicate: predicate(inner).expr
|
|
360
|
+
};
|
|
361
|
+
Object.defineProperty(node, REF_TARGET, {
|
|
362
|
+
value: meta,
|
|
363
|
+
enumerable: false,
|
|
364
|
+
configurable: true
|
|
182
365
|
});
|
|
366
|
+
return new PolicyExprRef(node);
|
|
183
367
|
}, "existsIn")
|
|
184
368
|
};
|
|
185
369
|
}
|
|
@@ -267,13 +451,13 @@ var PolicyBuilder = class {
|
|
|
267
451
|
* // → id IN (SELECT "channel_id" FROM "channel_members"
|
|
268
452
|
* // WHERE "user_id" = (select auth.uid()))
|
|
269
453
|
*/
|
|
270
|
-
memberOf(membershipTable,
|
|
454
|
+
memberOf(membershipTable, foreignKey2, options = {}) {
|
|
271
455
|
if (this._def.using !== null) {
|
|
272
456
|
throw new Error(`policy(${this._def.name}).memberOf(): this policy already has a using() expression. Write one or the other \u2014 memberOf IS the using expression.`);
|
|
273
457
|
}
|
|
274
458
|
const column = options.column ?? "id";
|
|
275
459
|
const userColumn = options.userColumn ?? "user_id";
|
|
276
|
-
this._def.using = `${quote(column)} IN (SELECT ${quote(
|
|
460
|
+
this._def.using = `${quote(column)} IN (SELECT ${quote(foreignKey2)} FROM ${quote(membershipTable)} WHERE ${quote(userColumn)} = (select auth.uid()))`;
|
|
277
461
|
return this;
|
|
278
462
|
}
|
|
279
463
|
/** `WITH CHECK (...)` yazma doğrulaması — `using` ile aynı iki biçim. */
|
|
@@ -311,6 +495,98 @@ function reservedCanRelation(tableName, columns) {
|
|
|
311
495
|
}
|
|
312
496
|
__name(reservedCanRelation, "reservedCanRelation");
|
|
313
497
|
|
|
498
|
+
// src/db/guard.ts
|
|
499
|
+
var GuardBuilder = class {
|
|
500
|
+
static {
|
|
501
|
+
__name(this, "GuardBuilder");
|
|
502
|
+
}
|
|
503
|
+
_def;
|
|
504
|
+
constructor(name) {
|
|
505
|
+
if (name.trim() === "") {
|
|
506
|
+
throw new Error("guard(ad): guard'\u0131n ad\u0131 bo\u015F olamaz \u2014 Postgres ayn\u0131 olaydaki trigger'lar\u0131 ADA G\xD6RE alfabetik ko\u015Fuyor ve ba\u015Fka s\u0131ra tutamac\u0131 yok.");
|
|
507
|
+
}
|
|
508
|
+
this._def = {
|
|
509
|
+
name
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
/** Hangi yazma fiilinde bakılacak. */
|
|
513
|
+
on(event) {
|
|
514
|
+
this._def.event = event;
|
|
515
|
+
return this;
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Satırın KENDİ kolonları üzerinde koşul — trigger'ın `WHEN` yan tümcesi.
|
|
519
|
+
*
|
|
520
|
+
* Emitter karşılaştırmaları `IS DISTINCT FROM` ile yazar (`<>` NULL'da yanlış
|
|
521
|
+
* cevap verir) ve geçen sütunlardan bir `UPDATE OF (…)` listesi türetir
|
|
522
|
+
* (FR-018).
|
|
523
|
+
*/
|
|
524
|
+
when(pred) {
|
|
525
|
+
this._def.when = pred.expr;
|
|
526
|
+
return this;
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* ÇAPRAZ SATIR koşulu — gövdedeki `EXISTS` bloğuna iner, `WHEN`'e DEĞİL:
|
|
530
|
+
* Postgres trigger `WHEN`'inde alt sorgu kabul etmiyor (FR-019).
|
|
531
|
+
*
|
|
532
|
+
* Yüklem içinde takma adsız kalan kolon guard'ın KENDİ satırıdır (`NEW`/`OLD`);
|
|
533
|
+
* `r.col(...)` hedef tablonun kolonlarını verir ve ayrı nitelenir. Bu yüzden
|
|
534
|
+
* düğümün `outer` alanı BOŞ kalır: bir guard'ın "dış satır"ı bir tablo takma
|
|
535
|
+
* adı değildir.
|
|
536
|
+
*/
|
|
537
|
+
exists(table, predicate) {
|
|
538
|
+
this._def.exists = exprCtx().existsIn(table, predicate).expr;
|
|
539
|
+
return this;
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* REDDİN KENDİSİ ve zincirin son halkası: mesaj olmadan bir guard tamamlanmaz.
|
|
543
|
+
*
|
|
544
|
+
* `detail`/`hint` Postgres'in aynı adlı alanlarına, `column` ise `COLUMN`
|
|
545
|
+
* alanına gider — istemci hangi alanın reddedildiğini mesajı parse etmeden
|
|
546
|
+
* okur.
|
|
547
|
+
*/
|
|
548
|
+
refuse(message, opts) {
|
|
549
|
+
this._def.message = message;
|
|
550
|
+
if (opts?.detail !== void 0) this._def.detail = opts.detail;
|
|
551
|
+
if (opts?.hint !== void 0) this._def.hint = opts.hint;
|
|
552
|
+
if (opts?.column !== void 0) this._def.column = opts.column;
|
|
553
|
+
return toGuardDef(this);
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
function toGuardDef(b) {
|
|
557
|
+
const def = b instanceof GuardBuilder ? b._def : b;
|
|
558
|
+
if (def.event === void 0) {
|
|
559
|
+
throw new Error(`guard(${def.name}): hangi olayda bakaca\u011F\u0131 gerekir \u2014 .on("insert"|"update"|"delete") \xE7a\u011F\u0131r\u0131n.`);
|
|
560
|
+
}
|
|
561
|
+
if (def.when === void 0 && def.exists === void 0) {
|
|
562
|
+
throw new Error(`guard(${def.name}): bir ko\u015Ful gerekir \u2014 .when(...) ya da .exists(...) \xE7a\u011F\u0131r\u0131n. Ko\u015Fulsuz bir guard o olaydaki HER yazmay\u0131 reddeder.`);
|
|
563
|
+
}
|
|
564
|
+
if (def.message === void 0 || def.message.trim() === "") {
|
|
565
|
+
throw new Error(`guard(${def.name}): bo\u015F mesaj kabul edilmez \u2014 reddin mesaj\u0131 guard'\u0131n kullan\u0131c\u0131ya ula\u015Fan TEK \xE7\u0131kt\u0131s\u0131.`);
|
|
566
|
+
}
|
|
567
|
+
return {
|
|
568
|
+
name: def.name,
|
|
569
|
+
event: def.event,
|
|
570
|
+
...def.when !== void 0 ? {
|
|
571
|
+
when: def.when
|
|
572
|
+
} : {},
|
|
573
|
+
...def.exists !== void 0 ? {
|
|
574
|
+
exists: def.exists
|
|
575
|
+
} : {},
|
|
576
|
+
message: def.message,
|
|
577
|
+
...def.detail !== void 0 ? {
|
|
578
|
+
detail: def.detail
|
|
579
|
+
} : {},
|
|
580
|
+
...def.hint !== void 0 ? {
|
|
581
|
+
hint: def.hint
|
|
582
|
+
} : {},
|
|
583
|
+
...def.column !== void 0 ? {
|
|
584
|
+
column: def.column
|
|
585
|
+
} : {}
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
__name(toGuardDef, "toGuardDef");
|
|
589
|
+
|
|
314
590
|
// src/db/schema.ts
|
|
315
591
|
var IndexBuilder = class {
|
|
316
592
|
static {
|
|
@@ -325,6 +601,15 @@ var IndexBuilder = class {
|
|
|
325
601
|
name
|
|
326
602
|
};
|
|
327
603
|
}
|
|
604
|
+
/**
|
|
605
|
+
* `CREATE UNIQUE INDEX` (FR-007). `.where()` ile birlikte PARTIAL UNIQUE
|
|
606
|
+
* index verir (FR-007b) — "NULL'lar serbest, non-NULL'lar tekil" kalıbının
|
|
607
|
+
* tek bildirimsel yolu.
|
|
608
|
+
*/
|
|
609
|
+
unique() {
|
|
610
|
+
this._def.unique = true;
|
|
611
|
+
return this;
|
|
612
|
+
}
|
|
328
613
|
/** Index'in kolonları. SIRA KORUNUR — çok kolonlu bir index'in anlamı sırasıdır. */
|
|
329
614
|
on(...cols) {
|
|
330
615
|
this._def.columns = cols.map((c) => {
|
|
@@ -378,7 +663,7 @@ function toPolicyDef(p) {
|
|
|
378
663
|
return p instanceof PolicyBuilder ? p._def : p;
|
|
379
664
|
}
|
|
380
665
|
__name(toPolicyDef, "toPolicyDef");
|
|
381
|
-
var
|
|
666
|
+
var TABLE_META2 = /* @__PURE__ */ Symbol.for("palbase.table.meta");
|
|
382
667
|
function defineTable(name, input) {
|
|
383
668
|
if (name.trim() === "") {
|
|
384
669
|
throw new Error("defineTable(name, \u2026): name must not be empty");
|
|
@@ -411,9 +696,46 @@ function defineTable(name, input) {
|
|
|
411
696
|
if (input.primaryKey !== void 0) def.primaryKey = input.primaryKey;
|
|
412
697
|
if (input.unique !== void 0) def.unique = input.unique;
|
|
413
698
|
if (input.raw !== void 0 && input.raw.length > 0) def.raw = input.raw.slice();
|
|
414
|
-
|
|
699
|
+
const declaredChecks = typeof input.checks === "function" ? input.checks(exprCtx(Object.keys(input.columns), 0, name)) : input.checks?.slice() ?? [];
|
|
700
|
+
if (declaredChecks.length > 0) def.checks = declaredChecks;
|
|
415
701
|
const declaredIndexes = (input.indexes?.(exprCtx(Object.keys(input.columns), 0, name)) ?? []).map((i) => i instanceof IndexBuilder ? i._def : i);
|
|
416
702
|
if (declaredIndexes.length > 0) def.indexes = declaredIndexes;
|
|
703
|
+
const declaredFKs = (input.foreignKeys?.(exprCtx(Object.keys(input.columns), 0, name)) ?? []).map(toForeignKeyDef);
|
|
704
|
+
if (declaredFKs.length > 0) def.foreignKeys = declaredFKs;
|
|
705
|
+
const declaredFreezes = (input.freeze?.(exprCtx(Object.keys(input.columns), 0, name)) ?? []).map(toFreezeDef);
|
|
706
|
+
if (declaredFreezes.length > 0) def.freeze = declaredFreezes;
|
|
707
|
+
for (const fz of declaredFreezes) {
|
|
708
|
+
for (const c of fz.columns) {
|
|
709
|
+
if (!(c in input.columns)) {
|
|
710
|
+
throw new Error(`table "${name}": freeze("${fz.name}").columns("${c}") \u2014 no such column on this table. Declared columns: ${Object.keys(input.columns).join(", ")}`);
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
const declaredGuards = (input.guards?.(exprCtx(Object.keys(input.columns), 0, name)) ?? []).map(toGuardDef);
|
|
715
|
+
if (declaredGuards.length > 0) def.guards = declaredGuards;
|
|
716
|
+
for (const g of declaredGuards) {
|
|
717
|
+
if (g.column !== void 0 && !(g.column in input.columns)) {
|
|
718
|
+
throw new Error(`table "${name}": guard("${g.name}").refuse(\u2026, { column: "${g.column}" }) \u2014 no such column on this table. Declared columns: ${Object.keys(input.columns).join(", ")}`);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
if (input.backfills !== void 0 && input.backfills.length > 0) {
|
|
722
|
+
const seen = /* @__PURE__ */ new Set();
|
|
723
|
+
for (const b of input.backfills) {
|
|
724
|
+
if (seen.has(b.name)) {
|
|
725
|
+
throw new Error(`table ${name}: backfill ad\u0131 iki kez bildirildi: ${b.name} \u2014 kay\u0131t ADA g\xF6re tutuluyor, ikincisi hi\xE7 ko\u015Fmazd\u0131.`);
|
|
726
|
+
}
|
|
727
|
+
seen.add(b.name);
|
|
728
|
+
}
|
|
729
|
+
def.backfills = input.backfills.map((b) => ({
|
|
730
|
+
name: b.name,
|
|
731
|
+
sql: b.sql
|
|
732
|
+
}));
|
|
733
|
+
}
|
|
734
|
+
if (input.dropConstraints !== void 0 && input.dropConstraints.length > 0) {
|
|
735
|
+
def.dropConstraints = [
|
|
736
|
+
...input.dropConstraints
|
|
737
|
+
];
|
|
738
|
+
}
|
|
417
739
|
if (input.appendOnly === true) def.appendOnly = true;
|
|
418
740
|
if (input.ignored === true) def.ignored = true;
|
|
419
741
|
if (input.search !== void 0) {
|
|
@@ -467,7 +789,7 @@ function defineTable(name, input) {
|
|
|
467
789
|
const handle = {
|
|
468
790
|
...owned
|
|
469
791
|
};
|
|
470
|
-
Object.defineProperty(handle,
|
|
792
|
+
Object.defineProperty(handle, TABLE_META2, {
|
|
471
793
|
value: def,
|
|
472
794
|
enumerable: false
|
|
473
795
|
});
|
|
@@ -476,6 +798,9 @@ function defineTable(name, input) {
|
|
|
476
798
|
__name(defineTable, "defineTable");
|
|
477
799
|
var declaringSchemaOf = /* @__PURE__ */ new WeakMap();
|
|
478
800
|
function resolveReferences(tables, schemaName) {
|
|
801
|
+
for (const table of Object.values(tables)) {
|
|
802
|
+
qualifyRefTargets(table, `table "${table.name}"`);
|
|
803
|
+
}
|
|
479
804
|
for (const table of Object.values(tables)) {
|
|
480
805
|
for (const [colName, builder] of Object.entries(table.columns)) {
|
|
481
806
|
const def = builder._def;
|
|
@@ -520,7 +845,7 @@ function defineSchema(name, input) {
|
|
|
520
845
|
}
|
|
521
846
|
const tables = {};
|
|
522
847
|
for (const handle of input.tables) {
|
|
523
|
-
const table = handle[
|
|
848
|
+
const table = handle[TABLE_META2];
|
|
524
849
|
if (tables[table.name] !== void 0) {
|
|
525
850
|
throw new Error(`defineSchema("${name}"): two tables declare the name "${table.name}" \u2014 table names must be unique within a schema`);
|
|
526
851
|
}
|
|
@@ -564,6 +889,48 @@ function defineSchema(name, input) {
|
|
|
564
889
|
};
|
|
565
890
|
}
|
|
566
891
|
__name(defineSchema, "defineSchema");
|
|
892
|
+
function qualifyRefTargets(table, where) {
|
|
893
|
+
const qualify = /* @__PURE__ */ __name((holder, what) => {
|
|
894
|
+
const target = holder[REF_TARGET];
|
|
895
|
+
if (target === void 0) return;
|
|
896
|
+
const targetSchema = declaringSchemaOf.get(target);
|
|
897
|
+
if (targetSchema === void 0) {
|
|
898
|
+
throw new Error(`${where}: ${what} points at table "${target.name}", which no defineSchema(...) has claimed yet \u2014 a cross-table reference cannot be written without its target's schema. Declare that table's schema first (one file per schema: db/public.ts, db/billing.ts \u2026, imported by this one).`);
|
|
899
|
+
}
|
|
900
|
+
const qualified = qualifiedTableKey(targetSchema, target.name);
|
|
901
|
+
if (holder.refTable !== void 0) holder.refTable = qualified;
|
|
902
|
+
if (holder.table !== void 0) holder.table = qualified;
|
|
903
|
+
}, "qualify");
|
|
904
|
+
for (const fk of table.foreignKeys ?? []) qualify(fk, `foreignKey("${fk.name}")`);
|
|
905
|
+
for (const fz of table.freeze ?? []) qualify(fz, `freeze("${fz.name}")`);
|
|
906
|
+
for (const g of table.guards ?? []) {
|
|
907
|
+
if (g.exists !== void 0) {
|
|
908
|
+
qualifyExistsNodes(g.exists, `guard("${g.name}").exists(...)`, where);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
__name(qualifyRefTargets, "qualifyRefTargets");
|
|
913
|
+
function qualifyExistsNodes(node, what, where) {
|
|
914
|
+
if (node === null || typeof node !== "object") return;
|
|
915
|
+
if (node.kind === "exists") {
|
|
916
|
+
const target = node[REF_TARGET];
|
|
917
|
+
if (target !== void 0) {
|
|
918
|
+
const targetSchema = declaringSchemaOf.get(target);
|
|
919
|
+
if (targetSchema === void 0) {
|
|
920
|
+
throw new Error(`${where}: ${what} points at table "${target.name}", which no defineSchema(...) has claimed yet \u2014 a guard body is parsed at RUN TIME under a pinned search_path, so an unqualified name never resolves.`);
|
|
921
|
+
}
|
|
922
|
+
node.table = qualifiedTableKey(targetSchema, target.name);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
for (const v of Object.values(node)) {
|
|
926
|
+
if (Array.isArray(v)) {
|
|
927
|
+
for (const e of v) qualifyExistsNodes(e, what, where);
|
|
928
|
+
} else if (v !== null && typeof v === "object") {
|
|
929
|
+
qualifyExistsNodes(v, what, where);
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
__name(qualifyExistsNodes, "qualifyExistsNodes");
|
|
567
934
|
|
|
568
935
|
// src/db/extensions.ts
|
|
569
936
|
var PALBASE_EXTENSIONS = [
|
|
@@ -927,13 +1294,10 @@ function installationRef(opts) {
|
|
|
927
1294
|
__name(installationRef, "installationRef");
|
|
928
1295
|
|
|
929
1296
|
// src/db/raw.ts
|
|
930
|
-
function raw(name, up
|
|
1297
|
+
function raw(name, up) {
|
|
931
1298
|
return {
|
|
932
1299
|
name,
|
|
933
|
-
up
|
|
934
|
-
...opts?.down != null ? {
|
|
935
|
-
down: opts.down
|
|
936
|
-
} : {}
|
|
1300
|
+
up
|
|
937
1301
|
};
|
|
938
1302
|
}
|
|
939
1303
|
__name(raw, "raw");
|