@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
|
@@ -824,6 +824,33 @@ declare class PolicyExprRef {
|
|
|
824
824
|
or(...others: PolicyExprRef[]): PolicyExprRef;
|
|
825
825
|
not(): PolicyExprRef;
|
|
826
826
|
}
|
|
827
|
+
/**
|
|
828
|
+
* Bir tablonun `existsIn` için ANNOTATION hâli — iki bildirim birbirini
|
|
829
|
+
* başlatırken çıkarım döngüsünü kıran şey.
|
|
830
|
+
*
|
|
831
|
+
* ÖLÇÜLDÜ: `memberships.household_id` `households.id`'ye referans verirken
|
|
832
|
+
* `households`'ın politikası `existsIn(memberships, …)` yazarsa TypeScript
|
|
833
|
+
* ikisini de TS7022 ile `any`'ye düşürüyor. Kesinti sadece hata mesajı değil:
|
|
834
|
+
* `m.col(…)` de `any` olduğu için politika gövdesindeki YANLIŞ YAZILMIŞ bir
|
|
835
|
+
* kolon adı sessizce derleniyor — RLS yolunda fail-open. Aynı ölçümde
|
|
836
|
+
* `existsIn`'in jeneriğini kaldırmak (tamamen jeneriksiz imza dahil) döngüyü
|
|
837
|
+
* KIRMADI: döngü çıkarımdan değil, iki `const`'un birbirini başlatmasından
|
|
838
|
+
* geliyor ve TypeScript'te tek çaresi bir tip annotation'ı.
|
|
839
|
+
*
|
|
840
|
+
* Bu, `references((): AnyColumn => y.id)`'nin tablo düzeyindeki karşılığı — ama
|
|
841
|
+
* `AnyColumn`'dan farklı olarak KOLON ADLARINI SİLMEZ:
|
|
842
|
+
*
|
|
843
|
+
* ```ts
|
|
844
|
+
* const memberships: TableRef<"id" | "household_id" | "user_id", "memberships"> =
|
|
845
|
+
* defineTable("memberships", { columns: { … } });
|
|
846
|
+
* ```
|
|
847
|
+
*
|
|
848
|
+
* Adlar `Cols`'ta durduğu için `m.col("user")` hâlâ DERLENMEZ, ve `N` verildiği
|
|
849
|
+
* için tablo `defineSchema` içinde anahtarını kaybetmez. Kolon adlarını silen
|
|
850
|
+
* gevşek bir `AnyTable` KASITLI OLARAK YOK: onu yazan kişi döngüyü susturur ve
|
|
851
|
+
* politikasının kolon denetimini kapattığını fark etmez.
|
|
852
|
+
*/
|
|
853
|
+
type TableRef<Cols extends string, N extends string = string> = TableHandle<Record<Cols, ColumnMap[string]>, N>;
|
|
827
854
|
/** `.eq()` gibi metotların sağ tarafı: başka bir ifade ya da düz bir değer. */
|
|
828
855
|
type PolicyOperand = PolicyExprRef | string | number | boolean | null;
|
|
829
856
|
/**
|
|
@@ -855,6 +882,11 @@ interface PolicyExprCtx<Cols extends string = string> {
|
|
|
855
882
|
* tipli ve SQL'de farklı nitelenirler. Karışsalardı `team_id = team_id`
|
|
856
883
|
* üretilir ve politika hiçbir şeyi süzmezdi.
|
|
857
884
|
*
|
|
885
|
+
* ÇIKARIM DÖNGÜSÜ: `table` iki bildirim birbirini başlatıyorsa (üyelik tablosu
|
|
886
|
+
* bu tabloya `references` veriyor, bu tablo da ona `existsIn` atıyor) o
|
|
887
|
+
* bildirime {@link TableRef} annotation'ı gerekir — yoksa TypeScript ikisini
|
|
888
|
+
* de TS7022 ile `any`'ye düşürür ve `m.col(…)` sessizce her adı kabul eder.
|
|
889
|
+
*
|
|
858
890
|
* ÖZYİNELEME TUZAĞI: üyelik tablosunun KENDİ politikası `existsIn`
|
|
859
891
|
* KULLANMAZ — `user_id = auth.uid()` yazar. İki tablo birbirini
|
|
860
892
|
* sorgularsa Postgres sorgu anında
|
|
@@ -1004,6 +1036,44 @@ declare class PolicyBuilder {
|
|
|
1004
1036
|
* `(table, name)`, so names must be unique per table.
|
|
1005
1037
|
*/
|
|
1006
1038
|
declare function policy(name: string): PolicyBuilder;
|
|
1039
|
+
/**
|
|
1040
|
+
* Adlandırılmış bir CHECK kısıtı — telin bugünkü şekli, HARFİYEN.
|
|
1041
|
+
*
|
|
1042
|
+
* `expr` STRING kalıyor: `TableJSON.checks` bugün de `{ name, expr }[]` ve Go
|
|
1043
|
+
* tarafındaki `CheckJSON.Expr` bir string. Tipli `check()` ifadeyi bildirim
|
|
1044
|
+
* anında SQL'e derleyip aynı yere koyuyor, yani string dalıyla tipli dal telde
|
|
1045
|
+
* AYNI şeye iniyor: `NormalizeDeclaredChecks` ikisini de canlı Postgres'e
|
|
1046
|
+
* sorarak kanonikleştiriyor (böylece değişmemiş bir CHECK churn olarak
|
|
1047
|
+
* yeniden diff'lenmiyor) ve `schema-json.ts` yeni bir alan taşımıyor.
|
|
1048
|
+
*/
|
|
1049
|
+
interface CheckDef {
|
|
1050
|
+
name: string;
|
|
1051
|
+
/** Derlenmiş SQL. Tipli dalda `check()` üretir, string dalda yazar verir. */
|
|
1052
|
+
expr: string;
|
|
1053
|
+
}
|
|
1054
|
+
/**
|
|
1055
|
+
* `check("<ad>", <ifade>)` — TİPLİ CHECK kısıtı (FR-009).
|
|
1056
|
+
*
|
|
1057
|
+
* İfade POLİTİKA ifade cebirinin ta kendisiyle yazılıyor; bu DSL'de iki ayrı
|
|
1058
|
+
* ifade dili olmaması kurulu ilke. Kolon adları `checks` callback'inin verdiği
|
|
1059
|
+
* bağlamdan geliyor, yani yanlış yazılmış bir ad DERLENMİYOR — bugün string
|
|
1060
|
+
* biçiminde o hata ancak `ALTER TABLE ... ADD CONSTRAINT` anında Postgres'ten
|
|
1061
|
+
* geliyor.
|
|
1062
|
+
*
|
|
1063
|
+
* ```ts
|
|
1064
|
+
* defineTable("payments", {
|
|
1065
|
+
* columns: { amount: integer().notNull(), currency: text().notNull() },
|
|
1066
|
+
* checks: (c) => [
|
|
1067
|
+
* check("payments_amount_pos", c.col("amount").gt(0)),
|
|
1068
|
+
* check("payments_currency_set", c.col("currency").isNull(true)),
|
|
1069
|
+
* ],
|
|
1070
|
+
* })
|
|
1071
|
+
* ```
|
|
1072
|
+
*
|
|
1073
|
+
* @param name Kısıtın adı. CHECK'ler ADA göre uzlaştırılıyor (gövde farkı
|
|
1074
|
+
* DROP + ADD demek), o yüzden ad tablo başına tekil olmalı.
|
|
1075
|
+
*/
|
|
1076
|
+
declare function check(name: string, expr: PolicyExprRef): CheckDef;
|
|
1007
1077
|
/**
|
|
1008
1078
|
* `can` alanının YANIT şeması (FR-004, D-14).
|
|
1009
1079
|
*
|
|
@@ -1057,22 +1127,336 @@ declare const EXTENSION_DEPENDENCIES: Partial<Record<PalbaseExtension, PalbaseEx
|
|
|
1057
1127
|
/** Runtime guard: is `name` a supported Palbase extension? */
|
|
1058
1128
|
declare function isPalbaseExtension(name: string): name is PalbaseExtension;
|
|
1059
1129
|
|
|
1130
|
+
/** `ON UPDATE` / `ON DELETE` eylemleri — Postgres'in kabul ettiği kapalı küme. */
|
|
1131
|
+
type FkAction = "cascade" | "restrict" | "set null" | "set default" | "no action";
|
|
1132
|
+
/** `MATCH` türü. `partial` Postgres'te HENÜZ uygulanmadı, o yüzden yok. */
|
|
1133
|
+
type FkMatch = "simple" | "full";
|
|
1134
|
+
/** Bir tablo düzeyi FOREIGN KEY bildirimi — C-1/C-2 (FR-001). */
|
|
1135
|
+
interface ForeignKeyDef {
|
|
1136
|
+
name: string;
|
|
1137
|
+
columns: string[];
|
|
1138
|
+
refTable: string;
|
|
1139
|
+
refColumns: string[];
|
|
1140
|
+
onUpdate?: FkAction;
|
|
1141
|
+
onDelete?: FkAction;
|
|
1142
|
+
match?: FkMatch;
|
|
1143
|
+
}
|
|
1144
|
+
/**
|
|
1145
|
+
* `foreignKey("<ad>")` — tablo düzeyinde, ÇOK SÜTUNLU FOREIGN KEY (C-1, FR-001).
|
|
1146
|
+
*
|
|
1147
|
+
* ```ts
|
|
1148
|
+
* foreignKeys: (c) => [
|
|
1149
|
+
* foreignKey("settlement_entry_household")
|
|
1150
|
+
* .on(c.col("household_id"), c.col("entry_id"))
|
|
1151
|
+
* .references(entries, "household_id", "id")
|
|
1152
|
+
* .onDelete("cascade"),
|
|
1153
|
+
* ]
|
|
1154
|
+
* ```
|
|
1155
|
+
*
|
|
1156
|
+
* NEDEN KOLON ÜZERİNDEKİ `.references()` YETMİYOR. O tek sütunlu ve tek
|
|
1157
|
+
* hedeflidir. Çok kiracılı bütünlüğün istediği şey
|
|
1158
|
+
* `FOREIGN KEY (household_id, entry_id) REFERENCES entries (household_id, id)`:
|
|
1159
|
+
* çocuğun ebeveyni yalnız var olmakla kalmaz, AYNI KİRACIYA ait olmak
|
|
1160
|
+
* zorundadır. Kolon başına model bunu ifade edemez.
|
|
1161
|
+
*
|
|
1162
|
+
* İki yol BİRBİRİNİ DÜŞÜRMEZ: bu bildirim kendi adıyla izlenir, kolon
|
|
1163
|
+
* üzerindekiler `<tablo>_<kolon>_fkey` ile. Aynı tabloda ikisi birden olabilir.
|
|
1164
|
+
*/
|
|
1165
|
+
declare class ForeignKeyBuilder {
|
|
1166
|
+
readonly _def: ForeignKeyDef;
|
|
1167
|
+
constructor(name: string);
|
|
1168
|
+
/** Yerel sütunlar. SIRA KORUNUR — hedef sütunlarla birebir eşleşir. */
|
|
1169
|
+
on(...cols: PolicyExprRef[]): this;
|
|
1170
|
+
/**
|
|
1171
|
+
* Hedef tablo ve sütunları. Sütun sayısı `.on()`'unkiyle eşit OLMALI ve bu
|
|
1172
|
+
* burada, bildirim yazılırken kontrol edilir — bozuk bir FK wire'a hiç çıkmaz.
|
|
1173
|
+
*/
|
|
1174
|
+
references<C extends ColumnMap, N extends string>(table: TableHandle<C, N>, ...cols: (Extract<keyof C, string>)[]): this;
|
|
1175
|
+
onUpdate(action: FkAction): this;
|
|
1176
|
+
onDelete(action: FkAction): this;
|
|
1177
|
+
/**
|
|
1178
|
+
* `MATCH FULL`: referans veren sütunların HEPSİ NULL olmadıkça kısıt
|
|
1179
|
+
* değerlendirilir. Varsayılan `MATCH SIMPLE`'da tek bir NULL kısıtı atlatır —
|
|
1180
|
+
* `freeze` bunu bilerek kullanır, sıradan bir FK'da genelde istenmez.
|
|
1181
|
+
*/
|
|
1182
|
+
match(m: FkMatch): this;
|
|
1183
|
+
}
|
|
1184
|
+
declare function foreignKey(name: string): ForeignKeyBuilder;
|
|
1185
|
+
/**
|
|
1186
|
+
* Bir KOŞULLU ("donan") FOREIGN KEY bildirimi — C-5 (FR-012).
|
|
1187
|
+
*
|
|
1188
|
+
* `columns` çocuğun donan sütunları, `refColumns` ebeveynin onlara karşılık
|
|
1189
|
+
* gelen anahtar sütunları; ikisi SIRAYLA eşleşir. `when` doğruyken FK
|
|
1190
|
+
* değerlendirilir, yanlışken hiç değerlendirilmez.
|
|
1191
|
+
*/
|
|
1192
|
+
interface FreezeDef {
|
|
1193
|
+
name: string;
|
|
1194
|
+
when: PolicyExpr;
|
|
1195
|
+
columns: string[];
|
|
1196
|
+
refTable: string;
|
|
1197
|
+
refColumns: string[];
|
|
1198
|
+
}
|
|
1199
|
+
/** Builder'ın YAZILMAKTA olan hâli: `when` henüz atanmamış olabilir. */
|
|
1200
|
+
type FreezeDraft = Omit<FreezeDef, "when"> & {
|
|
1201
|
+
when?: PolicyExpr;
|
|
1202
|
+
};
|
|
1203
|
+
/**
|
|
1204
|
+
* `freeze("<ad>")` — KOŞULLU FK: bir koşul sağlandığı sürece bir demeti dondurur
|
|
1205
|
+
* (C-5, FR-012).
|
|
1206
|
+
*
|
|
1207
|
+
* ```ts
|
|
1208
|
+
* freeze: (c) => [
|
|
1209
|
+
* freeze("pay_settled_inv")
|
|
1210
|
+
* .when(c.col("status").eq("settled"))
|
|
1211
|
+
* .columns("inv_id", "amount", "currency")
|
|
1212
|
+
* .references(invoices, "id", "amount", "currency"),
|
|
1213
|
+
* ]
|
|
1214
|
+
* ```
|
|
1215
|
+
*
|
|
1216
|
+
* NEDEN TRIGGER DEĞİL. Üretilen şey bir CONSTRAINT: ebeveyndeki demet üzerinde
|
|
1217
|
+
* bir UNIQUE, çocukta `when` sağlanmıyorken NULL veren `STORED` generated
|
|
1218
|
+
* sütunlar, ve bunlardan `ON UPDATE RESTRICT ON DELETE RESTRICT` bir FK.
|
|
1219
|
+
* `MATCH SIMPLE`'ın NULL kaçışı — "referans veren sütunlardan biri NULL ise satır
|
|
1220
|
+
* kısıtı sağlamak zorunda değildir" — "koşullu FK"yı `WHERE` olmadan veriyor.
|
|
1221
|
+
*
|
|
1222
|
+
* Trigger'a göre üç bedava üstünlük (canlı pg'de ölçüldü, spec Research
|
|
1223
|
+
* Appendix): TERS YÖN de kapanır (uyuşmayan bir çocuk `settled` yapılamaz —
|
|
1224
|
+
* trigger yalnız ebeveyni korurdu); koşul kalkınca donma KENDİLİĞİNDEN çözülür;
|
|
1225
|
+
* `pg_dump`/restore'da FK gibi davranır.
|
|
1226
|
+
*
|
|
1227
|
+
* Donan sütunlar `NOT NULL` OLMALI: nullable bir sütun `MATCH SIMPLE`'ın aynı
|
|
1228
|
+
* kaçışını koşuldan BAĞIMSIZ olarak açar ve donma sessizce hiç kurulmaz. Push o
|
|
1229
|
+
* bildirimi reddeder (FR-014).
|
|
1230
|
+
*/
|
|
1231
|
+
declare class FreezeBuilder {
|
|
1232
|
+
readonly _def: FreezeDraft;
|
|
1233
|
+
constructor(name: string);
|
|
1234
|
+
/**
|
|
1235
|
+
* DONMA KOŞULU — çocuk satırının kendi kolonları üzerinde bir yüklem.
|
|
1236
|
+
*
|
|
1237
|
+
* Generated sütunlara `CASE WHEN <koşul> THEN <sütun> END` olarak iner; yani
|
|
1238
|
+
* koşul yanlışken sütunlar NULL olur ve FK o satır için hiç değerlendirilmez.
|
|
1239
|
+
*/
|
|
1240
|
+
when(pred: PolicyExprRef): this;
|
|
1241
|
+
/** Çocuğun DONAN sütunları. SIRA KORUNUR — hedef sütunlarla birebir eşleşir. */
|
|
1242
|
+
columns(...cols: string[]): this;
|
|
1243
|
+
/**
|
|
1244
|
+
* Ebeveyn tablo ve donan demetin ORADAKİ karşılığı. Zincirin SON halkası:
|
|
1245
|
+
* bildirim burada tamamlanır ve tutarlılığı burada doğrulanır, yani
|
|
1246
|
+
* `.references()`'ı unutmuş bir freeze `FreezeDef` üretmediği için tabloya
|
|
1247
|
+
* hiç giremez.
|
|
1248
|
+
*/
|
|
1249
|
+
references<C extends ColumnMap, N extends string>(table: TableHandle<C, N>, ...cols: (Extract<keyof C, string>)[]): FreezeDef;
|
|
1250
|
+
}
|
|
1251
|
+
declare function freeze(name: string): FreezeBuilder;
|
|
1252
|
+
|
|
1253
|
+
/**
|
|
1254
|
+
* guard.ts — DAR REDDEDİCİ YÜZEY (C-3, FR-015…FR-021).
|
|
1255
|
+
*
|
|
1256
|
+
* Bildirimsel kısıtların yetişemediği beş madde kaldı: write-once alanlar,
|
|
1257
|
+
* durum makinesi geçişleri, sabit olmayan yüklemle çapraz satır kontrolü, işlem
|
|
1258
|
+
* düzeyinde toplam, ve alan diline ait teşhis. RLS yolu bunlara KAPALI: `OLD` ve
|
|
1259
|
+
* `NEW` bir politika ifadesinde ad olarak YOKTUR (ölçüldü — red, ad çözümleme
|
|
1260
|
+
* düzeyinde `CREATE POLICY` anında gelir: `missing FROM-clause entry for table
|
|
1261
|
+
* "new"`), ve `USING`/`WITH CHECK` iki ayrı satıra karşı ayrı ayrı
|
|
1262
|
+
* değerlendirilir; tek ifadede iki satırı yan yana getiren bir kapsam yok.
|
|
1263
|
+
*
|
|
1264
|
+
* YAZAR ÜÇ ŞEY YAZAR: hangi olay · hangi koşul · ne diyerek reddet. Kalan sekiz
|
|
1265
|
+
* knob'un güvenli varsayılanı var ve bu yüzeyde HİÇ görünmüyor: `BEFORE` ·
|
|
1266
|
+
* `FOR EACH ROW` (Postgres'in varsayılanı `STATEMENT` ve bir guard için yanlış) ·
|
|
1267
|
+
* `UPDATE OF` listesi `WHEN`'den türetilir · `SET search_path = pg_catalog,
|
|
1268
|
+
* pg_temp` HER ZAMAN · `SECURITY INVOKER` (asla `DEFINER`) · `NOT DEFERRABLE` ·
|
|
1269
|
+
* `REFERENCING`/`FROM` üretilmez · `DROP IF EXISTS` + `CREATE`. Bir yeteneği
|
|
1270
|
+
* yüzeye çıkarmak onu politika hâline getirir; bunlar politika DEĞİL, güvenli
|
|
1271
|
+
* varsayılan (FR-017).
|
|
1272
|
+
*
|
|
1273
|
+
* Global bir kaçış kapısı KASITLI OLARAK YOK: django-pgtrigger'ın
|
|
1274
|
+
* `SET pgtrigger.ignore`'u herhangi bir oturumun guard'ı atlamasına izin veriyor
|
|
1275
|
+
* ve bir BaaS'ta bu kabul edilemez.
|
|
1276
|
+
*/
|
|
1277
|
+
/** Guard'ın tetiklendiği yazma fiili. */
|
|
1278
|
+
type GuardEvent = "insert" | "update" | "delete";
|
|
1279
|
+
/**
|
|
1280
|
+
* Bir guard bildirimi — C-3/C-4 (FR-015).
|
|
1281
|
+
*
|
|
1282
|
+
* `when` satırın KENDİ kolonları üzerinde bir yüklem (trigger'ın `WHEN` yan
|
|
1283
|
+
* tümcesine iner), `exists` ise çapraz satır yüklemi (gövdedeki `EXISTS`
|
|
1284
|
+
* bloğuna). İkisi ayrı alan çünkü Postgres bir trigger'ın `WHEN` yan tümcesinde
|
|
1285
|
+
* ALT SORGUYA İZİN VERMİYOR (`ERROR: cannot use subquery in trigger WHEN
|
|
1286
|
+
* condition` — ölçüldü); ayrımı wire'da yapmak, emitter'ın yükleme bakıp
|
|
1287
|
+
* tahmin etmesinden daha dürüst (FR-019).
|
|
1288
|
+
*/
|
|
1289
|
+
interface GuardDef {
|
|
1290
|
+
name: string;
|
|
1291
|
+
event: GuardEvent;
|
|
1292
|
+
when?: PolicyExpr;
|
|
1293
|
+
exists?: PolicyExpr;
|
|
1294
|
+
message: string;
|
|
1295
|
+
detail?: string;
|
|
1296
|
+
hint?: string;
|
|
1297
|
+
column?: string;
|
|
1298
|
+
}
|
|
1299
|
+
/** Builder'ın YAZILMAKTA olan hâli: olay ve mesaj henüz atanmamış olabilir. */
|
|
1300
|
+
type GuardDraft = Omit<GuardDef, "event" | "message"> & {
|
|
1301
|
+
event?: GuardEvent;
|
|
1302
|
+
message?: string;
|
|
1303
|
+
};
|
|
1304
|
+
/**
|
|
1305
|
+
* `guard("<ad>")` — bir yazmayı ALAN DİLİYLE reddeden trigger (C-3, FR-015).
|
|
1306
|
+
*
|
|
1307
|
+
* ```ts
|
|
1308
|
+
* guards: (g) => [
|
|
1309
|
+
* guard("documents_frozen_body")
|
|
1310
|
+
* .on("update")
|
|
1311
|
+
* .when(g.col("status").eq("archived"))
|
|
1312
|
+
* .refuse("Arşivlenmiş belgenin gövdesi değiştirilemez", { column: "body" }),
|
|
1313
|
+
* ]
|
|
1314
|
+
* ```
|
|
1315
|
+
*
|
|
1316
|
+
* ADI ZORUNLU (FR-016). Postgres aynı olaya bağlı trigger'ları ADA GÖRE
|
|
1317
|
+
* alfabetik sırayla koşar ve başka bir sıra tutamacı YOKTUR: adsız üretilmiş bir
|
|
1318
|
+
* guard, sırası kendi kontrolünde olmayan bir guard demektir.
|
|
1319
|
+
*
|
|
1320
|
+
* Teşhis: red `PB001` SQLSTATE'i ile gelir — `23514` KULLANILMAZ, o gerçek bir
|
|
1321
|
+
* CHECK ihlalinin kodu ve istemci ikisini ayırt edemezdi. Guard'ın adı
|
|
1322
|
+
* `CONSTRAINT` alanına gider, yani istemci mesajı PARSE ETMEDEN hangi guard'ın
|
|
1323
|
+
* reddettiğini okur (FR-021).
|
|
1324
|
+
*/
|
|
1325
|
+
declare class GuardBuilder {
|
|
1326
|
+
readonly _def: GuardDraft;
|
|
1327
|
+
constructor(name: string);
|
|
1328
|
+
/** Hangi yazma fiilinde bakılacak. */
|
|
1329
|
+
on(event: GuardEvent): this;
|
|
1330
|
+
/**
|
|
1331
|
+
* Satırın KENDİ kolonları üzerinde koşul — trigger'ın `WHEN` yan tümcesi.
|
|
1332
|
+
*
|
|
1333
|
+
* Emitter karşılaştırmaları `IS DISTINCT FROM` ile yazar (`<>` NULL'da yanlış
|
|
1334
|
+
* cevap verir) ve geçen sütunlardan bir `UPDATE OF (…)` listesi türetir
|
|
1335
|
+
* (FR-018).
|
|
1336
|
+
*/
|
|
1337
|
+
when(pred: PolicyExprRef): this;
|
|
1338
|
+
/**
|
|
1339
|
+
* ÇAPRAZ SATIR koşulu — gövdedeki `EXISTS` bloğuna iner, `WHEN`'e DEĞİL:
|
|
1340
|
+
* Postgres trigger `WHEN`'inde alt sorgu kabul etmiyor (FR-019).
|
|
1341
|
+
*
|
|
1342
|
+
* Yüklem içinde takma adsız kalan kolon guard'ın KENDİ satırıdır (`NEW`/`OLD`);
|
|
1343
|
+
* `r.col(...)` hedef tablonun kolonlarını verir ve ayrı nitelenir. Bu yüzden
|
|
1344
|
+
* düğümün `outer` alanı BOŞ kalır: bir guard'ın "dış satır"ı bir tablo takma
|
|
1345
|
+
* adı değildir.
|
|
1346
|
+
*/
|
|
1347
|
+
exists<C extends ColumnMap, N extends string>(table: TableHandle<C, N>, predicate: (row: PolicyExprCtx<Extract<keyof C, string>>) => PolicyExprRef): this;
|
|
1348
|
+
/**
|
|
1349
|
+
* REDDİN KENDİSİ ve zincirin son halkası: mesaj olmadan bir guard tamamlanmaz.
|
|
1350
|
+
*
|
|
1351
|
+
* `detail`/`hint` Postgres'in aynı adlı alanlarına, `column` ise `COLUMN`
|
|
1352
|
+
* alanına gider — istemci hangi alanın reddedildiğini mesajı parse etmeden
|
|
1353
|
+
* okur.
|
|
1354
|
+
*/
|
|
1355
|
+
refuse(message: string, opts?: {
|
|
1356
|
+
detail?: string;
|
|
1357
|
+
hint?: string;
|
|
1358
|
+
column?: string;
|
|
1359
|
+
}): GuardDef;
|
|
1360
|
+
}
|
|
1361
|
+
declare function guard(name: string): GuardBuilder;
|
|
1362
|
+
|
|
1363
|
+
/**
|
|
1364
|
+
* backfill.ts — DDL'DEN AYRI, İZLENEN, BİR KEZ KOŞAN fiil (C-6, FR-033/FR-034).
|
|
1365
|
+
*
|
|
1366
|
+
* Bir sütun eklemek bildirimseldir; o sütunu DOLDURMAK değildir. Doldurma
|
|
1367
|
+
* bugüne kadar `raw()` içinde yaşıyordu ve `raw()` her deploy'da yeniden
|
|
1368
|
+
* koşulan bir DDL bloğu — yani veri düzeltmesi ya elle bir kez çalıştırılıyor
|
|
1369
|
+
* (kayıt yok, tekrarı belirsiz) ya da idempotent yazılmak zorunda kalıyordu.
|
|
1370
|
+
*
|
|
1371
|
+
* `backfills:` o işi kendi aşamasına alır: DDL'den SONRA, kendi işleminde ve
|
|
1372
|
+
* ADI BAŞINA BİR KEZ. Kayıt `public.palbase_backfills` tablosunda tutulur, yani
|
|
1373
|
+
* "koştu mu" sorusunun cevabı veritabanının kendisinde durur.
|
|
1374
|
+
*/
|
|
1375
|
+
/** Bir backfill bildirimi — C-6 (FR-033). */
|
|
1376
|
+
interface BackfillDef {
|
|
1377
|
+
name: string;
|
|
1378
|
+
sql: string;
|
|
1379
|
+
}
|
|
1380
|
+
/**
|
|
1381
|
+
* `backfill("<ad>", "<sql>")` — bir kez koşacak veri düzeltmesi.
|
|
1382
|
+
*
|
|
1383
|
+
* ```ts
|
|
1384
|
+
* backfills: [
|
|
1385
|
+
* backfill("ledger_currency_try", "UPDATE ledger SET currency = 'TRY' WHERE currency IS NULL"),
|
|
1386
|
+
* ]
|
|
1387
|
+
* ```
|
|
1388
|
+
*
|
|
1389
|
+
* AD, KAYDIN TA KENDİSİ. "Bu koştu mu?" sorusu ada göre cevaplanıyor, gövdeye
|
|
1390
|
+
* göre değil: adı sabit tutup SQL'i değiştirmek İKİNCİ bir koşu ÜRETMEZ. Bir
|
|
1391
|
+
* düzeltmeyi düzeltmek istiyorsan yeni bir ad verirsin — aynı adın altında
|
|
1392
|
+
* değişen bir gövde, canlıda hangi sürümün koştuğunu belirsiz bırakırdı.
|
|
1393
|
+
*
|
|
1394
|
+
* Bu yüzden BOŞ SQL de reddediliyor: boş bir gövde adı kayda geçirir ve o adı
|
|
1395
|
+
* KALICI olarak yakar — sonradan yazılan gerçek SQL "zaten koştu" diye hiç
|
|
1396
|
+
* çalışmaz, hiçbir yerde hata da vermez.
|
|
1397
|
+
*
|
|
1398
|
+
* SQL verbatim emit edilir (`raw()` ve `policy().using("…")` ile aynı güven
|
|
1399
|
+
* duruşu) ve `raw()` ile AYNI ayrıcalıklı DDL bağlantısında koşar — yalnızca
|
|
1400
|
+
* KENDİ AŞAMASINDA, yani DDL'den ayrı bir `Exec`'te. Ayrım budur ve tek başına
|
|
1401
|
+
* bir güvenlik iddiası DEĞİLDİR.
|
|
1402
|
+
*
|
|
1403
|
+
* Bu yorum daha önce "ayrıcalıklı DDL bağlantısında değil" diyordu ve YANLIŞTI.
|
|
1404
|
+
* Yanlış olduğu ölçüldü, ve niçin kayda geçtiği önemli: tam olarak bir
|
|
1405
|
+
* inceleyicinin "backfill güvenli" diye geçmesine sebep olacak cümleydi.
|
|
1406
|
+
*
|
|
1407
|
+
* Bu yüzden gövde `raw()` ile AYNI AST yetki kapısından geçiyor: rol yaratan,
|
|
1408
|
+
* sahiplik devreden, yetki dağıtan ya da `search_path` kaydıran bir ifade
|
|
1409
|
+
* taşıyan bir backfill push'u reddeder. Veri düzeltmesi veri düzeltmesidir.
|
|
1410
|
+
*/
|
|
1411
|
+
declare function backfill(name: string, sql: string): BackfillDef;
|
|
1412
|
+
|
|
1060
1413
|
/**
|
|
1061
1414
|
* A named raw-SQL DDL object declared in a schema file (`db/public.ts`,
|
|
1062
|
-
* `db/billing.ts`, …) for
|
|
1063
|
-
*
|
|
1415
|
+
* `db/billing.ts`, …) for what the typed DSL cannot express: an index method
|
|
1416
|
+
* other than btree (`gin`, `gist`, `brin`, `hash`), an opclass, `CONCURRENTLY`,
|
|
1417
|
+
* `EXCLUDE` constraints, views, and PL/pgSQL functions.
|
|
1418
|
+
*
|
|
1419
|
+
* REACH FOR THE TYPED FIELD FIRST. Most of what this list used to name is
|
|
1420
|
+
* declarative today and should not come through here:
|
|
1421
|
+
* - a CHECK constraint → `checks: [{ name, expr }]`, or the typed
|
|
1422
|
+
* `checks: (c) => [check(name, c.col("n").gt(0))]`
|
|
1423
|
+
* - a partial index → `index(n).on(…).where(…)`
|
|
1424
|
+
* - an expression index → `index(n).onExpression("lower(email)")`
|
|
1425
|
+
* - a covering index → `index(n).on(…).include([…])`
|
|
1426
|
+
* - a UNIQUE or PARTIAL UNIQUE index → `index(n).unique().where(…)`
|
|
1427
|
+
* - a composite FOREIGN KEY → `foreignKeys: (c) => [foreignKey(n).on(…).references(…)]`
|
|
1428
|
+
* - a conditional FK → `freeze: (c) => [freeze(n).when(…).columns(…).references(…)]`
|
|
1429
|
+
* - a trigger that refuses a write → `guards: (g) => [guard(n).on(…).refuse(…)]`
|
|
1430
|
+
* - a one-off data fix → `backfills: [backfill(name, sql)]`
|
|
1431
|
+
* - dropping a constraint → `dropConstraints: ["name"]`
|
|
1432
|
+
* Those are diffed, validated against the live database before the push, and
|
|
1433
|
+
* their mistakes answer you where you write them. A `raw()` is none of that.
|
|
1434
|
+
*
|
|
1064
1435
|
* The deploy emits `up` verbatim on the privileged DDL connection — same trust
|
|
1065
|
-
* posture as policy().using().
|
|
1066
|
-
*
|
|
1436
|
+
* posture as policy().using(). How a CHANGED body is treated depends on what
|
|
1437
|
+
* `name` addresses:
|
|
1438
|
+
* - names a constraint or an index → tracked by NAME only; the deploy sees
|
|
1439
|
+
* the catalog object and skips, so an edited body does nothing. Use a new
|
|
1440
|
+
* name, or drop and re-add explicitly.
|
|
1441
|
+
* - names nothing in the catalog (functions, triggers, grants, compound
|
|
1442
|
+
* statements) → the last applied body is recorded in
|
|
1443
|
+
* `public.palbase_raw_objects` in the same DDL transaction, and an edited
|
|
1444
|
+
* body IS re-applied.
|
|
1445
|
+
*
|
|
1446
|
+
* There is no teardown option — not on the call, and not on this type. One used
|
|
1447
|
+
* to be accepted and was carried into a generated `Down` that NOTHING ever ran:
|
|
1448
|
+
* the engine's `MigrationFiles.Down` has no consumer and the rollback path names
|
|
1449
|
+
* a `runner.go` that does not exist, so an author who wrote one believed they had
|
|
1450
|
+
* a teardown they did not have. `raw()` stopped ACCEPTING it first, and the field
|
|
1451
|
+
* outlived the parameter — an object literal (`raw: [{ name, up, down }]`) still
|
|
1452
|
+
* compiled and still set a field nothing read. Drop what a `raw()` created by
|
|
1453
|
+
* declaring the drop as its own `raw()`.
|
|
1067
1454
|
*/
|
|
1068
1455
|
interface RawConstraintDef {
|
|
1069
1456
|
name: string;
|
|
1070
1457
|
up: string;
|
|
1071
|
-
down?: string;
|
|
1072
1458
|
}
|
|
1073
|
-
declare function raw(name: string, up: string
|
|
1074
|
-
down?: string;
|
|
1075
|
-
}): RawConstraintDef;
|
|
1459
|
+
declare function raw(name: string, up: string): RawConstraintDef;
|
|
1076
1460
|
|
|
1077
1461
|
/** Embedding sağlayıcı DESKRIPTORU — canlı istemci değil, düz veri: şemayla
|
|
1078
1462
|
* birlikte serileşir, çağrıyı Go worker (yazma) ve engine (sorgu) yapar.
|
|
@@ -1201,6 +1585,12 @@ interface MemoryDecl {
|
|
|
1201
1585
|
*/
|
|
1202
1586
|
interface IndexDef {
|
|
1203
1587
|
name: string;
|
|
1588
|
+
/**
|
|
1589
|
+
* `CREATE UNIQUE INDEX` (FR-007). `unique: [{name, columns}]` bir UNIQUE
|
|
1590
|
+
* CONSTRAINT üretir ve constraint'in `WHERE`'i olamaz; `index()` partial
|
|
1591
|
+
* olabilir ama unique olamıyordu. İki yarım vardı, birleşmiyorlardı.
|
|
1592
|
+
*/
|
|
1593
|
+
unique?: boolean;
|
|
1204
1594
|
columns?: string[];
|
|
1205
1595
|
expression?: string;
|
|
1206
1596
|
where?: PolicyExpr;
|
|
@@ -1230,6 +1620,12 @@ interface IndexDef {
|
|
|
1230
1620
|
declare class IndexBuilder {
|
|
1231
1621
|
readonly _def: IndexDef;
|
|
1232
1622
|
constructor(name: string);
|
|
1623
|
+
/**
|
|
1624
|
+
* `CREATE UNIQUE INDEX` (FR-007). `.where()` ile birlikte PARTIAL UNIQUE
|
|
1625
|
+
* index verir (FR-007b) — "NULL'lar serbest, non-NULL'lar tekil" kalıbının
|
|
1626
|
+
* tek bildirimsel yolu.
|
|
1627
|
+
*/
|
|
1628
|
+
unique(): this;
|
|
1233
1629
|
/** Index'in kolonları. SIRA KORUNUR — çok kolonlu bir index'in anlamı sırasıdır. */
|
|
1234
1630
|
on(...cols: PolicyExprRef[]): this;
|
|
1235
1631
|
/**
|
|
@@ -1305,13 +1701,25 @@ interface TableInput<C extends ColumnMap = ColumnMap> {
|
|
|
1305
1701
|
/**
|
|
1306
1702
|
* Named first-class CHECK constraints. Diffed by NAME with a BODY compare:
|
|
1307
1703
|
* a changed `expr` (after pg normalization) recreates the constraint
|
|
1308
|
-
* (DROP + ADD). `
|
|
1309
|
-
*
|
|
1704
|
+
* (DROP + ADD). `name` is identifier-validated.
|
|
1705
|
+
*
|
|
1706
|
+
* İKİ BİÇİM, TEK TEL (FR-009, FR-011):
|
|
1707
|
+
*
|
|
1708
|
+
* - DİZİ — `expr` verbatim yayılan güvenilen SQL (policy `using` gibi).
|
|
1709
|
+
* Bugünkü biçim, olduğu gibi kabul edilmeye devam ediyor.
|
|
1710
|
+
* - CALLBACK — `(c) => [check(name, c.col("amount").gt(0))]`: ifade POLİTİKA
|
|
1711
|
+
* ifade cebiriyle yazılıyor ve kolon adları DERLEME anında doğrulanıyor.
|
|
1712
|
+
* Callback olması bunun şartı: `checks` düz bir dizi olsaydı TypeScript
|
|
1713
|
+
* `columns`'tan kolon adlarını çıkarıp ifadeyi onlarla bağlamlandıramazdı.
|
|
1714
|
+
*
|
|
1715
|
+
* Yanlış yazılmış bir kolon adı string biçiminde ancak
|
|
1716
|
+
* `ALTER TABLE … ADD CONSTRAINT` anında — deploy'un ORTASINDA — Postgres'ten
|
|
1717
|
+
* dönüyor. Tipli biçim aynı cevabı yazma anına taşıyor.
|
|
1718
|
+
*
|
|
1719
|
+
* Tipli ifade CHECK bağlamının DAR kümesine tabi: `existsIn` ve `auth.uid()`
|
|
1720
|
+
* alt sorgu oldukları için `check()` tarafından reddediliyor (FR-010).
|
|
1310
1721
|
*/
|
|
1311
|
-
checks?:
|
|
1312
|
-
name: string;
|
|
1313
|
-
expr: string;
|
|
1314
|
-
}[];
|
|
1722
|
+
checks?: CheckDef[] | ((c: PolicyExprCtx<Extract<keyof C, string>>) => CheckDef[]);
|
|
1315
1723
|
/**
|
|
1316
1724
|
* Plain (non-unique) btree indexes over an ordered column list, emitted as
|
|
1317
1725
|
* standalone `CREATE INDEX [IF NOT EXISTS] name ON table (col1, col2)`
|
|
@@ -1319,12 +1727,85 @@ interface TableInput<C extends ColumnMap = ColumnMap> {
|
|
|
1319
1727
|
* Structural compare by NAME (no expression normalization). `name` and each
|
|
1320
1728
|
* column are identifier-validated by the Go differ.
|
|
1321
1729
|
*
|
|
1322
|
-
*
|
|
1323
|
-
*
|
|
1324
|
-
*
|
|
1325
|
-
*
|
|
1730
|
+
* NAME is the WHOLE diff key. Editing `.where()`, `.onExpression()`,
|
|
1731
|
+
* `.include()` or the sort under a name that is already live does NOTHING —
|
|
1732
|
+
* the deploy matches the name, sees the index, and skips. Give a changed
|
|
1733
|
+
* definition a new name.
|
|
1734
|
+
*
|
|
1735
|
+
* Scope, via `index(name)`: `.on(...cols)` · `.onExpression(sql)` (expression
|
|
1736
|
+
* index) · `.where(pred)` (partial index, typed predicate) · `.unique()`
|
|
1737
|
+
* (UNIQUE, and WITH `.where()` a PARTIAL UNIQUE index) · `.include(cols)`
|
|
1738
|
+
* (covering) · `.asc()`/`.desc()`/`.nulls()`. Predicates and expressions are
|
|
1739
|
+
* probed against the live database before the push — as a prepared statement
|
|
1740
|
+
* AND as a real CREATE INDEX on an empty `LIKE` clone, which is what catches
|
|
1741
|
+
* a subquery predicate or a non-IMMUTABLE function before the apply.
|
|
1742
|
+
*
|
|
1743
|
+
* `index(n).unique().where(p)` is the ONE declarative way to say "NULLs are
|
|
1744
|
+
* free, non-NULLs are unique" — the table-level `unique:` cannot carry a
|
|
1745
|
+
* predicate, because it renders a CONSTRAINT and PostgreSQL has no partial
|
|
1746
|
+
* unique CONSTRAINT (only a partial unique INDEX).
|
|
1747
|
+
*
|
|
1748
|
+
* NOT expressible here: another index method (gin/gist/brin/hash), an
|
|
1749
|
+
* opclass, or CONCURRENTLY.
|
|
1326
1750
|
*/
|
|
1327
1751
|
indexes?: (p: PolicyExprCtx<Extract<keyof C, string>>) => (IndexBuilder | IndexDef)[];
|
|
1752
|
+
/**
|
|
1753
|
+
* Canlıdan DÜŞÜRÜLECEK constraint adları (FR-008).
|
|
1754
|
+
*
|
|
1755
|
+
* Differ additive: canlıda olup bildirimde olmayan bir constraint asla
|
|
1756
|
+
* düşürülmez — beyan dosyası veritabanının nesnelerine sahip değildir. Bu
|
|
1757
|
+
* alan o kuralın TEK istisnası ve açıkça yazılmış olması gerekiyor.
|
|
1758
|
+
*
|
|
1759
|
+
* Ad bilinçli olarak `retired` DEĞİL: bu DSL'de `retired` zaten "emekliye
|
|
1760
|
+
* ayrılmış ÇAĞRI biçimi" demek (`schema-retired-call.test.ts`).
|
|
1761
|
+
*/
|
|
1762
|
+
dropConstraints?: string[];
|
|
1763
|
+
/**
|
|
1764
|
+
* Tablo düzeyinde, ÇOK SÜTUNLU FOREIGN KEY'ler (FR-001).
|
|
1765
|
+
*
|
|
1766
|
+
* Kolon üzerindeki `.references()` tek sütunlu ve tek hedeflidir; çok kiracılı
|
|
1767
|
+
* bütünlüğün istediği `FOREIGN KEY (tenant_id, child_id) REFERENCES parent
|
|
1768
|
+
* (tenant_id, id)`'yi ifade edemez. İki yol birbirini DÜŞÜRMEZ: bu bildirim
|
|
1769
|
+
* kendi adıyla, kolon üzerindekiler `<tablo>_<kolon>_fkey` ile izlenir.
|
|
1770
|
+
*/
|
|
1771
|
+
foreignKeys?: (p: PolicyExprCtx<Extract<keyof C, string>>) => (ForeignKeyBuilder | ForeignKeyDef)[];
|
|
1772
|
+
/**
|
|
1773
|
+
* KOŞULLU FK'lar — bir koşul sağlandığı sürece donan demetler (FR-012).
|
|
1774
|
+
*
|
|
1775
|
+
* "Ödeme `settled` olduğu sürece faturanın tutarı değişemez" bir trigger
|
|
1776
|
+
* istemiyor: koşul sağlanmıyorken NULL veren `STORED` generated sütunlar ve
|
|
1777
|
+
* onlardan `ON UPDATE RESTRICT` bir FK, `MATCH SIMPLE`'ın NULL kaçışı
|
|
1778
|
+
* üzerinden aynı şeyi CONSTRAINT olarak veriyor.
|
|
1779
|
+
*
|
|
1780
|
+
* `foreignKeys` ile aynı sebeple callback: `when` yüklemi TABLONUN KENDİ
|
|
1781
|
+
* kolonlarından çözülüyor ve yanlış ad derleme hatası oluyor.
|
|
1782
|
+
*/
|
|
1783
|
+
freeze?: (p: PolicyExprCtx<Extract<keyof C, string>>) => (FreezeBuilder | FreezeDef)[];
|
|
1784
|
+
/**
|
|
1785
|
+
* Bu tablonun GUARD'ları — bildirimsel kısıtın yetişemediği yazma redleri
|
|
1786
|
+
* (FR-015).
|
|
1787
|
+
*
|
|
1788
|
+
* Yazar üç şey yazar: hangi olay · hangi koşul · ne diyerek reddet. `BEFORE`,
|
|
1789
|
+
* `FOR EACH ROW`, `SECURITY INVOKER`, pinlenmiş `search_path` ve `UPDATE OF`
|
|
1790
|
+
* türetimi güvenli VARSAYILAN — bu yüzeyde görünmezler (FR-017).
|
|
1791
|
+
*
|
|
1792
|
+
* `policies` ile aynı sebeple callback: koşul TABLONUN KENDİ kolonlarından
|
|
1793
|
+
* çözülüyor ve yanlış bir ad derleme hatası oluyor. Bir guard'da yanlış kolon
|
|
1794
|
+
* adı, hiç ateşlemeyen bir guard demektir — güvenlik yolunda fail-open.
|
|
1795
|
+
*/
|
|
1796
|
+
guards?: (p: PolicyExprCtx<Extract<keyof C, string>>) => (GuardBuilder | GuardDef)[];
|
|
1797
|
+
/**
|
|
1798
|
+
* BİR KEZ koşacak veri düzeltmeleri — DDL'den AYRI bir aşamada (FR-033).
|
|
1799
|
+
*
|
|
1800
|
+
* Sütun eklemek bildirimseldir, o sütunu DOLDURMAK değildir: doldurma bugüne
|
|
1801
|
+
* kadar her deploy'da yeniden koşan bir `raw()` bloğunun içindeydi. Burası o
|
|
1802
|
+
* işin kendi aşaması; kayıt ada göre tutuluyor ve aynı ad ikinci kez koşmuyor
|
|
1803
|
+
* (FR-034).
|
|
1804
|
+
*
|
|
1805
|
+
* `policies`/`guards`'ın aksine düz bir dizi: bir backfill'in yüklemi yok,
|
|
1806
|
+
* gövdesi verbatim SQL — bağlamlandıracak bir kolon adı da yok.
|
|
1807
|
+
*/
|
|
1808
|
+
backfills?: BackfillDef[];
|
|
1328
1809
|
/**
|
|
1329
1810
|
* appendOnly (FR-030): tablo yalnız INSERT kabul eder — UPDATE/DELETE hem
|
|
1330
1811
|
* veritabanı yetkisiyle hem üretilen tipte reddedilir (T017/T018).
|
|
@@ -1363,13 +1844,21 @@ interface TableDef<C extends ColumnMap = ColumnMap> {
|
|
|
1363
1844
|
}[];
|
|
1364
1845
|
/** Named raw-SQL DDL objects emitted verbatim on deploy. Tracked by name. */
|
|
1365
1846
|
raw?: RawConstraintDef[];
|
|
1366
|
-
/** Named first-class CHECK constraints. Diffed by name + (normalized) body.
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
expr: string;
|
|
1370
|
-
}[];
|
|
1847
|
+
/** Named first-class CHECK constraints. Diffed by name + (normalized) body.
|
|
1848
|
+
* İki yazım biçimi de (dizi / callback) BURAYA iner — bkz. TableInput.checks. */
|
|
1849
|
+
checks?: CheckDef[];
|
|
1371
1850
|
/** Index bildirimleri; partial/expression/sıra/covering alanlarıyla (FR-041…043). */
|
|
1372
1851
|
indexes?: IndexDef[];
|
|
1852
|
+
/** Canlıdan düşürülecek constraint adları (FR-008). */
|
|
1853
|
+
dropConstraints?: string[];
|
|
1854
|
+
/** Tablo düzeyi çok sütunlu FOREIGN KEY bildirimleri (FR-001). */
|
|
1855
|
+
foreignKeys?: ForeignKeyDef[];
|
|
1856
|
+
/** Koşullu FK ("donan demet") bildirimleri (FR-012). */
|
|
1857
|
+
freeze?: FreezeDef[];
|
|
1858
|
+
/** Guard bildirimleri — bildirimsel kısıtın yetişemediği yazma redleri (FR-015). */
|
|
1859
|
+
guards?: GuardDef[];
|
|
1860
|
+
/** Bir kez koşacak veri düzeltmeleri, DDL'den ayrı aşamada (FR-033). */
|
|
1861
|
+
backfills?: BackfillDef[];
|
|
1373
1862
|
/** appendOnly (FR-030) — bkz. TableInput. */
|
|
1374
1863
|
appendOnly?: boolean;
|
|
1375
1864
|
/** Arama beyanı, doğrulanmış ve taşınmış hali. */
|
|
@@ -1410,10 +1899,10 @@ type TablesByName<T extends readonly TableHandle[]> = {
|
|
|
1410
1899
|
* title: text().notNull(),
|
|
1411
1900
|
* },
|
|
1412
1901
|
* rls: true,
|
|
1413
|
-
* policies: [
|
|
1902
|
+
* policies: (p) => [
|
|
1414
1903
|
* policy("owner_all").for("all").to("authenticated")
|
|
1415
|
-
* .using("owner
|
|
1416
|
-
* .withCheck("owner
|
|
1904
|
+
* .using(p.col("owner").eq(p.auth.uid()))
|
|
1905
|
+
* .withCheck(p.col("owner").eq(p.auth.uid())),
|
|
1417
1906
|
* ],
|
|
1418
1907
|
* });
|
|
1419
1908
|
*
|
|
@@ -4288,6 +4777,7 @@ type EnvServiceDatabase = EnvSchemaSurface & {
|
|
|
4288
4777
|
$supersede: DBClient["supersede"];
|
|
4289
4778
|
$claim: DBClient["claim"];
|
|
4290
4779
|
$lockRows: DBClient["lockRows"];
|
|
4780
|
+
$lockRowsWhere: DBClient["lockRowsWhere"];
|
|
4291
4781
|
$advisoryXactLock: DBClient["advisoryXactLock"];
|
|
4292
4782
|
$attempt: DBClient["attempt"];
|
|
4293
4783
|
$command<T>(fn: (tx: TxPlan) => T extends Promise<unknown> ? never : T, options?: CommandOptions): Promise<Materialized<T>>;
|
|
@@ -4359,6 +4849,7 @@ type EnvTypedDatabase = EnvSchemaSurface & {
|
|
|
4359
4849
|
$supersede: DBClient["supersede"];
|
|
4360
4850
|
$claim: DBClient["claim"];
|
|
4361
4851
|
$lockRows: DBClient["lockRows"];
|
|
4852
|
+
$lockRowsWhere: DBClient["lockRowsWhere"];
|
|
4362
4853
|
$advisoryXactLock: DBClient["advisoryXactLock"];
|
|
4363
4854
|
$attempt: DBClient["attempt"];
|
|
4364
4855
|
$command<T>(fn: (tx: TxPlan) => T extends Promise<unknown> ? never : T, options?: CommandOptions): Promise<Materialized<T>>;
|
|
@@ -4984,8 +5475,12 @@ declare class SerializationFailure extends Conflict implements RetryableError {
|
|
|
4984
5475
|
* Postgres birini seçip iptal etti.
|
|
4985
5476
|
*
|
|
4986
5477
|
* Bu hatayı GÖRMEK bir tasarım sinyali: kilit sırası deterministik değilse
|
|
4987
|
-
* tekrar denemek yalnız maliyeti öteler.
|
|
4988
|
-
*
|
|
5478
|
+
* tekrar denemek yalnız maliyeti öteler. Sırayı sabitleyen üç şey var ve
|
|
5479
|
+
* hangisinin geçerli olduğunu ELİNDEKİ belirler: satırların id'leri elindeyse
|
|
5480
|
+
* `Database.$lockRows(tablo, id'ler)`, elinde bir FİLTRE varsa
|
|
5481
|
+
* `Database.$lockRowsWhere(tablo, filtre)` (FR-037 — birincil anahtara göre
|
|
5482
|
+
* sıralayarak kilitler, yani `updateMany` ile aynı sırayı paylaşır), ya da çok
|
|
5483
|
+
* satırlı yazmanın CTE'si (FR-015).
|
|
4989
5484
|
*/
|
|
4990
5485
|
declare class DeadlockDetected extends Conflict implements RetryableError {
|
|
4991
5486
|
readonly retryable: true;
|
|
@@ -5203,6 +5698,37 @@ interface DBOps {
|
|
|
5203
5698
|
* `FOR NO KEY UPDATE` — `updateMany`'nin CTE'siyle aynı mod.
|
|
5204
5699
|
*/
|
|
5205
5700
|
lockRows(table: string, ids: readonly string[]): Promise<void>;
|
|
5701
|
+
/**
|
|
5702
|
+
* Bir FİLTRENİN eşleştiği satırları kilitle — sırayı yine KATMAN koyar
|
|
5703
|
+
* (FR-037).
|
|
5704
|
+
*
|
|
5705
|
+
* `lockRows` kilitlenecek kümeyi çağıranın SAYMASINI istiyor. "Bu hesabın
|
|
5706
|
+
* bekleyen bütün hareketlerini kilitle" bunu yapamaz: id listesi ancak bir
|
|
5707
|
+
* sorguyla çıkar, ve o sorgu ile kilit arasındaki boşluk tam olarak kilidin
|
|
5708
|
+
* kapatması gereken yarıştır. Bu biçim kümeyi TEK statement'ta hem seçer hem
|
|
5709
|
+
* kilitler.
|
|
5710
|
+
*
|
|
5711
|
+
* ```ts
|
|
5712
|
+
* await db.lockRowsWhere("entries", { account_id: id, status: "pending" });
|
|
5713
|
+
* const rows = await db.findMany("entries", { account_id: id, status: "pending" });
|
|
5714
|
+
* ```
|
|
5715
|
+
*
|
|
5716
|
+
* `ORDER BY <pk>` — `updateMany`'nin kilit CTE'siyle AYNI sıra, yani aynı
|
|
5717
|
+
* satır kümesine giren iki yol birbirini deadlock'a sokmaz (FR-037b, canlı
|
|
5718
|
+
* kanıt: `v2/internal/schema/lock_order_test.go`).
|
|
5719
|
+
*
|
|
5720
|
+
* MOD ÇAĞIRANIN SEÇİMİ ve eşitlenmez: `"update"` (varsayılan, `FOR UPDATE`),
|
|
5721
|
+
* `"share"` (`FOR SHARE` — "ben okurken kimse değiştirmesin"), `"noKeyUpdate"`
|
|
5722
|
+
* (`FOR NO KEY UPDATE` — `updateMany`'nin modu, anahtar dışı alanları
|
|
5723
|
+
* değiştirecek yazmalar için). Herkesi tek moda zorlamak, okuma kilidi
|
|
5724
|
+
* isteyeni ihtiyacından fazlasını almaya zorlardı.
|
|
5725
|
+
*
|
|
5726
|
+
* BOŞ FİLTRE REDDEDİLİR: bütün tabloyu kilitlemek kazayla ulaşılacak bir yer
|
|
5727
|
+
* değil.
|
|
5728
|
+
*/
|
|
5729
|
+
lockRowsWhere(table: string, where: Record<string, unknown>, opts?: {
|
|
5730
|
+
mode?: "update" | "share" | "noKeyUpdate";
|
|
5731
|
+
}): Promise<void>;
|
|
5206
5732
|
/**
|
|
5207
5733
|
* Bir ADI kilitle — satırı değil (FR-054). Kilitlenecek satırı olmayan
|
|
5208
5734
|
* işler için ("aynı anda tek bir fatura kapanışı koşsun").
|
|
@@ -5614,4 +6140,4 @@ type Middleware = (ctx: MiddlewareContext, next: () => Promise<void>) => Promise
|
|
|
5614
6140
|
*/
|
|
5615
6141
|
type AuthSpec = boolean | Partial<AuthConfig>;
|
|
5616
6142
|
|
|
5617
|
-
export {
|
|
6143
|
+
export { type FileContext as $, type AuthSpec as A, type BackfillDef as B, type CommandOptions as C, type DatabaseBudget as D, type EnvServiceDatabase as E, type ColumnMap as F, type ColumnType as G, HttpError as H, Conflict as I, Database as J, type DatabaseQueryEvent as K, DeadlockDetected as L, Documents as M, EXTENSION_DEPENDENCIES as N, type EmbeddingModelRef as O, type Page as P, type EnvSchemas as Q, type RateLimitConfig as R, type SchemaDef as S, type TransactionIsolation as T, type EnvTables as U, type EnvTypedDatabase as V, type EnvTypedTable as W, type ErrorDef as X, type ErrorMap as Y, type ErrorThrowers as Z, __runWithRuntime as _, type DBClient as a, type PalbaseEmailClient as a$, type FindManyOpts as a0, type FkAction as a1, type FkMatch as a2, Flags as a3, Forbidden as a4, ForeignKeyBuilder as a5, type ForeignKeyDef as a6, FreezeBuilder as a7, type FreezeDef as a8, GuardBuilder as a9, type PalbaseAnalyticsClient as aA, type PalbaseAnalyticsManagementNamespace as aB, type PalbaseAnalyticsProperties as aC, type PalbaseAnalyticsQueryNamespace as aD, type PalbaseAttestAndroidParams as aE, type PalbaseAttestAndroidResult as aF, type PalbaseAttestiOSParams as aG, type PalbaseAttestiOSResult as aH, type PalbaseAuthAdminClient as aI, type PalbaseAuthClient as aJ, type PalbaseBatchOverrideOperation as aK, type PalbaseBatchSetOverridesResult as aL, type PalbaseBindDeviceParams as aM, type PalbaseBucketClient as aN, type PalbaseClearAllOverridesResult as aO, type PalbaseClearOverrideResult as aP, type PalbaseCohortQueryInput as aQ, type PalbaseCohortResult as aR, type PalbaseCollectionRef as aS, type PalbaseCountQueryInput as aT, type PalbaseCountResult as aU, type PalbaseCreateLinkParams as aV, type PalbaseDeviceInfo as aW, type PalbaseDeviceTokenView as aX, type PalbaseDocsClient as aY, type PalbaseDocumentRef as aZ, type PalbaseDocumentSnapshot as a_, type GuardDef as aa, type GuardEvent as ab, type HttpMethod as ac, IndexBuilder as ad, type IndexDef as ae, type InsertManyOptions as af, type InsertShape as ag, type InsertValues as ah, type LifecycleHook as ai, Log as aj, type Logger as ak, type Materialized as al, type Middleware as am, type MiddlewareContext as an, type MiddlewareHandler as ao, type MutateInput as ap, NotFound as aq, Notifications as ar, type OnDeleteAction as as, type OrderBySpec as at, PALBASE_EXTENSIONS as au, type PBRequest as av, type PageInfo as aw, type PageInput as ax, type PageNavigation as ay, PalError as az, type RuntimeServices as b, type PalbaseUsersResult as b$, type PalbaseEmailSendParams as b0, type PalbaseEmailSendResponse as b1, type PalbaseEventNamesResult as b2, type PalbaseEventsQueryInput as b3, type PalbaseEventsResult as b4, type PalbaseExtension as b5, type PalbaseFileObject as b6, type PalbaseFlag as b7, type PalbaseFlagContext as b8, type PalbaseFlagSource as b9, type PalbaseNotificationsClient as bA, type PalbaseOverviewResult as bB, type PalbasePreferences as bC, type PalbasePreferencesClient as bD, type PalbasePushClient as bE, type PalbasePushSendParams as bF, type PalbasePushSendResponse as bG, type PalbaseQrCodeOptions as bH, type PalbaseQuerySnapshot as bI, type PalbaseRealtimeClient as bJ, type PalbaseRegisterDeviceParams as bK, type PalbaseRetentionQueryInput as bL, type PalbaseRetentionResult as bM, type PalbaseSession as bN, type PalbaseSetOverrideResult as bO, type PalbaseSetOverridesResult as bP, type PalbaseSignedUrlResponse as bQ, type PalbaseSmsClient as bR, type PalbaseSmsSendParams as bS, type PalbaseSmsSendResponse as bT, type PalbaseStorageClient as bU, type PalbaseTransformOptions as bV, type PalbaseUpdateLinkParams as bW, type PalbaseUploadOptions as bX, type PalbaseUser as bY, type PalbaseUserDetailResult as bZ, type PalbaseUsersQueryInput as b_, type PalbaseFlagValue as ba, type PalbaseFlagVariant as bb, type PalbaseFlagsClient as bc, type PalbaseFlagsServiceClient as bd, type PalbaseFunctionsClient as be, type PalbaseFunnelQueryInput as bf, type PalbaseFunnelResult as bg, type PalbaseIdentifyTraits as bh, type PalbaseInboxClient as bi, type PalbaseInboxListOptions as bj, type PalbaseInboxListResult as bk, type PalbaseInboxMessage as bl, type PalbaseInboxSendParams as bm, type PalbaseInboxSendResponse as bn, type PalbaseInitialLink as bo, type PalbaseInvokeOptions as bp, type PalbaseLink as bq, type PalbaseLinkAnalytics as br, type PalbaseLinkDetails as bs, type PalbaseLinksClient as bt, type PalbaseListLinksOptions as bu, type PalbaseListLinksResult as bv, type PalbaseListOptions as bw, type PalbaseMatchParams as bx, type PalbaseMultiChannelResponse as by, type PalbaseNotificationChannel as bz, type DatabaseDiagnosticsOptions as c, type UniqueWhere as c$, type PalbaseVerifyRequestSignatureParams as c0, type PalbaseWhatsAppClient as c1, type PalbaseWhatsAppEvent as c2, type PalbaseWhatsAppSendParams as c3, type PalbaseWhatsAppSendResponse as c4, type PalbaseWhatsAppTemplate as c5, type PalbaseWhereOperator as c6, type PolicyBinOp as c7, PolicyBuilder as c8, type PolicyCommand as c9, type TxInsertShape as cA, type TxInsertValue as cB, type TxNow as cC, type TxPlan as cD, TxPlanError as cE, type TxPlanHandle as cF, type TxPlanOpResult as cG, type TxPlanRejection as cH, TxRefError as cI, type TxRow as cJ, type TxRows as cK, type TxSelectOptions as cL, type TxSetShape as cM, type TxSetValue as cN, type TxTable as cO, type TxTables as cP, type TxWhere as cQ, type TxWireExpr as cR, type TxWireGuard as cS, type TxWireOp as cT, type TxWireRef as cU, type TxWireValue as cV, type TypedDB as cW, type TypedTable as cX, type TypedTx as cY, Unauthorized as cZ, UniqueViolation as c_, type PolicyDef as ca, type PolicyExprCtx as cb, PolicyExprRef as cc, type PolicyMode as cd, type PolicyOperand as ce, type QueryInput as cf, type RawConstraintDef as cg, Realtime as ch, type Ref as ci, type RequestStore as cj, type RowShape as ck, Secrets as cl, type SecretsService as cm, SerializationFailure as cn, type SetShape as co, type SetValue as cp, type ShutdownRunner as cq, type SqlFragment as cr, Storage as cs, TABLE_META as ct, type TableDef as cu, type TableHandle as cv, type TableInput as cw, type TableRef as cx, TooManyRequests as cy, type TxColumnExpr as cz, type DatabaseDiagnostics as d, type User as d0, type VerifiedDevice as d1, type WhereFilter as d2, type WhereOp as d3, __getRuntime as d4, __resetLifecycleHooks as d5, __runStartHooks as d6, __setRuntime as d7, backfill as d8, bigint as d9, onShutdown as dA, onStart as dB, openai as dC, ownedByUser as dD, policy as dE, raw as dF, sqlFragment as dG, text as dH, timestamp as dI, userRef as dJ, uuid as dK, vector as dL, withRetry as dM, boolean as da, can as db, check as dc, col as dd, dec as de, decrement as df, defineMiddleware as dg, defineSchema as dh, defineTable as di, enumType as dj, exprCtx as dk, foreignKey as dl, freeze as dm, guard as dn, inc as dp, increment as dq, index as dr, installationRef as ds, integer as dt, isPalbaseExtension as du, isRetryable as dv, jsonb as dw, makeTypedDB as dx, now as dy, numeric as dz, type DBOps as e, type RawPageOptions as f, type TxPlanBody as g, type TxPlanResponse as h, type CacheClient as i, __requestALS as j, type PalbaseResult as k, type PolicyExpr as l, type AggregateInput as m, type AggregateResult as n, type AnyColumn as o, type AtomicDatabase as p, type AtomicOptions as q, Auth as r, type AuthConfig as s, BadRequest as t, Cache as u, type CheckDef as v, type ClientInfo as w, type ColRef as x, ColumnBuilder as y, type ColumnDef as z };
|