@palbase/backend 27.1.0 → 29.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 +284 -50
- package/dist/bin/palbase-backend.cjs.map +1 -1
- package/dist/bin/palbase-backend.js +4 -4
- package/dist/{chunk-JVZQCC77.js → chunk-3TUJWHC2.js} +8 -3
- package/dist/chunk-3TUJWHC2.js.map +1 -0
- package/dist/{chunk-EB3TUX5J.js → chunk-DHJ3SYAE.js} +251 -50
- package/dist/chunk-DHJ3SYAE.js.map +1 -0
- package/dist/{chunk-XABHGMUT.js → chunk-ENZ2RFFJ.js} +2 -2
- package/dist/{chunk-BQN723PL.js → chunk-ESSQ3YML.js} +73 -7
- package/dist/chunk-ESSQ3YML.js.map +1 -0
- package/dist/{chunk-OZKSM3JW.js → chunk-SG4UTNOP.js} +7 -3
- package/dist/chunk-SG4UTNOP.js.map +1 -0
- package/dist/db/index.cjs +8 -2
- 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 +294 -50
- 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 +11 -4
- package/dist/{index-V7QRh1wg.d.ts → index-BOe82fsK.d.ts} +256 -19
- package/dist/{index-CAKOgAlP.d.ts → index-BYDUKexK.d.ts} +139 -10
- package/dist/{index-H-0qv5d4.d.cts → index-BZfmdRmh.d.cts} +139 -10
- package/dist/{index-CgE4sVhg.d.cts → index-ChvoVczS.d.cts} +256 -19
- package/dist/index.cjs +81 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -22
- package/dist/index.d.ts +6 -22
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/dist/openapi/index.d.cts +2 -2
- package/dist/openapi/index.d.ts +2 -2
- package/dist/{registry-DHsPDY0_.d.cts → registry-B2KfKWv1.d.cts} +1 -1
- package/dist/{registry-4EI8aaFs.d.ts → registry-DaqHsOq8.d.ts} +1 -1
- package/dist/test/index.cjs +129 -6
- 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 +126 -6
- package/dist/test/index.js.map +1 -1
- package/docs/README.md +1 -1
- package/docs/database.md +118 -1
- package/docs/llms-full.txt +119 -2
- package/package.json +1 -1
- package/template/package.json +1 -1
- package/dist/chunk-BQN723PL.js.map +0 -1
- package/dist/chunk-EB3TUX5J.js.map +0 -1
- package/dist/chunk-JVZQCC77.js.map +0 -1
- package/dist/chunk-OZKSM3JW.js.map +0 -1
- /package/dist/{chunk-XABHGMUT.js.map → chunk-ENZ2RFFJ.js.map} +0 -0
package/dist/engine/index.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import '../index-
|
|
2
|
-
export { A as App,
|
|
1
|
+
import '../index-ChvoVczS.cjs';
|
|
2
|
+
export { A as App, g as AuthVerifier, B as BootRefused, h as CreateAppOptions, D as DECLARATION_REFUSAL, a as DeclarationRefused, E as EgressPolicy, j as EngineConfig, M as ModuleClients, R as RateLimiter, k as RequestDatabase, l as RouteEntry, m as RuntimeHooks, S as ScrubResult, n as SqlDriver, o as SqlTx, p as buildRouteTable, q as createApp, r as createLazyTransaction, s as createOps, t as createRequestDatabase, u as effectiveAuth, v as hostAllowed, w as installEgressFence, i as isDeclarationRefused, x as loadConfig, y as makeMemoryCache, z as matchRoute, F as quoteIdent, G as scrubSecrets, H as withTables } from '../index-BZfmdRmh.cjs';
|
|
3
3
|
import '../db/env.cjs';
|
|
4
4
|
import '../stack.cjs';
|
|
5
5
|
import 'zod';
|
|
6
6
|
import 'node:async_hooks';
|
|
7
7
|
import '../module-Dl1KFVtc.cjs';
|
|
8
|
-
import '../registry-
|
|
8
|
+
import '../registry-B2KfKWv1.cjs';
|
package/dist/engine/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import '../index-
|
|
2
|
-
export { A as App,
|
|
1
|
+
import '../index-BOe82fsK.js';
|
|
2
|
+
export { A as App, g as AuthVerifier, B as BootRefused, h as CreateAppOptions, D as DECLARATION_REFUSAL, a as DeclarationRefused, E as EgressPolicy, j as EngineConfig, M as ModuleClients, R as RateLimiter, k as RequestDatabase, l as RouteEntry, m as RuntimeHooks, S as ScrubResult, n as SqlDriver, o as SqlTx, p as buildRouteTable, q as createApp, r as createLazyTransaction, s as createOps, t as createRequestDatabase, u as effectiveAuth, v as hostAllowed, w as installEgressFence, i as isDeclarationRefused, x as loadConfig, y as makeMemoryCache, z as matchRoute, F as quoteIdent, G as scrubSecrets, H as withTables } from '../index-BYDUKexK.js';
|
|
3
3
|
import '../db/env.js';
|
|
4
4
|
import '../stack.js';
|
|
5
5
|
import 'zod';
|
|
6
6
|
import 'node:async_hooks';
|
|
7
7
|
import '../module-Dl1KFVtc.js';
|
|
8
|
-
import '../registry-
|
|
8
|
+
import '../registry-DaqHsOq8.js';
|
package/dist/engine/index.js
CHANGED
|
@@ -16,16 +16,22 @@ import {
|
|
|
16
16
|
quoteIdent,
|
|
17
17
|
scrubSecrets,
|
|
18
18
|
withTables
|
|
19
|
-
} from "../chunk-
|
|
20
|
-
import
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
} from "../chunk-DHJ3SYAE.js";
|
|
20
|
+
import {
|
|
21
|
+
DECLARATION_REFUSAL,
|
|
22
|
+
DeclarationRefused,
|
|
23
|
+
isDeclarationRefused
|
|
24
|
+
} from "../chunk-ESSQ3YML.js";
|
|
25
|
+
import "../chunk-SG4UTNOP.js";
|
|
26
|
+
import "../chunk-3TUJWHC2.js";
|
|
23
27
|
import "../chunk-VVMJEVQP.js";
|
|
24
28
|
import "../chunk-CGNN2PUH.js";
|
|
25
29
|
import "../chunk-VXPNPVAG.js";
|
|
26
30
|
export {
|
|
27
31
|
AuthVerifier,
|
|
28
32
|
BootRefused,
|
|
33
|
+
DECLARATION_REFUSAL,
|
|
34
|
+
DeclarationRefused,
|
|
29
35
|
RateLimiter,
|
|
30
36
|
buildRouteTable,
|
|
31
37
|
createApp,
|
|
@@ -35,6 +41,7 @@ export {
|
|
|
35
41
|
effectiveAuth,
|
|
36
42
|
hostAllowed,
|
|
37
43
|
installEgressFence,
|
|
44
|
+
isDeclarationRefused,
|
|
38
45
|
loadConfig,
|
|
39
46
|
makeMemoryCache,
|
|
40
47
|
matchRoute,
|
|
@@ -51,12 +51,24 @@ interface User {
|
|
|
51
51
|
interface AuthConfig {
|
|
52
52
|
/** Whether authentication is required. Defaults to true. */
|
|
53
53
|
required: boolean;
|
|
54
|
-
/** Required role for access. If undefined, any authenticated user is allowed.
|
|
54
|
+
/** Required application role for access. If undefined, any authenticated user is allowed.
|
|
55
55
|
*
|
|
56
|
-
* Matched against the caller's `
|
|
57
|
-
*
|
|
58
|
-
*
|
|
56
|
+
* Matched against the caller's rows in `auth.user_roles` — NOT against the
|
|
57
|
+
* `role` claim, which is the DATABASE role RLS reads and is the literal
|
|
58
|
+
* string "authenticated" for every signed-in user. Reading it from the table
|
|
59
|
+
* is what makes a revoked role take effect on the very NEXT request instead
|
|
60
|
+
* of whenever the token happens to expire.
|
|
61
|
+
*
|
|
62
|
+
* Not signed in → 401; signed in without the role → 403. */
|
|
59
63
|
role?: string;
|
|
64
|
+
/** Required permission for access, as `resource.action` (e.g. "posts.delete_any").
|
|
65
|
+
*
|
|
66
|
+
* Resolved through `auth.has_permission(...)`, which answers from the roles
|
|
67
|
+
* the caller holds and the permissions those roles carry. The query runs in
|
|
68
|
+
* the request's own transaction, so it costs no extra connection.
|
|
69
|
+
*
|
|
70
|
+
* Signed in without the permission → 403. */
|
|
71
|
+
permission?: string;
|
|
60
72
|
/** Require a confirmed email address. An unverified caller gets 403
|
|
61
73
|
* `email_not_verified`. Fences a whole controller; for a partial rule read
|
|
62
74
|
* `user.emailVerified` in the handler instead. */
|
|
@@ -2825,7 +2837,12 @@ type RowShape<T extends TableDef> = {
|
|
|
2825
2837
|
};
|
|
2826
2838
|
/** A typed table accessor that mirrors the runtime DBClient surface. */
|
|
2827
2839
|
interface TypedTable<T extends TableDef> {
|
|
2828
|
-
insert(data: InsertShape<T
|
|
2840
|
+
insert(data: InsertValues<InsertShape<T>>): Promise<RowShape<T>>;
|
|
2841
|
+
/** Çok satır, TEK statement. Satırların anahtar kümesi aynı olmalı. */
|
|
2842
|
+
insertMany(rows: readonly InsertValues<InsertShape<T>>[], opts?: {
|
|
2843
|
+
onConflict: readonly string[];
|
|
2844
|
+
action?: "ignore" | "update";
|
|
2845
|
+
}): Promise<RowShape<T>[]>;
|
|
2829
2846
|
put(q: {
|
|
2830
2847
|
data: InsertShape<T>;
|
|
2831
2848
|
onConflict: readonly string[];
|
|
@@ -2837,7 +2854,7 @@ interface TypedTable<T extends TableDef> {
|
|
|
2837
2854
|
where: {
|
|
2838
2855
|
id: string;
|
|
2839
2856
|
};
|
|
2840
|
-
set:
|
|
2857
|
+
set: SetShape<InsertShape<T>>;
|
|
2841
2858
|
}): Promise<RowShape<T> | null>;
|
|
2842
2859
|
delete(id: string): Promise<void>;
|
|
2843
2860
|
findById(id: string): Promise<RowShape<T> | null>;
|
|
@@ -2859,11 +2876,33 @@ interface TypedTable<T extends TableDef> {
|
|
|
2859
2876
|
* if (row === undefined) throw new Conflict("yetersiz bakiye");
|
|
2860
2877
|
* ```
|
|
2861
2878
|
*/
|
|
2862
|
-
updateMany
|
|
2879
|
+
updateMany<const Q extends MutateInput<RowShape<T>, InsertShape<T>>>(q: Q): Promise<Q extends {
|
|
2880
|
+
returning: false;
|
|
2881
|
+
} ? number : RowShape<T>[]>;
|
|
2863
2882
|
/** Delete every matching row; resolves to how many. Empty filter refused. */
|
|
2864
2883
|
deleteMany(q: {
|
|
2865
2884
|
where: WhereFilter<RowShape<T>> | SqlFragment;
|
|
2866
2885
|
}): Promise<number>;
|
|
2886
|
+
/**
|
|
2887
|
+
* Toplama — `sum` / `avg` / `min` / `max` / `count`, isteğe bağlı `groupBy`.
|
|
2888
|
+
*
|
|
2889
|
+
* ```ts
|
|
2890
|
+
* const r = await Database.public.entries.aggregate({
|
|
2891
|
+
* where: { account_id },
|
|
2892
|
+
* sum: ["amount_kurus"],
|
|
2893
|
+
* count: true,
|
|
2894
|
+
* });
|
|
2895
|
+
* r.sum.amount_kurus; // string | null — KAYIPSIZ
|
|
2896
|
+
* r.count; // number
|
|
2897
|
+
* ```
|
|
2898
|
+
*
|
|
2899
|
+
* `sum`/`avg` yalnız sayısal kolonlarda ve HER ZAMAN `string` döner: para JS
|
|
2900
|
+
* `number`'ına uğradığı anda kesinliğini kaybeder. `| null` çünkü Postgres
|
|
2901
|
+
* boş kümede NULL döndürür — "hiç satır yoktu" ile "toplam sıfırdı" farklı.
|
|
2902
|
+
*
|
|
2903
|
+
* `groupBy` verilirse dönüş bir DİZİ ve her satır grup kolonlarını taşır.
|
|
2904
|
+
*/
|
|
2905
|
+
aggregate<const Q extends AggregateInput<RowShape<T>>>(q: Q): Promise<AggregateResult<Q, RowShape<T>>>;
|
|
2867
2906
|
/** How many rows match. An empty filter is legitimate: counting is a read. */
|
|
2868
2907
|
count(q?: {
|
|
2869
2908
|
where?: WhereFilter<RowShape<T>> | SqlFragment;
|
|
@@ -2974,9 +3013,39 @@ declare function col<const N extends string>(name: N): ColRef<N>;
|
|
|
2974
3013
|
* kabul, `numeric ↔ text` ret olur ve ikisi de DOĞRU olur. Defterde teklif.
|
|
2975
3014
|
*/
|
|
2976
3015
|
type PgFamily<V> = [NonNullable<V>] extends [boolean] ? "bool" : [NonNullable<V>] extends [readonly (number | string)[]] ? "array" : [NonNullable<V>] extends [Date] ? "date" : [NonNullable<V>] extends [string | number] ? "scalar" : "opaque";
|
|
2977
|
-
/**
|
|
3016
|
+
/**
|
|
3017
|
+
* Kolonun BİLDİRİLMİŞ Postgres tipi — `env-gen`'in bastığı markadan.
|
|
3018
|
+
*
|
|
3019
|
+
* Marka yoksa `"?"`: elle yazılmış bir `Tables` (testler) ya da yeniden
|
|
3020
|
+
* üretilmemiş bir `palbase-env.d.ts`. O durumda eski TS-tipi sezgiseline
|
|
3021
|
+
* düşülüyor, çünkü marka olmadan söylenebilecek daha doğru bir şey yok.
|
|
3022
|
+
*/
|
|
3023
|
+
type PgTag<V> = [NonNullable<V>] extends [{
|
|
3024
|
+
readonly __pg?: infer N;
|
|
3025
|
+
}] ? [N] extends [string] ? N : "?" : "?";
|
|
3026
|
+
/**
|
|
3027
|
+
* Postgres'te birbirleriyle karşılaştırılabilen tipler tek "cins".
|
|
3028
|
+
*
|
|
3029
|
+
* `integer`, `bigint` ve `numeric` örtük sayısal dönüşümle karşılaştırılır;
|
|
3030
|
+
* geri kalan her tip yalnız kendisiyle. `uuid ↔ text` ve `enum ↔ text`
|
|
3031
|
+
* Postgres'te `operator does not exist` verir — D-021'de CANLI ölçülmüştü ve
|
|
3032
|
+
* tip bunu göremediği için kabul ediyordu.
|
|
3033
|
+
*/
|
|
3034
|
+
type PgKind<P> = P extends "integer" | "bigint" | "numeric" ? "num" : P;
|
|
3035
|
+
/** İki tarafın da markası var mı — yoksa sezgisele düşülür. */
|
|
3036
|
+
type BothBranded<A, B> = "?" extends PgTag<A> ? false : "?" extends PgTag<B> ? false : true;
|
|
3037
|
+
type PgSameKind<A, B> = [PgKind<PgTag<A>>] extends [PgKind<PgTag<B>>] ? [PgKind<PgTag<B>>] extends [PgKind<PgTag<A>>] ? true : false : false;
|
|
3038
|
+
/**
|
|
3039
|
+
* `A` kolonu `B` ile karşılaştırılabilir mi.
|
|
3040
|
+
*
|
|
3041
|
+
* Marka varsa CEVAP KESİN: ne yanlış ret ne yanlış kabul. D-021 bu kuralı
|
|
3042
|
+
* "doğru olamaz" diye kaydetmişti çünkü tipte ayırt edecek bilgi yoktu; bilgi
|
|
3043
|
+
* artık tipte.
|
|
3044
|
+
*/
|
|
3045
|
+
type ColComparable<A, B> = BothBranded<A, B> extends true ? PgSameKind<A, B> : [PgFamily<A>] extends [PgFamily<B>] ? true : false;
|
|
3046
|
+
/** `Row`'un `V` ile karşılaştırılabilir kolonları. */
|
|
2978
3047
|
type ColumnsComparableTo<Row, V> = {
|
|
2979
|
-
[K in keyof Row]-?:
|
|
3048
|
+
[K in keyof Row]-?: ColComparable<Row[K], V> extends true ? K : never;
|
|
2980
3049
|
}[keyof Row];
|
|
2981
3050
|
/**
|
|
2982
3051
|
* Bu satırın kolonlarından birine referans. `Row` bilinmiyorsa hiçbiri.
|
|
@@ -2985,7 +3054,26 @@ type ColumnsComparableTo<Row, V> = {
|
|
|
2985
3054
|
* `findMany`'nin `Row`'u bilmediği yolların ve jsonb kolonlarının hâli, ve
|
|
2986
3055
|
* ikisinde de tipin söyleyebileceği bir şey yok.
|
|
2987
3056
|
*/
|
|
2988
|
-
|
|
3057
|
+
/**
|
|
3058
|
+
* "Kısıt verilmedi" için AYRI bir işaret — `unknown` DEĞİL.
|
|
3059
|
+
*
|
|
3060
|
+
* Eskiden varsayılan `unknown`'dı ve dal `[unknown] extends [V]` ile
|
|
3061
|
+
* seçiliyordu. Ama `jsonb` kolonlarının DEĞER TİPİ de `unknown`: yani gerçek
|
|
3062
|
+
* bir jsonb kolonu "kısıt verilmedi" sanılıp TÜM kolonlarla karşılaştırılabilir
|
|
3063
|
+
* hâle geliyordu. D-021 bunu "jsonb ↔ text derleniyor" diye kaydetmişti ve PG
|
|
3064
|
+
* markası tek başına kapatmadı — `unknown & X` kesişimi `X`'e çöktüğü için
|
|
3065
|
+
* jsonb markalanamıyor (markalamak kolonu daraltıp meşru yazmaları kırdı,
|
|
3066
|
+
* gerçek projede ölçüldü).
|
|
3067
|
+
*
|
|
3068
|
+
* Ayrı bir işaretle iki durum artık ayrışıyor: kısıtsız yol kısıtsız kalıyor,
|
|
3069
|
+
* jsonb ise KENDİ ailesine düşüyor — yani yalnız başka bir jsonb ile
|
|
3070
|
+
* karşılaştırılabiliyor.
|
|
3071
|
+
*/
|
|
3072
|
+
declare const NO_CONSTRAINT: unique symbol;
|
|
3073
|
+
type NoColConstraint = {
|
|
3074
|
+
readonly [NO_CONSTRAINT]: true;
|
|
3075
|
+
};
|
|
3076
|
+
type ColRefOf<Row, V = NoColConstraint> = [keyof Row] extends [never] ? never : [V] extends [NoColConstraint] ? ColRef<Extract<keyof Row, string>> : ColRef<Extract<ColumnsComparableTo<Row, V>, string>>;
|
|
2989
3077
|
/**
|
|
2990
3078
|
* Doğrulanmış, GÖMÜLEBİLİR bir SQL parçası (FR-018, FR-019).
|
|
2991
3079
|
*
|
|
@@ -3063,7 +3151,7 @@ type TextOps<V> = V extends string ? {
|
|
|
3063
3151
|
* kolonunda YASAKLAMAK yazarı bu yüzden `sqlFragment`e düşürürdü — ve bu
|
|
3064
3152
|
* özelliğin var olma nedeni tam olarak o düşüşü kaldırmak.
|
|
3065
3153
|
*/
|
|
3066
|
-
type NowComparable<V> = [NonNullable<V>] extends [string | Date] ? TxNow : never;
|
|
3154
|
+
type NowComparable<V> = "?" extends PgTag<V> ? [NonNullable<V>] extends [string | Date] ? TxNow : never : PgTag<V> extends "timestamp" ? TxNow : never;
|
|
3067
3155
|
type WhereOpBody<V, C> = {
|
|
3068
3156
|
gt?: V | C | NowComparable<V>;
|
|
3069
3157
|
gte?: V | C | NowComparable<V>;
|
|
@@ -3246,6 +3334,15 @@ type QueryInput<Row, K extends keyof Row = keyof Row, Rels = unknown> = {
|
|
|
3246
3334
|
type MutateInput<Row, Insert, Rels = unknown> = {
|
|
3247
3335
|
where: WhereFilter<Row> | SqlFragment | HasBranch<Row, Rels>;
|
|
3248
3336
|
set: SetShape<Insert>;
|
|
3337
|
+
/**
|
|
3338
|
+
* `false` verilirse SATIRLAR değil SAYI döner — `deleteMany` ile aynı şekil.
|
|
3339
|
+
*
|
|
3340
|
+
* ÖLÇÜLDÜ (200 bin satır, canlı pg16): `RETURNING *` sunucuda %55 daha
|
|
3341
|
+
* pahalı (7,2 sn → 11,1 sn) ve JS'te 45 MB yığın tutuyor — satır başına 236
|
|
3342
|
+
* bayt, yani bir milyon satırda 225 MB. Çoğu çağrı için dönen diziyi okumak
|
|
3343
|
+
* DOĞRU ve varsayılan odur; toplu bir iş için çıkış yolu olması gerekiyordu.
|
|
3344
|
+
*/
|
|
3345
|
+
returning?: boolean;
|
|
3249
3346
|
};
|
|
3250
3347
|
/**
|
|
3251
3348
|
* `set`'e yazılabilen değer (FR-012): kolonun kendi tipi ya da — sayısal
|
|
@@ -3257,7 +3354,25 @@ type MutateInput<Row, Insert, Rels = unknown> = {
|
|
|
3257
3354
|
* string de sayısal sayılır; ayrımı burada yapamayız, ama D-007 zaten miktarın
|
|
3258
3355
|
* JS `number`'a hiç uğramamasını istiyor.
|
|
3259
3356
|
*/
|
|
3260
|
-
|
|
3357
|
+
/** `increment()`/`decrement()` HANGİ kolonlarda anlamlı — bildirilmiş PG tipine
|
|
3358
|
+
* göre. Marka yoksa eski sezgisel (`number | string`), ki o `text` kolonda da
|
|
3359
|
+
* izin veriyordu: Postgres `text + 1` demez. */
|
|
3360
|
+
type NumericCol<V> = "?" extends PgTag<V> ? NonNullable<V> extends number | string ? TxColumnExpr : never : PgKind<PgTag<V>> extends "num" ? TxColumnExpr : never;
|
|
3361
|
+
/**
|
|
3362
|
+
* Bir EKLEME yolunda yazılabilecek değer.
|
|
3363
|
+
*
|
|
3364
|
+
* Kolonun kendi tipi ya da — zaman kolonlarında — sunucu saati. `increment()`
|
|
3365
|
+
* burada YOK ve olamaz: satır henüz yokken "kolonun şu anki değeri" diye bir
|
|
3366
|
+
* şey yok, motor da bunu adıyla reddediyor.
|
|
3367
|
+
*
|
|
3368
|
+
* Var olma nedeni ölçülmüş: introspect edilmiş şemalarda zaman kolonlarının
|
|
3369
|
+
* çoğu varsayılansız (`timestamp()`), yani "eklerken sunucu saatini yaz"ın tek
|
|
3370
|
+
* karşılığı istemci saatiydi — 33 tablolu bir projede 12 yerde.
|
|
3371
|
+
*/
|
|
3372
|
+
type InsertValues<Insert> = {
|
|
3373
|
+
[K in keyof Insert]: Insert[K] | NowComparable<Insert[K]>;
|
|
3374
|
+
};
|
|
3375
|
+
type SetValue<V> = V | NumericCol<V> | NowComparable<V>;
|
|
3261
3376
|
/** Bir update'in `set`'i: insert şeklinin herhangi bir alt kümesi, ifadelerle. */
|
|
3262
3377
|
type SetShape<Insert> = {
|
|
3263
3378
|
[K in keyof Insert]?: SetValue<Insert[K]>;
|
|
@@ -3338,9 +3453,90 @@ type RecommendParamsTyped<T extends TableTypes> = SimilarParamsTyped<T> & {
|
|
|
3338
3453
|
type RelsOf<T> = T extends {
|
|
3339
3454
|
relations: infer R;
|
|
3340
3455
|
} ? R : unknown;
|
|
3456
|
+
/**
|
|
3457
|
+
* TOPLAMA — dönüş tipi PG markasından TÜRETİLİR, tahmin edilmez.
|
|
3458
|
+
*
|
|
3459
|
+
* Para bu SDK'dan geçecek, ve toplamada kaybedilecek tek şey kesinliktir:
|
|
3460
|
+
* `sum(numeric)` Postgres'te `numeric`, `sum(integer)` `bigint` — İKİSİ DE JS
|
|
3461
|
+
* `number`'ında kayıplı. Bu yüzden `sum`/`avg` HER ZAMAN `string` döner ve
|
|
3462
|
+
* motor `::text` ile döker. D-007'nin kapattığı hata buydu:
|
|
3463
|
+
* 41.00821234567890123 canlıda 41.0082123456789 oluyordu.
|
|
3464
|
+
*
|
|
3465
|
+
* `| null` bir süs değil: Postgres BOŞ kümede NULL döndürür, 0 değil. "Hiç
|
|
3466
|
+
* satır yoktu" ile "toplam sıfırdı" farklı şeyler, ve tip bunu sormaya
|
|
3467
|
+
* ZORLUYOR.
|
|
3468
|
+
*/
|
|
3469
|
+
type SummableCols<Row> = {
|
|
3470
|
+
[K in keyof Row]-?: "?" extends PgTag<Row[K]> ? NonNullable<Row[K]> extends number | string ? K : never : PgKind<PgTag<Row[K]>> extends "num" ? K : never;
|
|
3471
|
+
}[keyof Row];
|
|
3472
|
+
/** `min`/`max` sıralanabilir her kolonda — jsonb ve vektör hariç. */
|
|
3473
|
+
type OrderableCols<Row> = {
|
|
3474
|
+
[K in keyof Row]-?: "?" extends PgTag<Row[K]> ? NonNullable<Row[K]> extends number | string | Date ? K : never : PgTag<Row[K]> extends "jsonb" | "vector" ? never : K;
|
|
3475
|
+
}[keyof Row];
|
|
3476
|
+
type AggCols<Row> = Extract<SummableCols<Row>, string>;
|
|
3477
|
+
type AggOrderCols<Row> = Extract<OrderableCols<Row>, string>;
|
|
3478
|
+
type AggregateInput<Row, Rels = unknown> = {
|
|
3479
|
+
where?: WhereFilter<Row> | SqlFragment | HasBranch<Row, Rels>;
|
|
3480
|
+
/** Toplam — yalnız sayısal kolonlarda; sonuç `string | null` (kayıpsız). */
|
|
3481
|
+
sum?: readonly AggCols<Row>[];
|
|
3482
|
+
/** Ortalama — sonuç `numeric`, yani `string | null`. */
|
|
3483
|
+
avg?: readonly AggCols<Row>[];
|
|
3484
|
+
min?: readonly AggOrderCols<Row>[];
|
|
3485
|
+
max?: readonly AggOrderCols<Row>[];
|
|
3486
|
+
/** Kaç satır — `count()` ile aynı sayı, ama AYNI turda. */
|
|
3487
|
+
count?: boolean;
|
|
3488
|
+
/** Verilirse SATIRLAR döner ve her satır grup kolonlarını taşır. */
|
|
3489
|
+
groupBy?: readonly Extract<keyof Row, string>[];
|
|
3490
|
+
};
|
|
3491
|
+
type AggPart<Q, Row, F extends "sum" | "avg" | "min" | "max"> = Q extends {
|
|
3492
|
+
[K in F]: readonly (infer C extends keyof Row)[];
|
|
3493
|
+
} ? {
|
|
3494
|
+
[P in C]: F extends "sum" | "avg" ? string | null : Row[P] | null;
|
|
3495
|
+
} : never;
|
|
3496
|
+
type AggBody<Q, Row> = ([AggPart<Q, Row, "sum">] extends [never] ? unknown : {
|
|
3497
|
+
sum: AggPart<Q, Row, "sum">;
|
|
3498
|
+
}) & ([AggPart<Q, Row, "avg">] extends [never] ? unknown : {
|
|
3499
|
+
avg: AggPart<Q, Row, "avg">;
|
|
3500
|
+
}) & ([AggPart<Q, Row, "min">] extends [never] ? unknown : {
|
|
3501
|
+
min: AggPart<Q, Row, "min">;
|
|
3502
|
+
}) & ([AggPart<Q, Row, "max">] extends [never] ? unknown : {
|
|
3503
|
+
max: AggPart<Q, Row, "max">;
|
|
3504
|
+
}) & (Q extends {
|
|
3505
|
+
count: true;
|
|
3506
|
+
} ? {
|
|
3507
|
+
count: number;
|
|
3508
|
+
} : unknown);
|
|
3509
|
+
type AggregateResult<Q, Row> = Q extends {
|
|
3510
|
+
groupBy: readonly (infer G extends keyof Row)[];
|
|
3511
|
+
} ? ({
|
|
3512
|
+
[P in G]: Row[P];
|
|
3513
|
+
} & AggBody<Q, Row>)[] : AggBody<Q, Row>;
|
|
3341
3514
|
/** Temel tablo erişimcisi — search'süz beş op. */
|
|
3342
3515
|
interface EnvTypedTableBase<T extends TableTypes> {
|
|
3343
|
-
insert(data: T["insert"]): Promise<T["row"]>;
|
|
3516
|
+
insert(data: InsertValues<T["insert"]>): Promise<T["row"]>;
|
|
3517
|
+
/**
|
|
3518
|
+
* Çok satırı TEK statement'la ekle (tek gidiş-dönüş).
|
|
3519
|
+
*
|
|
3520
|
+
* ```ts
|
|
3521
|
+
* await Database.public.journey_stops.insertMany(
|
|
3522
|
+
* stops.map((s, i) => ({ journey_id, name: s.name, sort_order: i })),
|
|
3523
|
+
* );
|
|
3524
|
+
* ```
|
|
3525
|
+
*
|
|
3526
|
+
* Satırların anahtar kümesi AYNI olmalı: tek statement kolon listesini
|
|
3527
|
+
* paylaşır, yani farklı şekilli bir satırın fazla kolonu sessizce yazılmaz
|
|
3528
|
+
* ve eksiği yanlış sütuna kayardı. Eksik alan için `null` yazın.
|
|
3529
|
+
*
|
|
3530
|
+
* Boş dizi boş sonuç döner — hata değil: "eklenecek bir şey yoktu".
|
|
3531
|
+
*/
|
|
3532
|
+
insertMany(rows: readonly InsertValues<T["insert"]>[], opts?: {
|
|
3533
|
+
/** Çakışmanın ARANDIĞI kolonlar — benzersiz bir kısıt ya da index taşımalı. */
|
|
3534
|
+
onConflict: readonly Extract<keyof T["row"], string>[];
|
|
3535
|
+
/** `"ignore"` (VARSAYILAN, plan yoluyla aynı) çakışanı atlar ve o satır
|
|
3536
|
+
* SONUÇTA DÖNMEZ — Postgres yalnız yazdıklarını döndürür; `"update"`
|
|
3537
|
+
* üzerine yazar. */
|
|
3538
|
+
action?: "ignore" | "update";
|
|
3539
|
+
}): Promise<T["row"][]>;
|
|
3344
3540
|
/**
|
|
3345
3541
|
* Bir idempotency anahtarını sahiplen (FR-033).
|
|
3346
3542
|
*
|
|
@@ -3356,7 +3552,7 @@ interface EnvTypedTableBase<T extends TableTypes> {
|
|
|
3356
3552
|
* İlk argüman satırı BULAN alanlar, ikincisi yalnız yazılanlar — ikinci çağrı
|
|
3357
3553
|
* farklı bir yük gönderse bile satır anahtarla bulunur.
|
|
3358
3554
|
*/
|
|
3359
|
-
claim(unique: Partial<T["insert"]>, extra?: Partial<T["insert"]
|
|
3555
|
+
claim(unique: Partial<T["insert"]>, extra?: Partial<InsertValues<T["insert"]>>): Promise<{
|
|
3360
3556
|
inserted: boolean;
|
|
3361
3557
|
row: T["row"];
|
|
3362
3558
|
}>;
|
|
@@ -3381,7 +3577,7 @@ interface EnvTypedTableBase<T extends TableTypes> {
|
|
|
3381
3577
|
* seçmeyi kolay yapıyordu.
|
|
3382
3578
|
*/
|
|
3383
3579
|
put(q: {
|
|
3384
|
-
data: T["insert"]
|
|
3580
|
+
data: InsertValues<T["insert"]>;
|
|
3385
3581
|
onConflict: readonly Extract<keyof T["row"], string>[];
|
|
3386
3582
|
}): Promise<T["row"]>;
|
|
3387
3583
|
/** Update the row by id; resolves to the updated row, or `null` if no row
|
|
@@ -3391,7 +3587,7 @@ interface EnvTypedTableBase<T extends TableTypes> {
|
|
|
3391
3587
|
where: {
|
|
3392
3588
|
id: string;
|
|
3393
3589
|
};
|
|
3394
|
-
set:
|
|
3590
|
+
set: SetShape<T["insert"]>;
|
|
3395
3591
|
}): Promise<T["row"] | null>;
|
|
3396
3592
|
delete(id: string): Promise<void>;
|
|
3397
3593
|
findById(id: string): Promise<T["row"] | null>;
|
|
@@ -3413,11 +3609,34 @@ interface EnvTypedTableBase<T extends TableTypes> {
|
|
|
3413
3609
|
* if (row === undefined) throw new Conflict("yetersiz bakiye");
|
|
3414
3610
|
* ```
|
|
3415
3611
|
*/
|
|
3416
|
-
updateMany
|
|
3612
|
+
updateMany<const Q extends MutateInput<T["row"], T["insert"], RelsOf<T>>>(q: Q): Promise<Q extends {
|
|
3613
|
+
returning: false;
|
|
3614
|
+
} ? number : T["row"][]>;
|
|
3417
3615
|
/** Delete every matching row; resolves to how many. Empty filter refused. */
|
|
3418
3616
|
deleteMany(q: {
|
|
3419
3617
|
where: WhereFilter<T["row"]> | SqlFragment | HasBranch<T["row"], RelsOf<T>>;
|
|
3420
3618
|
}): Promise<number>;
|
|
3619
|
+
/**
|
|
3620
|
+
* Toplama — `sum` / `avg` / `min` / `max` / `count`, isteğe bağlı `groupBy`.
|
|
3621
|
+
*
|
|
3622
|
+
* ```ts
|
|
3623
|
+
* const r = await Database.public.entries.aggregate({
|
|
3624
|
+
* where: { account_id },
|
|
3625
|
+
* sum: ["amount_kurus"],
|
|
3626
|
+
* count: true,
|
|
3627
|
+
* });
|
|
3628
|
+
* r.sum.amount_kurus; // string | null — KAYIPSIZ
|
|
3629
|
+
* r.count; // number
|
|
3630
|
+
* ```
|
|
3631
|
+
*
|
|
3632
|
+
* `sum`/`avg` yalnız sayısal kolonlarda ve HER ZAMAN `string` döner: para JS
|
|
3633
|
+
* `number`'ına uğradığı anda kesinliğini kaybeder. `| null` çünkü Postgres
|
|
3634
|
+
* boş kümede NULL döndürür — "hiç satır yoktu" ile "toplam sıfırdı" farklı
|
|
3635
|
+
* şeyler ve tip bunu sormaya zorluyor.
|
|
3636
|
+
*
|
|
3637
|
+
* `groupBy` verilirse dönüş bir DİZİ ve her satır grup kolonlarını taşır.
|
|
3638
|
+
*/
|
|
3639
|
+
aggregate<const Q extends AggregateInput<T["row"], RelsOf<T>>>(q: Q): Promise<AggregateResult<Q, T["row"]>>;
|
|
3421
3640
|
/** How many rows match. An empty filter is legitimate: counting is a read. */
|
|
3422
3641
|
count(q?: {
|
|
3423
3642
|
where?: WhereFilter<T["row"]> | SqlFragment | HasBranch<T["row"], RelsOf<T>>;
|
|
@@ -3426,7 +3645,7 @@ interface EnvTypedTableBase<T extends TableTypes> {
|
|
|
3426
3645
|
* kapanır (valid_to/superseded_by), yenisi TEK savepoint'te eklenir; dönüş
|
|
3427
3646
|
* yeni satır. Validity beyanı olmayan tabloda adlandırılmış çalışma-zamanı
|
|
3428
3647
|
* hatası — tip düzeyinde ayrım env `Tables` bayrağı taşımadığından yapılamaz. */
|
|
3429
|
-
supersede(id: string, row: T["insert"]): Promise<T["row"]>;
|
|
3648
|
+
supersede(id: string, row: InsertValues<T["insert"]>): Promise<T["row"]>;
|
|
3430
3649
|
}
|
|
3431
3650
|
/** Tablo erişimcisi: env girdisi `searchable: true` taşıyorsa (vector kolonu ya da
|
|
3432
3651
|
* search beyanı — env-gen üretir) `search()` üyesi VARDIR; yoksa üye hiç yoktur ve
|
|
@@ -4362,6 +4581,22 @@ interface DBOps {
|
|
|
4362
4581
|
*/
|
|
4363
4582
|
query<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>;
|
|
4364
4583
|
insert(table: string, data: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
4584
|
+
/** Çok satır, TEK statement. Satırların anahtar kümesi aynı olmalı — kolon
|
|
4585
|
+
* listesi paylaşıldığı için farklı şekilli bir satırın kolonu sessizce
|
|
4586
|
+
* yazılmazdı. */
|
|
4587
|
+
aggregate(table: string, q: {
|
|
4588
|
+
where?: Record<string, unknown>;
|
|
4589
|
+
sum?: readonly string[];
|
|
4590
|
+
avg?: readonly string[];
|
|
4591
|
+
min?: readonly string[];
|
|
4592
|
+
max?: readonly string[];
|
|
4593
|
+
count?: boolean;
|
|
4594
|
+
groupBy?: readonly string[];
|
|
4595
|
+
}): Promise<Record<string, unknown> | Record<string, unknown>[]>;
|
|
4596
|
+
insertMany(table: string, rows: readonly Record<string, unknown>[], opts?: {
|
|
4597
|
+
onConflict: readonly string[];
|
|
4598
|
+
action?: "ignore" | "update";
|
|
4599
|
+
}): Promise<Record<string, unknown>[]>;
|
|
4365
4600
|
/**
|
|
4366
4601
|
* Insert the row, or update it when it collides on `onConflict` — one
|
|
4367
4602
|
* statement, so two concurrent callers cannot both lose.
|
|
@@ -4435,7 +4670,9 @@ interface DBOps {
|
|
|
4435
4670
|
* yetmedi) — ikisini ayıran tek şey dönen dizidir. Çağrı hata fırlatmadı diye
|
|
4436
4671
|
* işlem oldu SAYILAMAZ; kontrol çağıranın işi.
|
|
4437
4672
|
*/
|
|
4438
|
-
updateMany(table: string, where: Record<string, unknown>, set: Record<string, unknown
|
|
4673
|
+
updateMany(table: string, where: Record<string, unknown>, set: Record<string, unknown>, opts?: {
|
|
4674
|
+
returning?: boolean;
|
|
4675
|
+
}): Promise<Record<string, unknown>[] | number>;
|
|
4439
4676
|
/**
|
|
4440
4677
|
* Bir idempotency anahtarını sahiplen (FR-033).
|
|
4441
4678
|
*
|