@flaredev/core 0.4.1 → 0.5.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/index.d.ts +22 -2
- package/dist/index.js +1 -1
- package/dist/server.d.ts +124 -9
- package/dist/server.js +254 -97
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -125,6 +125,22 @@ interface StorageBucket {
|
|
|
125
125
|
};
|
|
126
126
|
}): Promise<unknown>;
|
|
127
127
|
delete(keys: string | string[]): Promise<void>;
|
|
128
|
+
/**
|
|
129
|
+
* The keys in the bucket, a page at a time. R2 counts this as a Class A operation —
|
|
130
|
+
* the expensive kind — so call it to answer a question, not on a page people reload.
|
|
131
|
+
*/
|
|
132
|
+
list?(options?: {
|
|
133
|
+
limit?: number;
|
|
134
|
+
prefix?: string;
|
|
135
|
+
cursor?: string;
|
|
136
|
+
}): Promise<{
|
|
137
|
+
objects: {
|
|
138
|
+
key: string;
|
|
139
|
+
size: number;
|
|
140
|
+
}[];
|
|
141
|
+
truncated: boolean;
|
|
142
|
+
cursor?: string;
|
|
143
|
+
}>;
|
|
128
144
|
}
|
|
129
145
|
interface StorageObjectBody {
|
|
130
146
|
body: ReadableStream;
|
|
@@ -497,7 +513,11 @@ declare const fake: Fake;
|
|
|
497
513
|
*/
|
|
498
514
|
type InsertMany = <T extends object>(table: unknown, count: number | readonly T[], build?: (index: number) => T) => Promise<number>;
|
|
499
515
|
interface SeedContext {
|
|
500
|
-
/**
|
|
516
|
+
/**
|
|
517
|
+
* The app's database client: Drizzle over the local D1 database on Cloudflare, the
|
|
518
|
+
* app's own Prisma client on Next.js. Untyped, because which one it is depends on
|
|
519
|
+
* the stack and both are generated per app.
|
|
520
|
+
*/
|
|
501
521
|
db: any;
|
|
502
522
|
/** All local bindings and variables (D1, R2, .dev.vars). */
|
|
503
523
|
env: Record<string, unknown>;
|
|
@@ -509,6 +529,6 @@ interface SeedContext {
|
|
|
509
529
|
type Seed = (context: SeedContext) => void | Promise<void>;
|
|
510
530
|
declare function defineSeed(seed: Seed): Seed;
|
|
511
531
|
|
|
512
|
-
declare const FLARE_VERSION = "0.
|
|
532
|
+
declare const FLARE_VERSION = "0.5.0";
|
|
513
533
|
|
|
514
534
|
export { type BelongsToRelation, type Country, CreateInput, FLARE_VERSION, type Fake, Field, type FormValues, type FormatOptions, type HasManyRelation, type InsertMany, type MailMessage, type MailResult, type Mailer, type MailerOptions, PBKDF2_ITERATIONS, type ReadUrlOptions, RelationError, type RelationGraph, Resource, type ResourceRelations, type ResourceValidators, SNIFF_BYTES, SUBSCRIPTION_STATUSES, type Seed, type SeedContext, type Storage, type StorageBucket, type StorageOptions, StoredField, type SubscriptionLike, type SubscriptionState, type SubscriptionStatus, type Tone, type TransactionalEmail, UpdateInput, type UploadUrlOptions, camelCase, checkoutPaid, countries, countryName, createFake, createMailer, createObjectKey, createStorage, createValidators, currentPeriodEnd, defineSeed, fake, fieldSchema, fileKeyPrefix, flagEmoji, formValuesToInput, formatPhone, formatValue, grantsAccess, hashPassword, humanize, importSigningKey, initialFormValues, isColor, isCountryCode, isDomain, isLiveSubscription, isPhoneNumber, isSlug, issuesByField, kebabCase, matchesContentType, normalizeDomain, optionLabel, parseMultiValue, pascalCase, pluralize, randomLetters, relationGraph, renderTransactionalEmail, shouldApplySubscription, signToken, slugify, snakeCase, sniffMatches, splitPhone, statusTone, subscriptionPriceId, subscriptionState, toE164, toSubscriptionStatus, verifyPassword, verifyToken, words };
|
package/dist/index.js
CHANGED
package/dist/server.d.ts
CHANGED
|
@@ -1,7 +1,83 @@
|
|
|
1
1
|
import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
|
|
2
|
-
import { BaseSQLiteDatabase, SQLiteTable } from 'drizzle-orm/sqlite-core';
|
|
2
|
+
import { BaseSQLiteDatabase, SQLiteTable, SQLiteColumn } from 'drizzle-orm/sqlite-core';
|
|
3
3
|
import { S as StoredField, R as Resource, F as Field, P as Policy } from './policy-DaKcWZ5g.js';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* The handful of things a resource store needs a database to do.
|
|
7
|
+
*
|
|
8
|
+
* Everything that makes a Flare resource behave the way it does — validation, hooks,
|
|
9
|
+
* computed values, cursors, capped counts, the wording of a constraint error — lives in
|
|
10
|
+
* the store and is the same on every stack. What differs is how rows are actually read
|
|
11
|
+
* and written, and that is this interface: nine operations, described in the
|
|
12
|
+
* descriptor's terms rather than in SQL.
|
|
13
|
+
*
|
|
14
|
+
* Drizzle over SQLite is one implementation; Prisma over Postgres is another. A store
|
|
15
|
+
* built on either behaves identically, which is the whole point — the same descriptor
|
|
16
|
+
* has to mean the same thing on Cloudflare and on Vercel.
|
|
17
|
+
*/
|
|
18
|
+
type Row = Record<string, unknown>;
|
|
19
|
+
/** What a list needs, before it becomes SQL. */
|
|
20
|
+
interface RowsQuery {
|
|
21
|
+
/** Free-text search across the fields the descriptor marks searchable. */
|
|
22
|
+
search?: {
|
|
23
|
+
term: string;
|
|
24
|
+
fields: string[];
|
|
25
|
+
};
|
|
26
|
+
/** field → value, or null for "is null". */
|
|
27
|
+
filters: Record<string, unknown>;
|
|
28
|
+
sort: {
|
|
29
|
+
field: string;
|
|
30
|
+
direction: "asc" | "desc";
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Keyset pagination: everything after (or before) this row, compared on
|
|
34
|
+
* `(sort field, id)` together so rows sharing a sort value are neither skipped nor
|
|
35
|
+
* repeated.
|
|
36
|
+
*/
|
|
37
|
+
cursor?: {
|
|
38
|
+
field: string;
|
|
39
|
+
value: unknown;
|
|
40
|
+
id: string;
|
|
41
|
+
greaterThan: boolean;
|
|
42
|
+
};
|
|
43
|
+
limit: number;
|
|
44
|
+
/** Offset paging, for the page-number case. Never combined with a cursor. */
|
|
45
|
+
offset?: number;
|
|
46
|
+
}
|
|
47
|
+
/** A database refusing a write, in terms the store can turn into a message. */
|
|
48
|
+
type ConstraintHit = {
|
|
49
|
+
kind: "unique";
|
|
50
|
+
column?: string;
|
|
51
|
+
} | {
|
|
52
|
+
kind: "foreignKey";
|
|
53
|
+
} | {
|
|
54
|
+
kind: "check";
|
|
55
|
+
};
|
|
56
|
+
interface ResourceRows {
|
|
57
|
+
/** The database handle a descriptor's hooks are given. Drizzle, or a Prisma client. */
|
|
58
|
+
readonly db: unknown;
|
|
59
|
+
find(query: RowsQuery): Promise<Row[]>;
|
|
60
|
+
/** How many rows match, giving up at `limit` so a huge table is never fully counted. */
|
|
61
|
+
countUpTo(query: Pick<RowsQuery, "search" | "filters">, limit: number): Promise<number>;
|
|
62
|
+
byId(id: string): Promise<Row | null>;
|
|
63
|
+
titles(ids: string[], titleField: string): Promise<{
|
|
64
|
+
id: string;
|
|
65
|
+
title: unknown;
|
|
66
|
+
}[]>;
|
|
67
|
+
insert(values: Row): Promise<Row>;
|
|
68
|
+
/** The saved row, or null when there was nothing with that id. */
|
|
69
|
+
update(id: string, values: Row): Promise<Row | null>;
|
|
70
|
+
/** Whether a row was actually removed. */
|
|
71
|
+
remove(id: string): Promise<boolean>;
|
|
72
|
+
/** Recognise a constraint violation, or hand the error back by returning undefined. */
|
|
73
|
+
constraint(error: unknown): ConstraintHit | undefined;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
type AnyDatabase = BaseSQLiteDatabase<"sync" | "async", any, any>;
|
|
77
|
+
declare function drizzleRows(table: SQLiteTable, getDb: () => AnyDatabase): ResourceRows & {
|
|
78
|
+
columns: Record<string, SQLiteColumn>;
|
|
79
|
+
};
|
|
80
|
+
|
|
5
81
|
interface ListQuery {
|
|
6
82
|
page: number;
|
|
7
83
|
perPage: number;
|
|
@@ -44,7 +120,6 @@ declare function parseListQuery(resource: Resource, params: URLSearchParams): {
|
|
|
44
120
|
issues: QueryIssue[];
|
|
45
121
|
};
|
|
46
122
|
|
|
47
|
-
type AnyDatabase = BaseSQLiteDatabase<"sync" | "async", any, any>;
|
|
48
123
|
type ResourceAction = "list" | "read" | "create" | "update" | "delete";
|
|
49
124
|
interface FieldIssue {
|
|
50
125
|
/** Dotted field path; "" for the whole body (e.g. unknown keys). */
|
|
@@ -106,8 +181,14 @@ interface ResourceStoreOptions {
|
|
|
106
181
|
email: string;
|
|
107
182
|
role?: string | null;
|
|
108
183
|
} | null;
|
|
109
|
-
|
|
110
|
-
|
|
184
|
+
/**
|
|
185
|
+
* The Drizzle table and database, for the Cloudflare stack. Another stack passes
|
|
186
|
+
* `rows` instead — a Prisma-backed one, say — and everything else is identical.
|
|
187
|
+
*/
|
|
188
|
+
table?: SQLiteTable;
|
|
189
|
+
getDb?: () => AnyDatabase;
|
|
190
|
+
/** Where rows come from, when it isn't Drizzle. */
|
|
191
|
+
rows?: ResourceRows;
|
|
111
192
|
/**
|
|
112
193
|
* Called after a write succeeds, for cache invalidation. Runs before the
|
|
113
194
|
* operation returns, so a caller that revalidates tags can't hand back a
|
|
@@ -124,7 +205,7 @@ interface ResourceStoreOptions {
|
|
|
124
205
|
*/
|
|
125
206
|
declare function createResourceStore(options: ResourceStoreOptions): {
|
|
126
207
|
resource: Resource<Record<string, Field>>;
|
|
127
|
-
table: SQLiteTable<drizzle_orm_sqlite_core.TableConfig
|
|
208
|
+
table: SQLiteTable<drizzle_orm_sqlite_core.TableConfig> | undefined;
|
|
128
209
|
/** `params`: page, perPage, sort, q, filter[field], cursor (as parsed by parseListQuery). */
|
|
129
210
|
list(params: URLSearchParams): Promise<Result<ListResult>>;
|
|
130
211
|
get(id: string): Promise<Result<Record<string, unknown>>>;
|
|
@@ -151,8 +232,11 @@ interface AuthorizeContext {
|
|
|
151
232
|
type Authorize = (context: AuthorizeContext) => Response | void | Promise<Response | void>;
|
|
152
233
|
interface ResourceHandlerOptions {
|
|
153
234
|
resource: Resource;
|
|
154
|
-
|
|
155
|
-
|
|
235
|
+
/** Drizzle and D1, on the Cloudflare stack. Another stack passes `rows` instead. */
|
|
236
|
+
table?: SQLiteTable;
|
|
237
|
+
getDb?: () => AnyDatabase;
|
|
238
|
+
/** Where rows come from, when it isn't Drizzle — a Prisma-backed adapter, say. */
|
|
239
|
+
rows?: ResourceRows;
|
|
156
240
|
authorize: Authorize;
|
|
157
241
|
/** Who is making the request, for the descriptor's hooks. */
|
|
158
242
|
currentUser?: ResourceStoreOptions["currentUser"];
|
|
@@ -178,7 +262,7 @@ declare function createResourceHandlers(options: ResourceHandlerOptions): {
|
|
|
178
262
|
};
|
|
179
263
|
store: {
|
|
180
264
|
resource: Resource<Record<string, Field>>;
|
|
181
|
-
table: SQLiteTable<drizzle_orm_sqlite_core.TableConfig
|
|
265
|
+
table: SQLiteTable<drizzle_orm_sqlite_core.TableConfig> | undefined;
|
|
182
266
|
list(params: URLSearchParams): Promise<Result<ListResult>>;
|
|
183
267
|
get(id: string): Promise<Result<Record<string, unknown>>>;
|
|
184
268
|
titles(ids: string[]): Promise<Record<string, string>>;
|
|
@@ -191,6 +275,37 @@ declare function createResourceHandlers(options: ResourceHandlerOptions): {
|
|
|
191
275
|
};
|
|
192
276
|
};
|
|
193
277
|
|
|
278
|
+
/**
|
|
279
|
+
* {@link ResourceRows} over Prisma and Postgres — the Next.js stack's half.
|
|
280
|
+
*
|
|
281
|
+
* The same nine operations the Drizzle adapter implements, expressed as Prisma queries.
|
|
282
|
+
* Everything a resource *means* — validation, hooks, computed values, the capped count,
|
|
283
|
+
* the wording of a unique-constraint error — stays in the store and is shared, so a
|
|
284
|
+
* descriptor behaves the same on either stack.
|
|
285
|
+
*
|
|
286
|
+
* Nothing here imports `@prisma/client`: a generated client is app-specific and this
|
|
287
|
+
* package can't depend on one. The delegate is described structurally instead, which is
|
|
288
|
+
* also what makes it easy to test without a database.
|
|
289
|
+
*/
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* The part of a Prisma model delegate a resource store uses.
|
|
293
|
+
*
|
|
294
|
+
* The arguments are loose on purpose. Prisma generates a precise argument type per
|
|
295
|
+
* model — `Prisma.ProductFindManyArgs` and so on — and describing them here would mean
|
|
296
|
+
* reproducing Prisma's generics for a client this package can't import. The queries are
|
|
297
|
+
* all built in this file, so there is exactly one place to get them right.
|
|
298
|
+
*/
|
|
299
|
+
interface PrismaDelegate {
|
|
300
|
+
findMany(args: any): Promise<any[]>;
|
|
301
|
+
findUnique(args: any): Promise<any>;
|
|
302
|
+
count(args: any): Promise<number>;
|
|
303
|
+
create(args: any): Promise<any>;
|
|
304
|
+
update(args: any): Promise<any>;
|
|
305
|
+
delete(args: any): Promise<any>;
|
|
306
|
+
}
|
|
307
|
+
declare function prismaRows(delegate: PrismaDelegate, client: unknown): ResourceRows;
|
|
308
|
+
|
|
194
309
|
/**
|
|
195
310
|
* An OpenAPI 3.1 document for an app's generated REST API, built at request time
|
|
196
311
|
* from the same descriptors and policies the API itself runs on, so it can't drift.
|
|
@@ -218,4 +333,4 @@ interface OpenApiOptions {
|
|
|
218
333
|
declare function fieldJsonSchema(def: StoredField): Schema;
|
|
219
334
|
declare function openApiDocument(options: OpenApiOptions): Schema;
|
|
220
335
|
|
|
221
|
-
export { type AnyDatabase, type Authorize, type AuthorizeContext, type ChangeEvent, type Failure, type FieldIssue, type ListQuery, type ListResult, type OpenApiOptions, type QueryIssue, type ResourceAction, type ResourceHandlerOptions, type ResourceStore, type ResourceStoreOptions, type Result, createResourceHandlers, createResourceStore, fieldJsonSchema, isFilterable, isSearchable, isSortable, openApiDocument, parseListQuery };
|
|
336
|
+
export { type AnyDatabase, type Authorize, type AuthorizeContext, type ChangeEvent, type ConstraintHit, type Failure, type FieldIssue, type ListQuery, type ListResult, type OpenApiOptions, type PrismaDelegate, type QueryIssue, type ResourceAction, type ResourceHandlerOptions, type ResourceRows, type ResourceStore, type ResourceStoreOptions, type Result, type Row, type RowsQuery, createResourceHandlers, createResourceStore, drizzleRows, fieldJsonSchema, isFilterable, isSearchable, isSortable, openApiDocument, parseListQuery, prismaRows };
|
package/dist/server.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
can,
|
|
3
|
+
columnName,
|
|
3
4
|
createValidators,
|
|
4
5
|
storedFields
|
|
5
6
|
} from "./chunk-VLHPSNQN.js";
|
|
6
7
|
|
|
7
|
-
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@
|
|
8
|
+
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/entity.js
|
|
8
9
|
var entityKind = /* @__PURE__ */ Symbol.for("drizzle:entityKind");
|
|
9
10
|
function is(value, type) {
|
|
10
11
|
if (!value || typeof value !== "object") {
|
|
@@ -30,7 +31,7 @@ function is(value, type) {
|
|
|
30
31
|
return false;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@
|
|
34
|
+
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/column.js
|
|
34
35
|
var Column = class {
|
|
35
36
|
constructor(table, config) {
|
|
36
37
|
this.table = table;
|
|
@@ -81,7 +82,7 @@ var Column = class {
|
|
|
81
82
|
}
|
|
82
83
|
};
|
|
83
84
|
|
|
84
|
-
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@
|
|
85
|
+
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/column-builder.js
|
|
85
86
|
var ColumnBuilder = class {
|
|
86
87
|
static [entityKind] = "ColumnBuilder";
|
|
87
88
|
config;
|
|
@@ -184,10 +185,10 @@ var ColumnBuilder = class {
|
|
|
184
185
|
}
|
|
185
186
|
};
|
|
186
187
|
|
|
187
|
-
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@
|
|
188
|
+
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/table.utils.js
|
|
188
189
|
var TableName = /* @__PURE__ */ Symbol.for("drizzle:Name");
|
|
189
190
|
|
|
190
|
-
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@
|
|
191
|
+
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/pg-core/foreign-keys.js
|
|
191
192
|
var ForeignKeyBuilder = class {
|
|
192
193
|
static [entityKind] = "PgForeignKeyBuilder";
|
|
193
194
|
/** @internal */
|
|
@@ -244,12 +245,12 @@ var ForeignKey = class {
|
|
|
244
245
|
}
|
|
245
246
|
};
|
|
246
247
|
|
|
247
|
-
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@
|
|
248
|
+
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/tracing-utils.js
|
|
248
249
|
function iife(fn, ...args) {
|
|
249
250
|
return fn(...args);
|
|
250
251
|
}
|
|
251
252
|
|
|
252
|
-
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@
|
|
253
|
+
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/pg-core/unique-constraint.js
|
|
253
254
|
function uniqueKeyName(table, columns) {
|
|
254
255
|
return `${table[TableName]}_${columns.join("_")}_unique`;
|
|
255
256
|
}
|
|
@@ -299,7 +300,7 @@ var UniqueConstraint = class {
|
|
|
299
300
|
}
|
|
300
301
|
};
|
|
301
302
|
|
|
302
|
-
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@
|
|
303
|
+
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/pg-core/utils/array.js
|
|
303
304
|
function parsePgArrayValue(arrayString, startFrom, inQuotes) {
|
|
304
305
|
for (let i = startFrom; i < arrayString.length; i++) {
|
|
305
306
|
const char = arrayString[i];
|
|
@@ -375,7 +376,7 @@ function makePgArray(array) {
|
|
|
375
376
|
}).join(",")}}`;
|
|
376
377
|
}
|
|
377
378
|
|
|
378
|
-
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@
|
|
379
|
+
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/pg-core/columns/common.js
|
|
379
380
|
var PgColumnBuilder = class extends ColumnBuilder {
|
|
380
381
|
foreignKeyConfigs = [];
|
|
381
382
|
static [entityKind] = "PgColumnBuilder";
|
|
@@ -559,7 +560,7 @@ var PgArray = class _PgArray extends PgColumn {
|
|
|
559
560
|
}
|
|
560
561
|
};
|
|
561
562
|
|
|
562
|
-
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@
|
|
563
|
+
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/pg-core/columns/enum.js
|
|
563
564
|
var PgEnumObjectColumnBuilder = class extends PgColumnBuilder {
|
|
564
565
|
static [entityKind] = "PgEnumObjectColumnBuilder";
|
|
565
566
|
constructor(name, enumInstance) {
|
|
@@ -617,7 +618,7 @@ var PgEnumColumn = class extends PgColumn {
|
|
|
617
618
|
}
|
|
618
619
|
};
|
|
619
620
|
|
|
620
|
-
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@
|
|
621
|
+
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/subquery.js
|
|
621
622
|
var Subquery = class {
|
|
622
623
|
static [entityKind] = "Subquery";
|
|
623
624
|
constructor(sql2, fields, alias, isWith = false, usedTables = []) {
|
|
@@ -638,10 +639,10 @@ var WithSubquery = class extends Subquery {
|
|
|
638
639
|
static [entityKind] = "WithSubquery";
|
|
639
640
|
};
|
|
640
641
|
|
|
641
|
-
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@
|
|
642
|
+
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/version.js
|
|
642
643
|
var version = "0.45.2";
|
|
643
644
|
|
|
644
|
-
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@
|
|
645
|
+
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/tracing.js
|
|
645
646
|
var otel;
|
|
646
647
|
var rawTracer;
|
|
647
648
|
var tracer = {
|
|
@@ -676,10 +677,10 @@ var tracer = {
|
|
|
676
677
|
}
|
|
677
678
|
};
|
|
678
679
|
|
|
679
|
-
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@
|
|
680
|
+
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/view-common.js
|
|
680
681
|
var ViewBaseConfig = /* @__PURE__ */ Symbol.for("drizzle:ViewBaseConfig");
|
|
681
682
|
|
|
682
|
-
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@
|
|
683
|
+
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/table.js
|
|
683
684
|
var Schema = /* @__PURE__ */ Symbol.for("drizzle:Schema");
|
|
684
685
|
var Columns = /* @__PURE__ */ Symbol.for("drizzle:Columns");
|
|
685
686
|
var ExtraConfigColumns = /* @__PURE__ */ Symbol.for("drizzle:ExtraConfigColumns");
|
|
@@ -735,7 +736,7 @@ var Table = class {
|
|
|
735
736
|
}
|
|
736
737
|
};
|
|
737
738
|
|
|
738
|
-
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@
|
|
739
|
+
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/sql/sql.js
|
|
739
740
|
var FakePrimitiveParam = class {
|
|
740
741
|
static [entityKind] = "FakePrimitiveParam";
|
|
741
742
|
};
|
|
@@ -847,13 +848,13 @@ var SQL = class _SQL {
|
|
|
847
848
|
};
|
|
848
849
|
}
|
|
849
850
|
if (is(chunk, Column)) {
|
|
850
|
-
const
|
|
851
|
+
const columnName2 = casing.getColumnCasing(chunk);
|
|
851
852
|
if (_config.invokeSource === "indexes") {
|
|
852
|
-
return { sql: escapeName(
|
|
853
|
+
return { sql: escapeName(columnName2), params: [] };
|
|
853
854
|
}
|
|
854
855
|
const schemaName = chunk.table[Table.Symbol.Schema];
|
|
855
856
|
return {
|
|
856
|
-
sql: chunk.table[IsAlias] || schemaName === void 0 ? escapeName(chunk.table[Table.Symbol.Name]) + "." + escapeName(
|
|
857
|
+
sql: chunk.table[IsAlias] || schemaName === void 0 ? escapeName(chunk.table[Table.Symbol.Name]) + "." + escapeName(columnName2) : escapeName(schemaName) + "." + escapeName(chunk.table[Table.Symbol.Name]) + "." + escapeName(columnName2),
|
|
857
858
|
params: []
|
|
858
859
|
};
|
|
859
860
|
}
|
|
@@ -1112,13 +1113,13 @@ Subquery.prototype.getSQL = function() {
|
|
|
1112
1113
|
return new SQL([this]);
|
|
1113
1114
|
};
|
|
1114
1115
|
|
|
1115
|
-
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@
|
|
1116
|
+
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/utils.js
|
|
1116
1117
|
function getTableColumns(table) {
|
|
1117
1118
|
return table[Table.Symbol.Columns];
|
|
1118
1119
|
}
|
|
1119
1120
|
var textDecoder = typeof TextDecoder === "undefined" ? null : new TextDecoder();
|
|
1120
1121
|
|
|
1121
|
-
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@
|
|
1122
|
+
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/sql/expressions/conditions.js
|
|
1122
1123
|
function bindIfParam(value, column) {
|
|
1123
1124
|
if (isDriverValueEncoder(column) && !isSQLWrapper(value) && !is(value, Param) && !is(value, Placeholder) && !is(value, Column) && !is(value, Table) && !is(value, View)) {
|
|
1124
1125
|
return new Param(value, column);
|
|
@@ -1173,7 +1174,7 @@ function isNull(value) {
|
|
|
1173
1174
|
return sql`${value} is null`;
|
|
1174
1175
|
}
|
|
1175
1176
|
|
|
1176
|
-
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@
|
|
1177
|
+
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/sql/expressions/select.js
|
|
1177
1178
|
function asc(column) {
|
|
1178
1179
|
return sql`${column} asc`;
|
|
1179
1180
|
}
|
|
@@ -1181,11 +1182,101 @@ function desc(column) {
|
|
|
1181
1182
|
return sql`${column} desc`;
|
|
1182
1183
|
}
|
|
1183
1184
|
|
|
1184
|
-
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@
|
|
1185
|
+
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/sql/functions/aggregate.js
|
|
1185
1186
|
function count(expression) {
|
|
1186
1187
|
return sql`count(${expression || sql.raw("*")})`.mapWith(Number);
|
|
1187
1188
|
}
|
|
1188
1189
|
|
|
1190
|
+
// src/server/drizzle-rows.ts
|
|
1191
|
+
function errorText(error) {
|
|
1192
|
+
const parts = [];
|
|
1193
|
+
for (let current = error, depth = 0; current && depth < 5; depth++) {
|
|
1194
|
+
if (current instanceof Error) {
|
|
1195
|
+
parts.push(current.message);
|
|
1196
|
+
current = current.cause;
|
|
1197
|
+
} else {
|
|
1198
|
+
parts.push(String(current));
|
|
1199
|
+
break;
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
return parts.join(" | ");
|
|
1203
|
+
}
|
|
1204
|
+
function drizzleRows(table, getDb) {
|
|
1205
|
+
const columns = getTableColumns(table);
|
|
1206
|
+
const idColumn = columns.id;
|
|
1207
|
+
const byId = (id) => eq(idColumn, id);
|
|
1208
|
+
function matching(query) {
|
|
1209
|
+
const conditions = [];
|
|
1210
|
+
if (query.search && query.search.fields.length > 0) {
|
|
1211
|
+
const pattern = `%${query.search.term.replace(/[\\%_]/g, (char) => `\\${char}`)}%`;
|
|
1212
|
+
const searchable = query.search.fields.map((key) => columns[key]);
|
|
1213
|
+
conditions.push(or(...searchable.map((column) => sql`${column} LIKE ${pattern} ESCAPE '\\'`)));
|
|
1214
|
+
}
|
|
1215
|
+
for (const [key, value] of Object.entries(query.filters)) {
|
|
1216
|
+
conditions.push(value === null ? isNull(columns[key]) : eq(columns[key], value));
|
|
1217
|
+
}
|
|
1218
|
+
return conditions;
|
|
1219
|
+
}
|
|
1220
|
+
return {
|
|
1221
|
+
columns,
|
|
1222
|
+
get db() {
|
|
1223
|
+
return getDb();
|
|
1224
|
+
},
|
|
1225
|
+
async find(query) {
|
|
1226
|
+
const conditions = matching(query);
|
|
1227
|
+
const sortColumn = columns[query.sort.field];
|
|
1228
|
+
const descending = query.sort.direction === "desc";
|
|
1229
|
+
const order = descending ? [desc(sortColumn), desc(idColumn)] : [asc(sortColumn), asc(idColumn)];
|
|
1230
|
+
if (query.cursor) {
|
|
1231
|
+
const { value, id, greaterThan } = query.cursor;
|
|
1232
|
+
conditions.push(
|
|
1233
|
+
greaterThan ? or(sql`${sortColumn} > ${value}`, and(sql`${sortColumn} = ${value}`, sql`${idColumn} > ${id}`)) : or(sql`${sortColumn} < ${value}`, and(sql`${sortColumn} = ${value}`, sql`${idColumn} < ${id}`))
|
|
1234
|
+
);
|
|
1235
|
+
}
|
|
1236
|
+
const where = conditions.length ? and(...conditions) : void 0;
|
|
1237
|
+
const statement = getDb().select().from(table).where(where).orderBy(...order).limit(query.limit);
|
|
1238
|
+
const rows = query.offset ? await statement.offset(query.offset) : await statement;
|
|
1239
|
+
return rows;
|
|
1240
|
+
},
|
|
1241
|
+
async countUpTo(query, limit) {
|
|
1242
|
+
const conditions = matching(query);
|
|
1243
|
+
const where = conditions.length ? and(...conditions) : void 0;
|
|
1244
|
+
const db = getDb();
|
|
1245
|
+
const [counted] = await db.select({ total: count() }).from(db.select({ id: idColumn }).from(table).where(where).limit(limit).as("capped"));
|
|
1246
|
+
return counted?.total ?? 0;
|
|
1247
|
+
},
|
|
1248
|
+
async byId(id) {
|
|
1249
|
+
const [record] = await getDb().select().from(table).where(byId(id)).limit(1);
|
|
1250
|
+
return record ?? null;
|
|
1251
|
+
},
|
|
1252
|
+
async titles(ids, titleField) {
|
|
1253
|
+
const titleColumn = columns[titleField] ?? idColumn;
|
|
1254
|
+
const rows = await getDb().select({ id: idColumn, title: titleColumn }).from(table).where(inArray(idColumn, ids));
|
|
1255
|
+
return rows;
|
|
1256
|
+
},
|
|
1257
|
+
async insert(values) {
|
|
1258
|
+
const [record] = await getDb().insert(table).values(values).returning();
|
|
1259
|
+
return record;
|
|
1260
|
+
},
|
|
1261
|
+
async update(id, values) {
|
|
1262
|
+
const [record] = await getDb().update(table).set(values).where(byId(id)).returning();
|
|
1263
|
+
return record ?? null;
|
|
1264
|
+
},
|
|
1265
|
+
async remove(id) {
|
|
1266
|
+
const deleted = await getDb().delete(table).where(byId(id)).returning({ id: idColumn });
|
|
1267
|
+
return deleted.length > 0;
|
|
1268
|
+
},
|
|
1269
|
+
constraint(error) {
|
|
1270
|
+
const text = errorText(error);
|
|
1271
|
+
const unique = /UNIQUE constraint failed: ([\w.]+(?:, [\w.]+)*)/.exec(text);
|
|
1272
|
+
if (unique) return { kind: "unique", column: unique[1].split(", ")[0].split(".").pop() };
|
|
1273
|
+
if (/FOREIGN KEY constraint failed/.test(text)) return { kind: "foreignKey" };
|
|
1274
|
+
if (/CHECK constraint failed/.test(text)) return { kind: "check" };
|
|
1275
|
+
return void 0;
|
|
1276
|
+
}
|
|
1277
|
+
};
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1189
1280
|
// src/server/query.ts
|
|
1190
1281
|
function encodeCursor(cursor) {
|
|
1191
1282
|
const json2 = JSON.stringify([cursor.value, cursor.id, cursor.direction === "before" ? 0 : 1]);
|
|
@@ -1284,45 +1375,36 @@ function toCursorValue(value) {
|
|
|
1284
1375
|
if (typeof value === "object") return String(value);
|
|
1285
1376
|
return value;
|
|
1286
1377
|
}
|
|
1287
|
-
function errorText(error) {
|
|
1288
|
-
const parts = [];
|
|
1289
|
-
for (let current = error, depth = 0; current && depth < 5; depth++) {
|
|
1290
|
-
if (current instanceof Error) {
|
|
1291
|
-
parts.push(current.message);
|
|
1292
|
-
current = current.cause;
|
|
1293
|
-
} else {
|
|
1294
|
-
parts.push(String(current));
|
|
1295
|
-
break;
|
|
1296
|
-
}
|
|
1297
|
-
}
|
|
1298
|
-
return parts.join(" | ");
|
|
1299
|
-
}
|
|
1300
1378
|
function createResourceStore(options) {
|
|
1301
|
-
const { resource, table
|
|
1379
|
+
const { resource, table } = options;
|
|
1302
1380
|
const validators = createValidators(resource);
|
|
1303
|
-
const columns = getTableColumns(table);
|
|
1304
1381
|
const fields = storedFields(resource);
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1382
|
+
if (!options.rows && !(table && options.getDb)) {
|
|
1383
|
+
throw new Error(`Resource "${resource.name}": a store needs either a Drizzle table and getDb, or rows.`);
|
|
1384
|
+
}
|
|
1385
|
+
const rows = options.rows ?? drizzleRows(table, options.getDb);
|
|
1386
|
+
const columns = "columns" in rows ? rows.columns : void 0;
|
|
1387
|
+
if (columns) {
|
|
1388
|
+
for (const key of ["id", "createdAt", "updatedAt", ...fields.map(([key2]) => key2)]) {
|
|
1389
|
+
if (!columns[key]) {
|
|
1390
|
+
throw new Error(`Resource "${resource.name}": table has no column for "${key}". Run \`flare sync-types\` and create a migration.`);
|
|
1391
|
+
}
|
|
1308
1392
|
}
|
|
1309
1393
|
}
|
|
1310
|
-
const
|
|
1311
|
-
const columnKeyByName = new Map(Object.entries(columns).map(([key, column]) => [column.name, key]));
|
|
1394
|
+
const keyForColumn = (name) => columns ? Object.entries(columns).find(([, column]) => column.name === name)?.[0] : ["id", "createdAt", "updatedAt", ...fields.map(([key]) => key)].find((key) => columnName(key) === name || key === name);
|
|
1312
1395
|
const fail = (status, error, extra = {}) => ({ ok: false, status, error, ...extra });
|
|
1313
1396
|
function constraintFailure(error, action) {
|
|
1314
|
-
const
|
|
1315
|
-
|
|
1316
|
-
if (unique) {
|
|
1317
|
-
const key =
|
|
1397
|
+
const hit = rows.constraint(error);
|
|
1398
|
+
if (!hit) return void 0;
|
|
1399
|
+
if (hit.kind === "unique") {
|
|
1400
|
+
const key = hit.column ? keyForColumn(hit.column) : void 0;
|
|
1318
1401
|
const label = key ? resource.fields[key]?.label ?? key : "Value";
|
|
1319
1402
|
return fail(409, `${label} is already taken.`, key ? { field: key } : {});
|
|
1320
1403
|
}
|
|
1321
|
-
if (
|
|
1404
|
+
if (hit.kind === "foreignKey") {
|
|
1322
1405
|
return action === "delete" ? fail(409, `This ${resource.label.toLowerCase()} is still referenced by other records.`) : fail(422, "A related record doesn't exist.");
|
|
1323
1406
|
}
|
|
1324
|
-
|
|
1325
|
-
return void 0;
|
|
1407
|
+
return fail(422, "A value is outside its allowed options.");
|
|
1326
1408
|
}
|
|
1327
1409
|
async function guarded(action, work) {
|
|
1328
1410
|
try {
|
|
@@ -1347,7 +1429,6 @@ function createResourceStore(options) {
|
|
|
1347
1429
|
return result;
|
|
1348
1430
|
}
|
|
1349
1431
|
const invalid = (issues) => fail(422, "Validation failed.", { issues: issues.map((issue) => ({ path: issue.path.map(String).join("."), message: issue.message })) });
|
|
1350
|
-
const byId = (id) => eq(idColumn, id);
|
|
1351
1432
|
const notFound = () => fail(404, `${resource.label} not found.`);
|
|
1352
1433
|
const computed = Object.entries(resource.computed ?? {});
|
|
1353
1434
|
const withComputed = (row) => {
|
|
@@ -1363,7 +1444,7 @@ function createResourceStore(options) {
|
|
|
1363
1444
|
return result;
|
|
1364
1445
|
};
|
|
1365
1446
|
const hooks = resource.hooks ?? {};
|
|
1366
|
-
const hookContext = async () => ({ db:
|
|
1447
|
+
const hookContext = async () => ({ db: rows.db, user: await options.currentUser?.() ?? null });
|
|
1367
1448
|
return {
|
|
1368
1449
|
resource,
|
|
1369
1450
|
table,
|
|
@@ -1372,50 +1453,35 @@ function createResourceStore(options) {
|
|
|
1372
1453
|
const parsed = parseListQuery(resource, params);
|
|
1373
1454
|
if ("issues" in parsed) return fail(400, "Invalid query.", { queryIssues: parsed.issues });
|
|
1374
1455
|
const { page, perPage, sort, q, filters, cursor } = parsed.query;
|
|
1375
|
-
const
|
|
1376
|
-
|
|
1377
|
-
const pattern = `%${q.replace(/[\\%_]/g, (char) => `\\${char}`)}%`;
|
|
1378
|
-
const searchable = fields.filter(([, def]) => isSearchable(def)).map(([key]) => columns[key]);
|
|
1379
|
-
if (searchable.length) conditions.push(or(...searchable.map((column) => sql`${column} LIKE ${pattern} ESCAPE '\\'`)));
|
|
1380
|
-
}
|
|
1381
|
-
for (const [key, value] of Object.entries(filters)) {
|
|
1382
|
-
conditions.push(value === null ? isNull(columns[key]) : eq(columns[key], value));
|
|
1383
|
-
}
|
|
1384
|
-
const filterWhere = conditions.length ? and(...conditions) : void 0;
|
|
1385
|
-
const sortColumn = columns[sort.field];
|
|
1456
|
+
const searchable = fields.filter(([, def]) => isSearchable(def)).map(([key]) => key);
|
|
1457
|
+
const matching = { search: q ? { term: q, fields: searchable } : void 0, filters };
|
|
1386
1458
|
const backwards = cursor?.direction === "before";
|
|
1387
1459
|
const descending = backwards ? sort.direction === "asc" : sort.direction === "desc";
|
|
1388
|
-
const
|
|
1389
|
-
const pageConditions = [...conditions];
|
|
1390
|
-
if (cursor) {
|
|
1391
|
-
const value = cursor.value;
|
|
1392
|
-
pageConditions.push(
|
|
1393
|
-
descending ? or(sql`${sortColumn} < ${value}`, and(sql`${sortColumn} = ${value}`, sql`${idColumn} < ${cursor.id}`)) : or(sql`${sortColumn} > ${value}`, and(sql`${sortColumn} = ${value}`, sql`${idColumn} > ${cursor.id}`))
|
|
1394
|
-
);
|
|
1395
|
-
}
|
|
1396
|
-
const where = pageConditions.length ? and(...pageConditions) : void 0;
|
|
1397
|
-
const db = getDb();
|
|
1398
|
-
const query = db.select().from(table).where(where).orderBy(...order).limit(perPage + 1);
|
|
1399
|
-
const [found, counted] = await Promise.all([
|
|
1400
|
-
cursor ? query : query.offset((page - 1) * perPage),
|
|
1460
|
+
const [found, counting] = await Promise.all([
|
|
1401
1461
|
// One row past the limit is enough to know there's more without counting it all.
|
|
1402
|
-
|
|
1462
|
+
rows.find({
|
|
1463
|
+
...matching,
|
|
1464
|
+
sort: { field: sort.field, direction: descending ? "desc" : "asc" },
|
|
1465
|
+
cursor: cursor ? { field: sort.field, value: cursor.value, id: cursor.id, greaterThan: !descending } : void 0,
|
|
1466
|
+
limit: perPage + 1,
|
|
1467
|
+
offset: cursor ? void 0 : (page - 1) * perPage
|
|
1468
|
+
}),
|
|
1469
|
+
rows.countUpTo(matching, COUNT_LIMIT + 1)
|
|
1403
1470
|
]);
|
|
1404
1471
|
const hasMore = found.length > perPage;
|
|
1405
|
-
const
|
|
1406
|
-
if (backwards)
|
|
1407
|
-
const counting = counted[0]?.total ?? 0;
|
|
1472
|
+
const page_ = (hasMore ? found.slice(0, perPage) : found).map(withComputed);
|
|
1473
|
+
if (backwards) page_.reverse();
|
|
1408
1474
|
const exactTotal = counting <= COUNT_LIMIT;
|
|
1409
1475
|
const total = exactTotal ? counting : COUNT_LIMIT;
|
|
1410
|
-
const first =
|
|
1411
|
-
const last =
|
|
1476
|
+
const first = page_[0];
|
|
1477
|
+
const last = page_[page_.length - 1];
|
|
1412
1478
|
const moreAfter = backwards ? true : hasMore;
|
|
1413
1479
|
const moreBefore = backwards ? hasMore : Boolean(cursor) || page > 1;
|
|
1414
1480
|
const cursorFor = (row, direction) => row ? encodeCursor({ value: toCursorValue(row[sort.field]), id: String(row.id), direction }) : void 0;
|
|
1415
1481
|
return {
|
|
1416
1482
|
ok: true,
|
|
1417
1483
|
data: {
|
|
1418
|
-
data:
|
|
1484
|
+
data: page_,
|
|
1419
1485
|
meta: {
|
|
1420
1486
|
page,
|
|
1421
1487
|
perPage,
|
|
@@ -1429,16 +1495,15 @@ function createResourceStore(options) {
|
|
|
1429
1495
|
};
|
|
1430
1496
|
},
|
|
1431
1497
|
async get(id) {
|
|
1432
|
-
const
|
|
1498
|
+
const record = await rows.byId(id);
|
|
1433
1499
|
return record ? { ok: true, data: withComputed(record) } : notFound();
|
|
1434
1500
|
},
|
|
1435
1501
|
/** Title-field values for a set of ids (for showing relations). Missing ids are omitted. */
|
|
1436
1502
|
async titles(ids) {
|
|
1437
1503
|
const unique = [...new Set(ids.filter(Boolean))];
|
|
1438
1504
|
if (unique.length === 0) return {};
|
|
1439
|
-
const
|
|
1440
|
-
|
|
1441
|
-
return Object.fromEntries(rows.map((row) => [row.id, row.title == null ? row.id : String(row.title)]));
|
|
1505
|
+
const found = await rows.titles(unique, resource.titleField);
|
|
1506
|
+
return Object.fromEntries(found.map((row) => [row.id, row.title == null ? row.id : String(row.title)]));
|
|
1442
1507
|
},
|
|
1443
1508
|
create(raw) {
|
|
1444
1509
|
return writing("create", async () => {
|
|
@@ -1448,7 +1513,7 @@ function createResourceStore(options) {
|
|
|
1448
1513
|
if (!result.success) return invalid(result.error.issues);
|
|
1449
1514
|
const input = result.data;
|
|
1450
1515
|
const now = /* @__PURE__ */ new Date();
|
|
1451
|
-
const
|
|
1516
|
+
const record = await rows.insert({ ...input, id: crypto.randomUUID(), createdAt: now, updatedAt: now });
|
|
1452
1517
|
const saved = withComputed(record);
|
|
1453
1518
|
await hooks.afterCreate?.(saved, context);
|
|
1454
1519
|
return { ok: true, data: saved };
|
|
@@ -1458,13 +1523,12 @@ function createResourceStore(options) {
|
|
|
1458
1523
|
update(id, raw) {
|
|
1459
1524
|
return writing("update", async () => {
|
|
1460
1525
|
const context = await hookContext();
|
|
1461
|
-
const
|
|
1462
|
-
const current = existing ?? null;
|
|
1526
|
+
const current = hooks.beforeUpdate || hooks.afterUpdate ? await rows.byId(id) : null;
|
|
1463
1527
|
const supplied = hooks.beforeUpdate ? await hooks.beforeUpdate({ ...raw ?? {} }, { ...context, id, current }) : raw;
|
|
1464
1528
|
const result = validators.update.safeParse(supplied);
|
|
1465
1529
|
if (!result.success) return invalid(result.error.issues);
|
|
1466
1530
|
const input = result.data;
|
|
1467
|
-
const
|
|
1531
|
+
const record = await rows.update(id, { ...input, updatedAt: /* @__PURE__ */ new Date() });
|
|
1468
1532
|
if (!record) return notFound();
|
|
1469
1533
|
const saved = withComputed(record);
|
|
1470
1534
|
await hooks.afterUpdate?.(saved, { ...context, previous: current });
|
|
@@ -1481,7 +1545,7 @@ function createResourceStore(options) {
|
|
|
1481
1545
|
values[key] = "default" in def && def.default !== void 0 ? def.default : def.required ? void 0 : null;
|
|
1482
1546
|
}
|
|
1483
1547
|
Object.assign(values, result.data, { updatedAt: /* @__PURE__ */ new Date() });
|
|
1484
|
-
const
|
|
1548
|
+
const record = await rows.update(id, values);
|
|
1485
1549
|
return record ? { ok: true, data: withComputed(record) } : notFound();
|
|
1486
1550
|
});
|
|
1487
1551
|
},
|
|
@@ -1489,11 +1553,9 @@ function createResourceStore(options) {
|
|
|
1489
1553
|
return writing("delete", async () => {
|
|
1490
1554
|
const context = await hookContext();
|
|
1491
1555
|
if (hooks.beforeDelete) {
|
|
1492
|
-
|
|
1493
|
-
await hooks.beforeDelete({ ...context, id, current: existing ?? null });
|
|
1556
|
+
await hooks.beforeDelete({ ...context, id, current: await rows.byId(id) });
|
|
1494
1557
|
}
|
|
1495
|
-
|
|
1496
|
-
if (deleted.length === 0) return notFound();
|
|
1558
|
+
if (!await rows.remove(id)) return notFound();
|
|
1497
1559
|
await hooks.afterDelete?.({ ...context, id });
|
|
1498
1560
|
return { ok: true, data: { id } };
|
|
1499
1561
|
});
|
|
@@ -1586,6 +1648,99 @@ function createResourceHandlers(options) {
|
|
|
1586
1648
|
};
|
|
1587
1649
|
}
|
|
1588
1650
|
|
|
1651
|
+
// src/server/prisma-rows.ts
|
|
1652
|
+
var NOT_FOUND = "P2025";
|
|
1653
|
+
var codeOf = (error) => typeof error === "object" && error !== null && "code" in error ? String(error.code) : void 0;
|
|
1654
|
+
function uniqueColumn(error) {
|
|
1655
|
+
const meta = error.meta;
|
|
1656
|
+
if (!meta) return void 0;
|
|
1657
|
+
const target = meta.target;
|
|
1658
|
+
if (Array.isArray(target) && target.length > 0) return String(target[0]);
|
|
1659
|
+
if (typeof target === "string") return fromIndexName(target);
|
|
1660
|
+
const cause = meta.driverAdapterError?.cause;
|
|
1661
|
+
const constraint = cause?.constraint;
|
|
1662
|
+
if (constraint?.fields?.length) return constraint.fields[0];
|
|
1663
|
+
if (constraint?.index) return fromIndexName(constraint.index);
|
|
1664
|
+
return void 0;
|
|
1665
|
+
}
|
|
1666
|
+
function fromIndexName(name) {
|
|
1667
|
+
const match = /^.*?_(.+)_key$/.exec(name);
|
|
1668
|
+
return match ? match[1] : name;
|
|
1669
|
+
}
|
|
1670
|
+
function prismaRows(delegate, client) {
|
|
1671
|
+
function matching(query) {
|
|
1672
|
+
const where = { ...query.filters };
|
|
1673
|
+
if (query.search && query.search.fields.length > 0) {
|
|
1674
|
+
where.OR = query.search.fields.map((field) => ({ [field]: { contains: query.search.term, mode: "insensitive" } }));
|
|
1675
|
+
}
|
|
1676
|
+
return where;
|
|
1677
|
+
}
|
|
1678
|
+
return {
|
|
1679
|
+
db: client,
|
|
1680
|
+
async find(query) {
|
|
1681
|
+
const where = matching(query);
|
|
1682
|
+
if (query.cursor) {
|
|
1683
|
+
const { field, value, id, greaterThan } = query.cursor;
|
|
1684
|
+
const op = greaterThan ? "gt" : "lt";
|
|
1685
|
+
const keyset = [{ [field]: { [op]: value } }, { AND: [{ [field]: value }, { id: { [op]: id } }] }];
|
|
1686
|
+
where.AND = [...where.AND ?? [], { OR: keyset }];
|
|
1687
|
+
}
|
|
1688
|
+
return delegate.findMany({
|
|
1689
|
+
where,
|
|
1690
|
+
orderBy: [{ [query.sort.field]: query.sort.direction }, { id: query.sort.direction }],
|
|
1691
|
+
take: query.limit,
|
|
1692
|
+
...query.offset ? { skip: query.offset } : {}
|
|
1693
|
+
});
|
|
1694
|
+
},
|
|
1695
|
+
countUpTo(query, limit) {
|
|
1696
|
+
return delegate.count({ where: matching(query), take: limit });
|
|
1697
|
+
},
|
|
1698
|
+
byId(id) {
|
|
1699
|
+
return delegate.findUnique({ where: { id } });
|
|
1700
|
+
},
|
|
1701
|
+
async titles(ids, titleField) {
|
|
1702
|
+
const rows = await delegate.findMany({ where: { id: { in: ids } }, select: { id: true, [titleField]: true } });
|
|
1703
|
+
return rows.map((row) => ({ id: String(row.id), title: row[titleField] }));
|
|
1704
|
+
},
|
|
1705
|
+
insert(values) {
|
|
1706
|
+
return delegate.create({ data: values });
|
|
1707
|
+
},
|
|
1708
|
+
async update(id, values) {
|
|
1709
|
+
try {
|
|
1710
|
+
return await delegate.update({ where: { id }, data: values });
|
|
1711
|
+
} catch (error) {
|
|
1712
|
+
if (codeOf(error) === NOT_FOUND) return null;
|
|
1713
|
+
throw error;
|
|
1714
|
+
}
|
|
1715
|
+
},
|
|
1716
|
+
async remove(id) {
|
|
1717
|
+
try {
|
|
1718
|
+
await delegate.delete({ where: { id } });
|
|
1719
|
+
return true;
|
|
1720
|
+
} catch (error) {
|
|
1721
|
+
if (codeOf(error) === NOT_FOUND) return false;
|
|
1722
|
+
throw error;
|
|
1723
|
+
}
|
|
1724
|
+
},
|
|
1725
|
+
constraint(error) {
|
|
1726
|
+
switch (codeOf(error)) {
|
|
1727
|
+
case "P2002":
|
|
1728
|
+
return { kind: "unique", column: uniqueColumn(error) };
|
|
1729
|
+
case "P2003":
|
|
1730
|
+
case "P2014":
|
|
1731
|
+
return { kind: "foreignKey" };
|
|
1732
|
+
// A value outside its type, too long for its column, or null where it can't be.
|
|
1733
|
+
case "P2000":
|
|
1734
|
+
case "P2011":
|
|
1735
|
+
case "P2020":
|
|
1736
|
+
return { kind: "check" };
|
|
1737
|
+
default:
|
|
1738
|
+
return void 0;
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
};
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1589
1744
|
// src/server/openapi.ts
|
|
1590
1745
|
var E164 = "^\\+[1-9]\\d{6,14}$";
|
|
1591
1746
|
function fieldJsonSchema(def) {
|
|
@@ -1859,10 +2014,12 @@ function openApiDocument(options) {
|
|
|
1859
2014
|
export {
|
|
1860
2015
|
createResourceHandlers,
|
|
1861
2016
|
createResourceStore,
|
|
2017
|
+
drizzleRows,
|
|
1862
2018
|
fieldJsonSchema,
|
|
1863
2019
|
isFilterable,
|
|
1864
2020
|
isSearchable,
|
|
1865
2021
|
isSortable,
|
|
1866
2022
|
openApiDocument,
|
|
1867
|
-
parseListQuery
|
|
2023
|
+
parseListQuery,
|
|
2024
|
+
prismaRows
|
|
1868
2025
|
};
|