@palbase/backend 28.0.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 +151 -12
- package/dist/bin/palbase-backend.cjs.map +1 -1
- package/dist/bin/palbase-backend.js +3 -3
- package/dist/{chunk-75YROPRZ.js → chunk-DHJ3SYAE.js} +152 -15
- package/dist/chunk-DHJ3SYAE.js.map +1 -0
- package/dist/{chunk-IVZERLTM.js → chunk-ENZ2RFFJ.js} +2 -2
- package/dist/{chunk-RVP6BTEZ.js → chunk-ESSQ3YML.js} +13 -4
- package/dist/chunk-ESSQ3YML.js.map +1 -0
- package/dist/{chunk-SNDXY565.js → chunk-SG4UTNOP.js} +5 -2
- package/dist/chunk-SG4UTNOP.js.map +1 -0
- package/dist/db/index.cjs +4 -1
- 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 +2 -2
- package/dist/engine/index.cjs +151 -12
- 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 +3 -3
- package/dist/{index-dTTLlHIn.d.ts → index-BOe82fsK.d.ts} +162 -8
- package/dist/{index-BbvOoZFr.d.ts → index-BYDUKexK.d.ts} +29 -7
- package/dist/{index-9C3JHxg-.d.cts → index-BZfmdRmh.d.cts} +29 -7
- package/dist/{index-DtISj9QX.d.cts → index-ChvoVczS.d.cts} +162 -8
- package/dist/index.cjs +15 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +3 -3
- package/dist/openapi/index.d.cts +2 -2
- package/dist/openapi/index.d.ts +2 -2
- package/dist/{registry-qIPM5BQe.d.cts → registry-B2KfKWv1.d.cts} +1 -1
- package/dist/{registry-JQNIX-eA.d.ts → registry-DaqHsOq8.d.ts} +1 -1
- package/dist/test/index.cjs +56 -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 +56 -0
- package/dist/test/index.js.map +1 -1
- package/docs/README.md +1 -1
- package/docs/database.md +49 -0
- package/docs/llms-full.txt +50 -1
- package/package.json +1 -1
- package/template/package.json +1 -1
- package/dist/chunk-75YROPRZ.js.map +0 -1
- package/dist/chunk-RVP6BTEZ.js.map +0 -1
- package/dist/chunk-SNDXY565.js.map +0 -1
- /package/dist/{chunk-IVZERLTM.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, 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-
|
|
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, 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-
|
|
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,13 +16,13 @@ import {
|
|
|
16
16
|
quoteIdent,
|
|
17
17
|
scrubSecrets,
|
|
18
18
|
withTables
|
|
19
|
-
} from "../chunk-
|
|
19
|
+
} from "../chunk-DHJ3SYAE.js";
|
|
20
20
|
import {
|
|
21
21
|
DECLARATION_REFUSAL,
|
|
22
22
|
DeclarationRefused,
|
|
23
23
|
isDeclarationRefused
|
|
24
|
-
} from "../chunk-
|
|
25
|
-
import "../chunk-
|
|
24
|
+
} from "../chunk-ESSQ3YML.js";
|
|
25
|
+
import "../chunk-SG4UTNOP.js";
|
|
26
26
|
import "../chunk-3TUJWHC2.js";
|
|
27
27
|
import "../chunk-VVMJEVQP.js";
|
|
28
28
|
import "../chunk-CGNN2PUH.js";
|
|
@@ -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. */
|
|
@@ -2864,11 +2876,33 @@ interface TypedTable<T extends TableDef> {
|
|
|
2864
2876
|
* if (row === undefined) throw new Conflict("yetersiz bakiye");
|
|
2865
2877
|
* ```
|
|
2866
2878
|
*/
|
|
2867
|
-
updateMany
|
|
2879
|
+
updateMany<const Q extends MutateInput<RowShape<T>, InsertShape<T>>>(q: Q): Promise<Q extends {
|
|
2880
|
+
returning: false;
|
|
2881
|
+
} ? number : RowShape<T>[]>;
|
|
2868
2882
|
/** Delete every matching row; resolves to how many. Empty filter refused. */
|
|
2869
2883
|
deleteMany(q: {
|
|
2870
2884
|
where: WhereFilter<RowShape<T>> | SqlFragment;
|
|
2871
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>>>;
|
|
2872
2906
|
/** How many rows match. An empty filter is legitimate: counting is a read. */
|
|
2873
2907
|
count(q?: {
|
|
2874
2908
|
where?: WhereFilter<RowShape<T>> | SqlFragment;
|
|
@@ -3020,7 +3054,26 @@ type ColumnsComparableTo<Row, V> = {
|
|
|
3020
3054
|
* `findMany`'nin `Row`'u bilmediği yolların ve jsonb kolonlarının hâli, ve
|
|
3021
3055
|
* ikisinde de tipin söyleyebileceği bir şey yok.
|
|
3022
3056
|
*/
|
|
3023
|
-
|
|
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>>;
|
|
3024
3077
|
/**
|
|
3025
3078
|
* Doğrulanmış, GÖMÜLEBİLİR bir SQL parçası (FR-018, FR-019).
|
|
3026
3079
|
*
|
|
@@ -3281,6 +3334,15 @@ type QueryInput<Row, K extends keyof Row = keyof Row, Rels = unknown> = {
|
|
|
3281
3334
|
type MutateInput<Row, Insert, Rels = unknown> = {
|
|
3282
3335
|
where: WhereFilter<Row> | SqlFragment | HasBranch<Row, Rels>;
|
|
3283
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;
|
|
3284
3346
|
};
|
|
3285
3347
|
/**
|
|
3286
3348
|
* `set`'e yazılabilen değer (FR-012): kolonun kendi tipi ya da — sayısal
|
|
@@ -3391,6 +3453,64 @@ type RecommendParamsTyped<T extends TableTypes> = SimilarParamsTyped<T> & {
|
|
|
3391
3453
|
type RelsOf<T> = T extends {
|
|
3392
3454
|
relations: infer R;
|
|
3393
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>;
|
|
3394
3514
|
/** Temel tablo erişimcisi — search'süz beş op. */
|
|
3395
3515
|
interface EnvTypedTableBase<T extends TableTypes> {
|
|
3396
3516
|
insert(data: InsertValues<T["insert"]>): Promise<T["row"]>;
|
|
@@ -3489,11 +3609,34 @@ interface EnvTypedTableBase<T extends TableTypes> {
|
|
|
3489
3609
|
* if (row === undefined) throw new Conflict("yetersiz bakiye");
|
|
3490
3610
|
* ```
|
|
3491
3611
|
*/
|
|
3492
|
-
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"][]>;
|
|
3493
3615
|
/** Delete every matching row; resolves to how many. Empty filter refused. */
|
|
3494
3616
|
deleteMany(q: {
|
|
3495
3617
|
where: WhereFilter<T["row"]> | SqlFragment | HasBranch<T["row"], RelsOf<T>>;
|
|
3496
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"]>>;
|
|
3497
3640
|
/** How many rows match. An empty filter is legitimate: counting is a read. */
|
|
3498
3641
|
count(q?: {
|
|
3499
3642
|
where?: WhereFilter<T["row"]> | SqlFragment | HasBranch<T["row"], RelsOf<T>>;
|
|
@@ -4441,6 +4584,15 @@ interface DBOps {
|
|
|
4441
4584
|
/** Çok satır, TEK statement. Satırların anahtar kümesi aynı olmalı — kolon
|
|
4442
4585
|
* listesi paylaşıldığı için farklı şekilli bir satırın kolonu sessizce
|
|
4443
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>[]>;
|
|
4444
4596
|
insertMany(table: string, rows: readonly Record<string, unknown>[], opts?: {
|
|
4445
4597
|
onConflict: readonly string[];
|
|
4446
4598
|
action?: "ignore" | "update";
|
|
@@ -4518,7 +4670,9 @@ interface DBOps {
|
|
|
4518
4670
|
* yetmedi) — ikisini ayıran tek şey dönen dizidir. Çağrı hata fırlatmadı diye
|
|
4519
4671
|
* işlem oldu SAYILAMAZ; kontrol çağıranın işi.
|
|
4520
4672
|
*/
|
|
4521
|
-
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>;
|
|
4522
4676
|
/**
|
|
4523
4677
|
* Bir idempotency anahtarını sahiplen (FR-033).
|
|
4524
4678
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { D as DBClient, a as DBOps, T as TxPlanBody, b as TxPlanResponse, A as AuthSpec, C as CacheClient, c as RuntimeServices, _ as __runWithRuntime, d as __requestALS } from './index-
|
|
1
|
+
import { D as DBClient, a as DBOps, T as TxPlanBody, b as TxPlanResponse, A as AuthSpec, C as CacheClient, c as RuntimeServices, _ as __runWithRuntime, d as __requestALS } from './index-BOe82fsK.js';
|
|
2
2
|
import { T as Token } from './module-Dl1KFVtc.js';
|
|
3
|
-
import { R as RouteMeta } from './registry-
|
|
3
|
+
import { R as RouteMeta } from './registry-DaqHsOq8.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* engine/config.ts — settings from the environment, and the gate that refuses
|
|
@@ -291,7 +291,9 @@ declare function createOps(tx: TxLike): {
|
|
|
291
291
|
* should not silently succeed. Callers who mean every row say so with a
|
|
292
292
|
* predicate that is true for every row.
|
|
293
293
|
*/
|
|
294
|
-
updateMany(table: string, where: Row, set: Row
|
|
294
|
+
updateMany(table: string, where: Row, set: Row, opts?: {
|
|
295
|
+
returning?: boolean;
|
|
296
|
+
}): Promise<Row[] | number>;
|
|
295
297
|
/**
|
|
296
298
|
* Delete every row the filter matches, in ONE statement; resolves to how
|
|
297
299
|
* many went. Same filter language, same empty-filter refusal as
|
|
@@ -307,6 +309,27 @@ declare function createOps(tx: TxLike): {
|
|
|
307
309
|
* An empty filter is legitimate HERE: counting a whole table is a read, and
|
|
308
310
|
* reads do not destroy anything.
|
|
309
311
|
*/
|
|
312
|
+
/**
|
|
313
|
+
* Toplama — `count`'un yanına `sum`/`avg`/`min`/`max` ve `groupBy`.
|
|
314
|
+
*
|
|
315
|
+
* Var olma nedeni: bunlar olmadan "bu hesabın toplamı" ya `$query`'ye ya da
|
|
316
|
+
* TÜM satırları çekip JS'te toplamaya düşüyor. İkincisi hem N+1 hem de para
|
|
317
|
+
* için YANLIŞ — `numeric` JS `number`'ına uğradığı anda kesinliğini
|
|
318
|
+
* kaybeder.
|
|
319
|
+
*
|
|
320
|
+
* `groupBy` verilirse SATIRLAR döner, verilmezse TEK sonuç. Boş kümede
|
|
321
|
+
* Postgres NULL döndürür, 0 değil — ve bu SDK onu `null` olarak geçiriyor:
|
|
322
|
+
* "hiç satır yoktu" ile "toplam sıfırdı" farklı şeyler.
|
|
323
|
+
*/
|
|
324
|
+
aggregate(table: string, q?: {
|
|
325
|
+
where?: Row;
|
|
326
|
+
sum?: readonly string[];
|
|
327
|
+
avg?: readonly string[];
|
|
328
|
+
min?: readonly string[];
|
|
329
|
+
max?: readonly string[];
|
|
330
|
+
count?: boolean;
|
|
331
|
+
groupBy?: readonly string[];
|
|
332
|
+
}): Promise<Record<string, unknown> | Record<string, unknown>[]>;
|
|
310
333
|
count(table: string, where?: Row): Promise<number>;
|
|
311
334
|
findById(table: string, id: string): Promise<Row | null>;
|
|
312
335
|
findMany(table: string, query?: Row, opts?: FindManyOptions): Promise<Row[]>;
|
|
@@ -809,6 +832,9 @@ declare class AuthVerifier {
|
|
|
809
832
|
interface EffectiveAuth {
|
|
810
833
|
required: boolean;
|
|
811
834
|
role?: string;
|
|
835
|
+
/** The permission the route demands, as `resource.action`. Resolved against
|
|
836
|
+
* `auth.has_permission(...)` at the gate — see AuthConfig.permission. */
|
|
837
|
+
permission?: string;
|
|
812
838
|
verifiedEmail: boolean;
|
|
813
839
|
}
|
|
814
840
|
/**
|
|
@@ -1028,10 +1054,6 @@ interface App {
|
|
|
1028
1054
|
*/
|
|
1029
1055
|
readonly container: Container;
|
|
1030
1056
|
}
|
|
1031
|
-
/**
|
|
1032
|
-
* Build the app. Fails fast: the database is reached here, at boot, rather than
|
|
1033
|
-
* on the first request that needs it.
|
|
1034
|
-
*/
|
|
1035
1057
|
declare function createApp(opts: CreateAppOptions): Promise<App>;
|
|
1036
1058
|
|
|
1037
1059
|
export { type App as A, BootRefused as B, type Container as C, DECLARATION_REFUSAL as D, type EgressPolicy as E, quoteIdent as F, scrubSecrets as G, withTables as H, type ModuleClients as M, RateLimiter as R, type ScrubResult as S, DeclarationRefused as a, DiError as b, type DiKind as c, type ModulePressure as d, assertNoOrphanEntryPoints as e, buildContainer as f, AuthVerifier as g, type CreateAppOptions as h, isDeclarationRefused as i, type EngineConfig as j, type RequestDatabase as k, type RouteEntry as l, type RuntimeHooks as m, type SqlDriver as n, type SqlTx as o, buildRouteTable as p, createApp as q, createLazyTransaction as r, createOps as s, createRequestDatabase as t, effectiveAuth as u, hostAllowed as v, installEgressFence as w, loadConfig as x, makeMemoryCache as y, matchRoute as z };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { D as DBClient, a as DBOps, T as TxPlanBody, b as TxPlanResponse, A as AuthSpec, C as CacheClient, c as RuntimeServices, _ as __runWithRuntime, d as __requestALS } from './index-
|
|
1
|
+
import { D as DBClient, a as DBOps, T as TxPlanBody, b as TxPlanResponse, A as AuthSpec, C as CacheClient, c as RuntimeServices, _ as __runWithRuntime, d as __requestALS } from './index-ChvoVczS.cjs';
|
|
2
2
|
import { T as Token } from './module-Dl1KFVtc.cjs';
|
|
3
|
-
import { R as RouteMeta } from './registry-
|
|
3
|
+
import { R as RouteMeta } from './registry-B2KfKWv1.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* engine/config.ts — settings from the environment, and the gate that refuses
|
|
@@ -291,7 +291,9 @@ declare function createOps(tx: TxLike): {
|
|
|
291
291
|
* should not silently succeed. Callers who mean every row say so with a
|
|
292
292
|
* predicate that is true for every row.
|
|
293
293
|
*/
|
|
294
|
-
updateMany(table: string, where: Row, set: Row
|
|
294
|
+
updateMany(table: string, where: Row, set: Row, opts?: {
|
|
295
|
+
returning?: boolean;
|
|
296
|
+
}): Promise<Row[] | number>;
|
|
295
297
|
/**
|
|
296
298
|
* Delete every row the filter matches, in ONE statement; resolves to how
|
|
297
299
|
* many went. Same filter language, same empty-filter refusal as
|
|
@@ -307,6 +309,27 @@ declare function createOps(tx: TxLike): {
|
|
|
307
309
|
* An empty filter is legitimate HERE: counting a whole table is a read, and
|
|
308
310
|
* reads do not destroy anything.
|
|
309
311
|
*/
|
|
312
|
+
/**
|
|
313
|
+
* Toplama — `count`'un yanına `sum`/`avg`/`min`/`max` ve `groupBy`.
|
|
314
|
+
*
|
|
315
|
+
* Var olma nedeni: bunlar olmadan "bu hesabın toplamı" ya `$query`'ye ya da
|
|
316
|
+
* TÜM satırları çekip JS'te toplamaya düşüyor. İkincisi hem N+1 hem de para
|
|
317
|
+
* için YANLIŞ — `numeric` JS `number`'ına uğradığı anda kesinliğini
|
|
318
|
+
* kaybeder.
|
|
319
|
+
*
|
|
320
|
+
* `groupBy` verilirse SATIRLAR döner, verilmezse TEK sonuç. Boş kümede
|
|
321
|
+
* Postgres NULL döndürür, 0 değil — ve bu SDK onu `null` olarak geçiriyor:
|
|
322
|
+
* "hiç satır yoktu" ile "toplam sıfırdı" farklı şeyler.
|
|
323
|
+
*/
|
|
324
|
+
aggregate(table: string, q?: {
|
|
325
|
+
where?: Row;
|
|
326
|
+
sum?: readonly string[];
|
|
327
|
+
avg?: readonly string[];
|
|
328
|
+
min?: readonly string[];
|
|
329
|
+
max?: readonly string[];
|
|
330
|
+
count?: boolean;
|
|
331
|
+
groupBy?: readonly string[];
|
|
332
|
+
}): Promise<Record<string, unknown> | Record<string, unknown>[]>;
|
|
310
333
|
count(table: string, where?: Row): Promise<number>;
|
|
311
334
|
findById(table: string, id: string): Promise<Row | null>;
|
|
312
335
|
findMany(table: string, query?: Row, opts?: FindManyOptions): Promise<Row[]>;
|
|
@@ -809,6 +832,9 @@ declare class AuthVerifier {
|
|
|
809
832
|
interface EffectiveAuth {
|
|
810
833
|
required: boolean;
|
|
811
834
|
role?: string;
|
|
835
|
+
/** The permission the route demands, as `resource.action`. Resolved against
|
|
836
|
+
* `auth.has_permission(...)` at the gate — see AuthConfig.permission. */
|
|
837
|
+
permission?: string;
|
|
812
838
|
verifiedEmail: boolean;
|
|
813
839
|
}
|
|
814
840
|
/**
|
|
@@ -1028,10 +1054,6 @@ interface App {
|
|
|
1028
1054
|
*/
|
|
1029
1055
|
readonly container: Container;
|
|
1030
1056
|
}
|
|
1031
|
-
/**
|
|
1032
|
-
* Build the app. Fails fast: the database is reached here, at boot, rather than
|
|
1033
|
-
* on the first request that needs it.
|
|
1034
|
-
*/
|
|
1035
1057
|
declare function createApp(opts: CreateAppOptions): Promise<App>;
|
|
1036
1058
|
|
|
1037
1059
|
export { type App as A, BootRefused as B, type Container as C, DECLARATION_REFUSAL as D, type EgressPolicy as E, quoteIdent as F, scrubSecrets as G, withTables as H, type ModuleClients as M, RateLimiter as R, type ScrubResult as S, DeclarationRefused as a, DiError as b, type DiKind as c, type ModulePressure as d, assertNoOrphanEntryPoints as e, buildContainer as f, AuthVerifier as g, type CreateAppOptions as h, isDeclarationRefused as i, type EngineConfig as j, type RequestDatabase as k, type RouteEntry as l, type RuntimeHooks as m, type SqlDriver as n, type SqlTx as o, buildRouteTable as p, createApp as q, createLazyTransaction as r, createOps as s, createRequestDatabase as t, effectiveAuth as u, hostAllowed as v, installEgressFence as w, loadConfig as x, makeMemoryCache as y, matchRoute as z };
|
|
@@ -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. */
|
|
@@ -2864,11 +2876,33 @@ interface TypedTable<T extends TableDef> {
|
|
|
2864
2876
|
* if (row === undefined) throw new Conflict("yetersiz bakiye");
|
|
2865
2877
|
* ```
|
|
2866
2878
|
*/
|
|
2867
|
-
updateMany
|
|
2879
|
+
updateMany<const Q extends MutateInput<RowShape<T>, InsertShape<T>>>(q: Q): Promise<Q extends {
|
|
2880
|
+
returning: false;
|
|
2881
|
+
} ? number : RowShape<T>[]>;
|
|
2868
2882
|
/** Delete every matching row; resolves to how many. Empty filter refused. */
|
|
2869
2883
|
deleteMany(q: {
|
|
2870
2884
|
where: WhereFilter<RowShape<T>> | SqlFragment;
|
|
2871
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>>>;
|
|
2872
2906
|
/** How many rows match. An empty filter is legitimate: counting is a read. */
|
|
2873
2907
|
count(q?: {
|
|
2874
2908
|
where?: WhereFilter<RowShape<T>> | SqlFragment;
|
|
@@ -3020,7 +3054,26 @@ type ColumnsComparableTo<Row, V> = {
|
|
|
3020
3054
|
* `findMany`'nin `Row`'u bilmediği yolların ve jsonb kolonlarının hâli, ve
|
|
3021
3055
|
* ikisinde de tipin söyleyebileceği bir şey yok.
|
|
3022
3056
|
*/
|
|
3023
|
-
|
|
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>>;
|
|
3024
3077
|
/**
|
|
3025
3078
|
* Doğrulanmış, GÖMÜLEBİLİR bir SQL parçası (FR-018, FR-019).
|
|
3026
3079
|
*
|
|
@@ -3281,6 +3334,15 @@ type QueryInput<Row, K extends keyof Row = keyof Row, Rels = unknown> = {
|
|
|
3281
3334
|
type MutateInput<Row, Insert, Rels = unknown> = {
|
|
3282
3335
|
where: WhereFilter<Row> | SqlFragment | HasBranch<Row, Rels>;
|
|
3283
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;
|
|
3284
3346
|
};
|
|
3285
3347
|
/**
|
|
3286
3348
|
* `set`'e yazılabilen değer (FR-012): kolonun kendi tipi ya da — sayısal
|
|
@@ -3391,6 +3453,64 @@ type RecommendParamsTyped<T extends TableTypes> = SimilarParamsTyped<T> & {
|
|
|
3391
3453
|
type RelsOf<T> = T extends {
|
|
3392
3454
|
relations: infer R;
|
|
3393
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>;
|
|
3394
3514
|
/** Temel tablo erişimcisi — search'süz beş op. */
|
|
3395
3515
|
interface EnvTypedTableBase<T extends TableTypes> {
|
|
3396
3516
|
insert(data: InsertValues<T["insert"]>): Promise<T["row"]>;
|
|
@@ -3489,11 +3609,34 @@ interface EnvTypedTableBase<T extends TableTypes> {
|
|
|
3489
3609
|
* if (row === undefined) throw new Conflict("yetersiz bakiye");
|
|
3490
3610
|
* ```
|
|
3491
3611
|
*/
|
|
3492
|
-
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"][]>;
|
|
3493
3615
|
/** Delete every matching row; resolves to how many. Empty filter refused. */
|
|
3494
3616
|
deleteMany(q: {
|
|
3495
3617
|
where: WhereFilter<T["row"]> | SqlFragment | HasBranch<T["row"], RelsOf<T>>;
|
|
3496
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"]>>;
|
|
3497
3640
|
/** How many rows match. An empty filter is legitimate: counting is a read. */
|
|
3498
3641
|
count(q?: {
|
|
3499
3642
|
where?: WhereFilter<T["row"]> | SqlFragment | HasBranch<T["row"], RelsOf<T>>;
|
|
@@ -4441,6 +4584,15 @@ interface DBOps {
|
|
|
4441
4584
|
/** Çok satır, TEK statement. Satırların anahtar kümesi aynı olmalı — kolon
|
|
4442
4585
|
* listesi paylaşıldığı için farklı şekilli bir satırın kolonu sessizce
|
|
4443
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>[]>;
|
|
4444
4596
|
insertMany(table: string, rows: readonly Record<string, unknown>[], opts?: {
|
|
4445
4597
|
onConflict: readonly string[];
|
|
4446
4598
|
action?: "ignore" | "update";
|
|
@@ -4518,7 +4670,9 @@ interface DBOps {
|
|
|
4518
4670
|
* yetmedi) — ikisini ayıran tek şey dönen dizidir. Çağrı hata fırlatmadı diye
|
|
4519
4671
|
* işlem oldu SAYILAMAZ; kontrol çağıranın işi.
|
|
4520
4672
|
*/
|
|
4521
|
-
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>;
|
|
4522
4676
|
/**
|
|
4523
4677
|
* Bir idempotency anahtarını sahiplen (FR-033).
|
|
4524
4678
|
*
|