@ai0x0/utils 0.0.50 → 0.1.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/.agents/skills/ai0x0-utils/backend/SKILL.md +35 -11
- package/README.md +3 -3
- package/SKILL.md +35 -11
- package/es/backend/actions/create-delete-action.d.ts +4 -2
- package/es/backend/actions/create-delete-action.js +22 -28
- package/es/backend/actions/create-get-action.d.ts +4 -1
- package/es/backend/actions/create-get-action.js +10 -10
- package/es/backend/actions/create-get-list-action.d.ts +4 -1
- package/es/backend/actions/create-get-list-action.js +9 -9
- package/es/backend/actions/create-put-action.d.ts +3 -2
- package/es/backend/actions/create-put-action.js +23 -38
- package/es/backend/actions/get-list-query.d.ts +8 -1
- package/es/backend/actions/get-list-query.js +19 -8
- package/es/backend/index.d.ts +1 -0
- package/es/backend/index.js +2 -1
- package/es/backend/route-operation/delete-operation.d.ts +3 -1
- package/es/backend/route-operation/get-list-operation.d.ts +3 -1
- package/es/backend/route-operation/get-operation.d.ts +3 -1
- package/es/backend/route-operation/operation-common.d.ts +80 -8
- package/es/backend/route-operation/operation-common.js +216 -67
- package/es/backend/route-operation/post-operation.d.ts +3 -1
- package/es/backend/route-operation/put-operation.d.ts +3 -1
- package/es/backend/route-operation/read-operation-core.d.ts +17 -14
- package/es/backend/route-operation/read-operation-core.js +42 -34
- package/es/backend/route-operation/write-operation-core.d.ts +25 -22
- package/es/backend/route-operation/write-operation-core.js +195 -165
- package/es/backend/schemas/index.d.ts +240 -240
- package/es/backend/scope.d.ts +27 -0
- package/es/backend/scope.js +60 -0
- package/es/backend/sqlite/actions/create-delete-action.d.ts +4 -2
- package/es/backend/sqlite/actions/create-delete-action.js +21 -28
- package/es/backend/sqlite/actions/create-get-action.d.ts +4 -1
- package/es/backend/sqlite/actions/create-get-action.js +9 -7
- package/es/backend/sqlite/actions/create-get-list-action.d.ts +4 -1
- package/es/backend/sqlite/actions/create-get-list-action.js +8 -6
- package/es/backend/sqlite/actions/create-put-action.d.ts +3 -2
- package/es/backend/sqlite/actions/create-put-action.js +20 -38
- package/es/backend/sqlite/actions/get-list-query.d.ts +4 -1
- package/es/backend/sqlite/actions/get-list-query.js +8 -3
- package/es/backend/sqlite/route-operation/delete-operation.d.ts +3 -1
- package/es/backend/sqlite/route-operation/get-list-operation.d.ts +3 -1
- package/es/backend/sqlite/route-operation/get-operation.d.ts +3 -1
- package/es/backend/sqlite/route-operation/post-operation.d.ts +3 -1
- package/es/backend/sqlite/route-operation/put-operation.d.ts +3 -1
- package/lib/backend/actions/create-delete-action.d.ts +4 -2
- package/lib/backend/actions/create-delete-action.js +10 -16
- package/lib/backend/actions/create-get-action.d.ts +4 -1
- package/lib/backend/actions/create-get-action.js +2 -1
- package/lib/backend/actions/create-get-list-action.d.ts +4 -1
- package/lib/backend/actions/create-get-list-action.js +2 -1
- package/lib/backend/actions/create-put-action.d.ts +3 -2
- package/lib/backend/actions/create-put-action.js +10 -21
- package/lib/backend/actions/get-list-query.d.ts +8 -1
- package/lib/backend/actions/get-list-query.js +11 -4
- package/lib/backend/index.d.ts +1 -0
- package/lib/backend/index.js +3 -1
- package/lib/backend/route-operation/delete-operation.d.ts +3 -1
- package/lib/backend/route-operation/get-list-operation.d.ts +3 -1
- package/lib/backend/route-operation/get-operation.d.ts +3 -1
- package/lib/backend/route-operation/operation-common.d.ts +80 -8
- package/lib/backend/route-operation/operation-common.js +57 -7
- package/lib/backend/route-operation/post-operation.d.ts +3 -1
- package/lib/backend/route-operation/put-operation.d.ts +3 -1
- package/lib/backend/route-operation/read-operation-core.d.ts +17 -14
- package/lib/backend/route-operation/read-operation-core.js +12 -6
- package/lib/backend/route-operation/write-operation-core.d.ts +25 -22
- package/lib/backend/route-operation/write-operation-core.js +52 -16
- package/lib/backend/schemas/index.d.ts +240 -240
- package/lib/backend/scope.d.ts +27 -0
- package/lib/backend/scope.js +57 -0
- package/lib/backend/sqlite/actions/create-delete-action.d.ts +4 -2
- package/lib/backend/sqlite/actions/create-delete-action.js +10 -16
- package/lib/backend/sqlite/actions/create-get-action.d.ts +4 -1
- package/lib/backend/sqlite/actions/create-get-action.js +2 -1
- package/lib/backend/sqlite/actions/create-get-list-action.d.ts +4 -1
- package/lib/backend/sqlite/actions/create-get-list-action.js +2 -1
- package/lib/backend/sqlite/actions/create-put-action.d.ts +3 -2
- package/lib/backend/sqlite/actions/create-put-action.js +10 -21
- package/lib/backend/sqlite/actions/get-list-query.d.ts +4 -1
- package/lib/backend/sqlite/actions/get-list-query.js +5 -1
- package/lib/backend/sqlite/route-operation/delete-operation.d.ts +3 -1
- package/lib/backend/sqlite/route-operation/get-list-operation.d.ts +3 -1
- package/lib/backend/sqlite/route-operation/get-operation.d.ts +3 -1
- package/lib/backend/sqlite/route-operation/post-operation.d.ts +3 -1
- package/lib/backend/sqlite/route-operation/put-operation.d.ts +3 -1
- package/package.json +38 -1
|
@@ -48,7 +48,7 @@ export {
|
|
|
48
48
|
createTableSchema,
|
|
49
49
|
queryListSchema,
|
|
50
50
|
listBodySchema,
|
|
51
|
-
} from "@ai0x0/utils/
|
|
51
|
+
} from "@ai0x0/utils/backend/schemas";
|
|
52
52
|
```
|
|
53
53
|
|
|
54
54
|
```ts
|
|
@@ -59,7 +59,7 @@ export {
|
|
|
59
59
|
createGetListAction,
|
|
60
60
|
createPostAction,
|
|
61
61
|
createPutAction,
|
|
62
|
-
} from "@ai0x0/utils/
|
|
62
|
+
} from "@ai0x0/utils/backend";
|
|
63
63
|
```
|
|
64
64
|
|
|
65
65
|
```ts
|
|
@@ -70,7 +70,7 @@ import {
|
|
|
70
70
|
createPostOperation,
|
|
71
71
|
createDeleteOperation,
|
|
72
72
|
createGetListOperation,
|
|
73
|
-
} from "@ai0x0/utils/
|
|
73
|
+
} from "@ai0x0/utils/backend";
|
|
74
74
|
import { db } from "@backend/db";
|
|
75
75
|
import getSession from "@backend/utils/get-session";
|
|
76
76
|
|
|
@@ -330,8 +330,13 @@ export const { GET } = route({
|
|
|
330
330
|
## Built-in Conventions
|
|
331
331
|
|
|
332
332
|
- **Base fields** auto-added by `createTableSchema`: `id` (uuid, pk, default random) / `creatorId` / `editorId` / `accessedAt` / `createdAt` / `updatedAt`.
|
|
333
|
-
- **
|
|
334
|
-
-
|
|
333
|
+
- **Row-level scope** (`access`, on by default for every verb): the request may only see / touch rows whose scope column matches. Three knobs:
|
|
334
|
+
- `byCreator?: boolean` — the old spelling, equivalent to `scope: { column: "creatorId", value: (s) => s.userId }`. Default `true`.
|
|
335
|
+
- `scope?: { column?, value }` — pick the column (default `creatorId`) and derive the value from the session. Return an array for `IN (...)`. Use this when a row can belong to something other than one user (a team, a workspace).
|
|
336
|
+
- `can?: ({ session, method }) => boolean | { status?, message? }` — the _action_ gate, as opposed to the _row_ filter. Read-only roles belong here, in one place, not spread across every route.
|
|
337
|
+
- **Fail closed**: if the session is missing → 401; if `scope.value` returns empty → 403. A scope that cannot be resolved is **never** downgraded to "no filter". PUT/DELETE put the scope straight into the `UPDATE`/`DELETE` `where` (one statement, no read-then-write window) and return 404 when it affects zero rows — "does not exist" and "not yours" are deliberately indistinguishable, otherwise the endpoint becomes an existence oracle.
|
|
338
|
+
- **Auto injection**: POST stamps the scope column with the scope value (by default that is `creatorId = session.userId`); PUT writes `editorId = session.userId`; GET/GET_LIST apply the scope as a mandatory `where`.
|
|
339
|
+
- **Session shape** is yours: `getSession` is generic, so resolve "who + which space + what role" once and let `scope.value` / `can` read the same object instead of each querying again.
|
|
335
340
|
- **Date coercion**: any body field ending in `At` is passed through `dayjs(value).toDate()` before write — accept ISO strings from clients.
|
|
336
341
|
- **List filtering** (all querystring values are strings):
|
|
337
342
|
- `key=a,b,c` → `IN (...)` when key ends with `Id`; otherwise `OR ILIKE %a% OR ILIKE %b%`
|
|
@@ -352,6 +357,26 @@ export const { GET } = route({
|
|
|
352
357
|
- Swallowing errors: an unhandled throw in a handler propagates to next-rest-framework as a 500. Provide `catch` for any operation exposed to untrusted clients.
|
|
353
358
|
- For non-CRUD behavior (middleware chains, streaming, custom `TypedNextResponse` unions, RPC) stop using these factories and switch to the `create-next-rest-framework-api` skill.
|
|
354
359
|
|
|
360
|
+
## Using the actions directly
|
|
361
|
+
|
|
362
|
+
`createGetAction` / `createGetListAction` / `createPutAction` / `createDeleteAction` and `getListQuery` all take the scope as a **required** argument — pass `NO_SCOPE` to opt out explicitly:
|
|
363
|
+
|
|
364
|
+
```ts
|
|
365
|
+
import { NO_SCOPE } from "@ai0x0/utils/backend";
|
|
366
|
+
|
|
367
|
+
await createGetListAction({ bodySchema, db, table })(params, {
|
|
368
|
+
scope: NO_SCOPE,
|
|
369
|
+
});
|
|
370
|
+
await createDeleteAction({ db, table })(
|
|
371
|
+
{ id },
|
|
372
|
+
{
|
|
373
|
+
scope: { column: "ownerId", value: currentTeamId },
|
|
374
|
+
},
|
|
375
|
+
);
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
It is required rather than optional on purpose: a forgotten scope is a compile error, not a silent full-table query.
|
|
379
|
+
|
|
355
380
|
## Escape Hatches
|
|
356
381
|
|
|
357
382
|
- Extra server-side filters — `setParams(req) => Promise<Record<string, unknown>>` on GET/GET_LIST; returned keys are merged into the filter.
|
|
@@ -362,19 +387,18 @@ export const { GET } = route({
|
|
|
362
387
|
## Imports
|
|
363
388
|
|
|
364
389
|
```
|
|
365
|
-
@ai0x0/utils/
|
|
366
|
-
@ai0x0/utils/
|
|
367
|
-
@ai0x0/utils/
|
|
368
|
-
@ai0x0/utils/lib/backend/schemas
|
|
390
|
+
@ai0x0/utils/backend // actions + route-operation + schemas + scope
|
|
391
|
+
@ai0x0/utils/backend/schemas // createTableSchema / queryListSchema
|
|
392
|
+
@ai0x0/utils/backend/sqlite // same surface, SQLite flavour
|
|
369
393
|
```
|
|
370
394
|
|
|
371
|
-
ESM
|
|
395
|
+
The `exports` map picks CJS or ESM per consumer; you do not choose. **Do not write `@ai0x0/utils/es/backend/...` or `/lib/backend/...`** — those name build artifacts and hard-code an internal detail into every import. The `./es/*` and `./lib/*` wildcards stay only so existing callers keep working.
|
|
372
396
|
|
|
373
397
|
## Done Criteria
|
|
374
398
|
|
|
375
399
|
- Route files contain zero hand-written `{ db, getSession }` wiring; all operations come from `@backend/utils/route-operation`.
|
|
376
400
|
- Each domain has a `table.ts` (columns + `createTableSchema`) and an `index.ts` (five zod schemas + re-exports).
|
|
377
401
|
- Every list endpoint accepts `current / pageSize / orderBy / orderDir / *AtFrom / *AtTo` and — where applicable — `jsonArrayFields` is declared.
|
|
378
|
-
- `access
|
|
402
|
+
- `access` is explicitly set when the endpoint is admin-facing or otherwise crosses ownership boundaries — `byCreator: false` for genuinely public data, `scope` when ownership is not "one user", `can` for read-only roles.
|
|
379
403
|
- Non-CRUD endpoints are implemented via raw `routeOperation` + action helpers, not by forcing a CRUD factory.
|
|
380
404
|
- `next-rest-framework validate` / `generate` (from the partner skill) still pass — the factory values are plain `RouteOperationDefinition` and participate in OpenAPI generation.
|
package/README.md
CHANGED
|
@@ -19,17 +19,17 @@ See [SKILL.md](./SKILL.md) for detailed workflow, setup, and escape hatches.
|
|
|
19
19
|
|
|
20
20
|
## SQLite Backend (`src/backend/sqlite/`)
|
|
21
21
|
|
|
22
|
-
Projects that use a local SQLite database can import the same CRUD factory surface from `@ai0x0/utils/
|
|
22
|
+
Projects that use a local SQLite database can import the same CRUD factory surface from `@ai0x0/utils/backend/sqlite`.
|
|
23
23
|
|
|
24
24
|
```ts
|
|
25
25
|
import {
|
|
26
26
|
createTableSchema,
|
|
27
27
|
queryListSchema,
|
|
28
|
-
} from "@ai0x0/utils/
|
|
28
|
+
} from "@ai0x0/utils/backend/sqlite/schemas";
|
|
29
29
|
import {
|
|
30
30
|
createGetOperation,
|
|
31
31
|
createPostOperation,
|
|
32
|
-
} from "@ai0x0/utils/
|
|
32
|
+
} from "@ai0x0/utils/backend/sqlite";
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
The SQLite helpers mirror the PostgreSQL helpers, but use `drizzle-orm/sqlite-core`, SQLite `LIKE`, and `json_each(...)` for JSON-array filtering.
|
package/SKILL.md
CHANGED
|
@@ -27,7 +27,7 @@ export {
|
|
|
27
27
|
createTableSchema,
|
|
28
28
|
queryListSchema,
|
|
29
29
|
listBodySchema,
|
|
30
|
-
} from "@ai0x0/utils/
|
|
30
|
+
} from "@ai0x0/utils/backend/schemas";
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
```ts
|
|
@@ -38,7 +38,7 @@ export {
|
|
|
38
38
|
createGetListAction,
|
|
39
39
|
createPostAction,
|
|
40
40
|
createPutAction,
|
|
41
|
-
} from "@ai0x0/utils/
|
|
41
|
+
} from "@ai0x0/utils/backend";
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
```ts
|
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
createPostOperation,
|
|
50
50
|
createDeleteOperation,
|
|
51
51
|
createGetListOperation,
|
|
52
|
-
} from "@ai0x0/utils/
|
|
52
|
+
} from "@ai0x0/utils/backend";
|
|
53
53
|
import { db } from "@backend/db";
|
|
54
54
|
import getSession from "@backend/utils/get-session";
|
|
55
55
|
|
|
@@ -309,8 +309,13 @@ export const { GET } = route({
|
|
|
309
309
|
## Built-in Conventions
|
|
310
310
|
|
|
311
311
|
- **Base fields** auto-added by `createTableSchema`: `id` (uuid, pk, default random) / `creatorId` / `editorId` / `accessedAt` / `createdAt` / `updatedAt`.
|
|
312
|
-
- **
|
|
313
|
-
-
|
|
312
|
+
- **Row-level scope** (`access`, on by default for every verb): the request may only see / touch rows whose scope column matches. Three knobs:
|
|
313
|
+
- `byCreator?: boolean` — the old spelling, equivalent to `scope: { column: "creatorId", value: (s) => s.userId }`. Default `true`.
|
|
314
|
+
- `scope?: { column?, value }` — pick the column (default `creatorId`) and derive the value from the session. Return an array for `IN (...)`. Use this when a row can belong to something other than one user (a team, a workspace).
|
|
315
|
+
- `can?: ({ session, method }) => boolean | { status?, message? }` — the _action_ gate, as opposed to the _row_ filter. Read-only roles belong here, in one place, not spread across every route.
|
|
316
|
+
- **Fail closed**: if the session is missing → 401; if `scope.value` returns empty → 403. A scope that cannot be resolved is **never** downgraded to "no filter". PUT/DELETE put the scope straight into the `UPDATE`/`DELETE` `where` (one statement, no read-then-write window) and return 404 when it affects zero rows — "does not exist" and "not yours" are deliberately indistinguishable, otherwise the endpoint becomes an existence oracle.
|
|
317
|
+
- **Auto injection**: POST stamps the scope column with the scope value (by default that is `creatorId = session.userId`); PUT writes `editorId = session.userId`; GET/GET_LIST apply the scope as a mandatory `where`.
|
|
318
|
+
- **Session shape** is yours: `getSession` is generic, so resolve "who + which space + what role" once and let `scope.value` / `can` read the same object instead of each querying again.
|
|
314
319
|
- **Date coercion**: any body field ending in `At` is passed through `dayjs(value).toDate()` before write — accept ISO strings from clients.
|
|
315
320
|
- **List filtering** (all querystring values are strings):
|
|
316
321
|
- `key=a,b,c` → `IN (...)` when key ends with `Id`; otherwise `OR ILIKE %a% OR ILIKE %b%`
|
|
@@ -331,6 +336,26 @@ export const { GET } = route({
|
|
|
331
336
|
- Swallowing errors: an unhandled throw in a handler propagates to next-rest-framework as a 500. Provide `catch` for any operation exposed to untrusted clients.
|
|
332
337
|
- For non-CRUD behavior (middleware chains, streaming, custom `TypedNextResponse` unions, RPC) stop using these factories and switch to the `create-next-rest-framework-api` skill.
|
|
333
338
|
|
|
339
|
+
## Using the actions directly
|
|
340
|
+
|
|
341
|
+
`createGetAction` / `createGetListAction` / `createPutAction` / `createDeleteAction` and `getListQuery` all take the scope as a **required** argument — pass `NO_SCOPE` to opt out explicitly:
|
|
342
|
+
|
|
343
|
+
```ts
|
|
344
|
+
import { NO_SCOPE } from "@ai0x0/utils/backend";
|
|
345
|
+
|
|
346
|
+
await createGetListAction({ bodySchema, db, table })(params, {
|
|
347
|
+
scope: NO_SCOPE,
|
|
348
|
+
});
|
|
349
|
+
await createDeleteAction({ db, table })(
|
|
350
|
+
{ id },
|
|
351
|
+
{
|
|
352
|
+
scope: { column: "ownerId", value: currentTeamId },
|
|
353
|
+
},
|
|
354
|
+
);
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
It is required rather than optional on purpose: a forgotten scope is a compile error, not a silent full-table query.
|
|
358
|
+
|
|
334
359
|
## Escape Hatches
|
|
335
360
|
|
|
336
361
|
- Extra server-side filters — `setParams(req) => Promise<Record<string, unknown>>` on GET/GET_LIST; returned keys are merged into the filter.
|
|
@@ -341,19 +366,18 @@ export const { GET } = route({
|
|
|
341
366
|
## Imports
|
|
342
367
|
|
|
343
368
|
```
|
|
344
|
-
@ai0x0/utils/
|
|
345
|
-
@ai0x0/utils/
|
|
346
|
-
@ai0x0/utils/
|
|
347
|
-
@ai0x0/utils/lib/backend/schemas
|
|
369
|
+
@ai0x0/utils/backend // actions + route-operation + schemas + scope
|
|
370
|
+
@ai0x0/utils/backend/schemas // createTableSchema / queryListSchema
|
|
371
|
+
@ai0x0/utils/backend/sqlite // same surface, SQLite flavour
|
|
348
372
|
```
|
|
349
373
|
|
|
350
|
-
ESM
|
|
374
|
+
The `exports` map picks CJS or ESM per consumer; you do not choose. **Do not write `@ai0x0/utils/es/backend/...` or `/lib/backend/...`** — those name build artifacts and hard-code an internal detail into every import. The `./es/*` and `./lib/*` wildcards stay only so existing callers keep working.
|
|
351
375
|
|
|
352
376
|
## Done Criteria
|
|
353
377
|
|
|
354
378
|
- Route files contain zero hand-written `{ db, getSession }` wiring; all operations come from `@backend/utils/route-operation`.
|
|
355
379
|
- Each domain has a `table.ts` (columns + `createTableSchema`) and an `index.ts` (five zod schemas + re-exports).
|
|
356
380
|
- Every list endpoint accepts `current / pageSize / orderBy / orderDir / *AtFrom / *AtTo` and — where applicable — `jsonArrayFields` is declared.
|
|
357
|
-
- `access
|
|
381
|
+
- `access` is explicitly set when the endpoint is admin-facing or otherwise crosses ownership boundaries — `byCreator: false` for genuinely public data, `scope` when ownership is not "one user", `can` for read-only roles.
|
|
358
382
|
- Non-CRUD endpoints are implemented via raw `routeOperation` + action helpers, not by forcing a CRUD factory.
|
|
359
383
|
- `next-rest-framework validate` / `generate` (from the partner skill) still pass — the factory values are plain `RouteOperationDefinition` and participate in OpenAPI generation.
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { NodePgDatabase } from "drizzle-orm/node-postgres";
|
|
2
2
|
import { BaseTable } from "../types.js";
|
|
3
|
+
import { ScopeArg } from "../scope.js";
|
|
3
4
|
export declare function createDeleteAction<TTable extends BaseTable>({ table, db, }: {
|
|
4
5
|
db: NodePgDatabase<Record<string, unknown>>;
|
|
5
6
|
table: TTable;
|
|
6
|
-
}): ({ id
|
|
7
|
+
}): ({ id }: {
|
|
7
8
|
id: string;
|
|
8
|
-
|
|
9
|
+
}, { scope }: {
|
|
10
|
+
scope: ScopeArg;
|
|
9
11
|
}) => Promise<TTable["$inferSelect"] extends infer T ? T extends TTable["$inferSelect"] ? T extends undefined ? QueryResult<import("drizzle-orm").Assume<this["row"], QueryResultRow>> : T[] : never : never>;
|
|
@@ -2,53 +2,47 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" ==
|
|
|
2
2
|
function _regeneratorRuntime() { "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */ _regeneratorRuntime = function _regeneratorRuntime() { return e; }; var t, e = {}, r = Object.prototype, n = r.hasOwnProperty, o = Object.defineProperty || function (t, e, r) { t[e] = r.value; }, i = "function" == typeof Symbol ? Symbol : {}, a = i.iterator || "@@iterator", c = i.asyncIterator || "@@asyncIterator", u = i.toStringTag || "@@toStringTag"; function define(t, e, r) { return Object.defineProperty(t, e, { value: r, enumerable: !0, configurable: !0, writable: !0 }), t[e]; } try { define({}, ""); } catch (t) { define = function define(t, e, r) { return t[e] = r; }; } function wrap(t, e, r, n) { var i = e && e.prototype instanceof Generator ? e : Generator, a = Object.create(i.prototype), c = new Context(n || []); return o(a, "_invoke", { value: makeInvokeMethod(t, r, c) }), a; } function tryCatch(t, e, r) { try { return { type: "normal", arg: t.call(e, r) }; } catch (t) { return { type: "throw", arg: t }; } } e.wrap = wrap; var h = "suspendedStart", l = "suspendedYield", f = "executing", s = "completed", y = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var p = {}; define(p, a, function () { return this; }); var d = Object.getPrototypeOf, v = d && d(d(values([]))); v && v !== r && n.call(v, a) && (p = v); var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p); function defineIteratorMethods(t) { ["next", "throw", "return"].forEach(function (e) { define(t, e, function (t) { return this._invoke(e, t); }); }); } function AsyncIterator(t, e) { function invoke(r, o, i, a) { var c = tryCatch(t[r], t, o); if ("throw" !== c.type) { var u = c.arg, h = u.value; return h && "object" == _typeof(h) && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) { invoke("next", t, i, a); }, function (t) { invoke("throw", t, i, a); }) : e.resolve(h).then(function (t) { u.value = t, i(u); }, function (t) { return invoke("throw", t, i, a); }); } a(c.arg); } var r; o(this, "_invoke", { value: function value(t, n) { function callInvokeWithMethodAndArg() { return new e(function (e, r) { invoke(t, n, e, r); }); } return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(e, r, n) { var o = h; return function (i, a) { if (o === f) throw new Error("Generator is already running"); if (o === s) { if ("throw" === i) throw a; return { value: t, done: !0 }; } for (n.method = i, n.arg = a;;) { var c = n.delegate; if (c) { var u = maybeInvokeDelegate(c, n); if (u) { if (u === y) continue; return u; } } if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) { if (o === h) throw o = s, n.arg; n.dispatchException(n.arg); } else "return" === n.method && n.abrupt("return", n.arg); o = f; var p = tryCatch(e, r, n); if ("normal" === p.type) { if (o = n.done ? s : l, p.arg === y) continue; return { value: p.arg, done: n.done }; } "throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg); } }; } function maybeInvokeDelegate(e, r) { var n = r.method, o = e.iterator[n]; if (o === t) return r.delegate = null, "throw" === n && e.iterator.return && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y; var i = tryCatch(o, e.iterator, r.arg); if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y; var a = i.arg; return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y); } function pushTryEntry(t) { var e = { tryLoc: t[0] }; 1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e); } function resetTryEntry(t) { var e = t.completion || {}; e.type = "normal", delete e.arg, t.completion = e; } function Context(t) { this.tryEntries = [{ tryLoc: "root" }], t.forEach(pushTryEntry, this), this.reset(!0); } function values(e) { if (e || "" === e) { var r = e[a]; if (r) return r.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) { var o = -1, i = function next() { for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next; return next.value = t, next.done = !0, next; }; return i.next = i; } } throw new TypeError(_typeof(e) + " is not iterable"); } return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), o(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) { var e = "function" == typeof t && t.constructor; return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name)); }, e.mark = function (t) { return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t; }, e.awrap = function (t) { return { __await: t }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () { return this; }), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) { void 0 === i && (i = Promise); var a = new AsyncIterator(wrap(t, r, n, o), i); return e.isGeneratorFunction(r) ? a : a.next().then(function (t) { return t.done ? t.value : a.next(); }); }, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () { return this; }), define(g, "toString", function () { return "[object Generator]"; }), e.keys = function (t) { var e = Object(t), r = []; for (var n in e) r.push(n); return r.reverse(), function next() { for (; r.length;) { var t = r.pop(); if (t in e) return next.value = t, next.done = !1, next; } return next.done = !0, next; }; }, e.values = values, Context.prototype = { constructor: Context, reset: function reset(e) { if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t); }, stop: function stop() { this.done = !0; var t = this.tryEntries[0].completion; if ("throw" === t.type) throw t.arg; return this.rval; }, dispatchException: function dispatchException(e) { if (this.done) throw e; var r = this; function handle(n, o) { return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o; } for (var o = this.tryEntries.length - 1; o >= 0; --o) { var i = this.tryEntries[o], a = i.completion; if ("root" === i.tryLoc) return handle("end"); if (i.tryLoc <= this.prev) { var c = n.call(i, "catchLoc"), u = n.call(i, "finallyLoc"); if (c && u) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } else if (c) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); } else { if (!u) throw new Error("try statement without catch or finally"); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } } } }, abrupt: function abrupt(t, e) { for (var r = this.tryEntries.length - 1; r >= 0; --r) { var o = this.tryEntries[r]; if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) { var i = o; break; } } i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null); var a = i ? i.completion : {}; return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a); }, complete: function complete(t, e) { if ("throw" === t.type) throw t.arg; return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y; }, finish: function finish(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y; } }, catch: function _catch(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.tryLoc === t) { var n = r.completion; if ("throw" === n.type) { var o = n.arg; resetTryEntry(r); } return o; } } throw new Error("illegal catch attempt"); }, delegateYield: function delegateYield(e, r, n) { return this.delegate = { iterator: values(e), resultName: r, nextLoc: n }, "next" === this.method && (this.arg = t), y; } }, e; }
|
|
3
3
|
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
4
4
|
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
5
|
-
import { eq } from "drizzle-orm";
|
|
6
|
-
import {
|
|
7
|
-
import { z } from "zod";
|
|
5
|
+
import { and, eq } from "drizzle-orm";
|
|
6
|
+
import { NO_SCOPE, scopeCondition } from "../scope.js";
|
|
8
7
|
import { HttpError } from "../errors.js";
|
|
9
8
|
export function createDeleteAction(_ref) {
|
|
10
9
|
var table = _ref.table,
|
|
11
10
|
db = _ref.db;
|
|
12
11
|
return /*#__PURE__*/function () {
|
|
13
|
-
var
|
|
14
|
-
var id,
|
|
12
|
+
var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(_ref2, _ref3) {
|
|
13
|
+
var id, scope, guard, rows;
|
|
15
14
|
return _regeneratorRuntime().wrap(function _callee$(_context) {
|
|
16
15
|
while (1) switch (_context.prev = _context.next) {
|
|
17
16
|
case 0:
|
|
18
|
-
id = _ref2.id
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
id = _ref2.id;
|
|
18
|
+
scope = _ref3.scope;
|
|
19
|
+
if (id) {
|
|
20
|
+
_context.next = 4;
|
|
21
21
|
break;
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
return createGetAction({
|
|
25
|
-
db: db,
|
|
26
|
-
table: table,
|
|
27
|
-
bodySchema: z.object({
|
|
28
|
-
creatorId: z.string(),
|
|
29
|
-
id: z.string()
|
|
30
|
-
})
|
|
31
|
-
})({
|
|
32
|
-
creatorId: creatorId,
|
|
33
|
-
id: id
|
|
34
|
-
});
|
|
23
|
+
throw new HttpError(400, "缺少 id");
|
|
35
24
|
case 4:
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
25
|
+
// 归属写进 DELETE 的 where,不先查后删(理由同 create-put-action)。
|
|
26
|
+
guard = scopeCondition(table, scope);
|
|
27
|
+
_context.next = 7;
|
|
28
|
+
return db.delete(table).where(guard ? and(eq(table.id, id), guard) : eq(table.id, id)).returning();
|
|
29
|
+
case 7:
|
|
30
|
+
rows = _context.sent;
|
|
31
|
+
if (!(rows.length === 0 && scope !== NO_SCOPE)) {
|
|
32
|
+
_context.next = 10;
|
|
39
33
|
break;
|
|
40
34
|
}
|
|
41
35
|
throw new HttpError(404, "未找到删除对象,或没有权限");
|
|
42
|
-
case
|
|
43
|
-
return _context.abrupt("return",
|
|
44
|
-
case
|
|
36
|
+
case 10:
|
|
37
|
+
return _context.abrupt("return", rows);
|
|
38
|
+
case 11:
|
|
45
39
|
case "end":
|
|
46
40
|
return _context.stop();
|
|
47
41
|
}
|
|
48
42
|
}, _callee);
|
|
49
43
|
}));
|
|
50
|
-
return function (_x) {
|
|
51
|
-
return
|
|
44
|
+
return function (_x, _x2) {
|
|
45
|
+
return _ref4.apply(this, arguments);
|
|
52
46
|
};
|
|
53
47
|
}();
|
|
54
48
|
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { z, ZodSchema } from "zod";
|
|
2
2
|
import { NodePgDatabase } from "drizzle-orm/node-postgres";
|
|
3
3
|
import { BaseTable, GetListRelations } from "../types.js";
|
|
4
|
+
import { ScopeArg } from "../scope.js";
|
|
4
5
|
export declare function createGetAction<T extends ZodSchema, TTable extends BaseTable>({ bodySchema, db, jsonArrayFields, relations, table, }: {
|
|
5
6
|
bodySchema: T;
|
|
6
7
|
db: NodePgDatabase<Record<string, unknown>>;
|
|
7
8
|
jsonArrayFields?: string[];
|
|
8
9
|
relations?: GetListRelations;
|
|
9
10
|
table: TTable;
|
|
10
|
-
}): (params: Partial<z.infer<T>> & Record<string, unknown
|
|
11
|
+
}): (params: Partial<z.infer<T>> & Record<string, unknown>, { scope }: {
|
|
12
|
+
scope: ScopeArg;
|
|
13
|
+
}) => Promise<z.core.output<T> | undefined>;
|
|
@@ -17,16 +17,15 @@ export function createGetAction(_ref) {
|
|
|
17
17
|
relations = _ref.relations,
|
|
18
18
|
table = _ref.table;
|
|
19
19
|
return /*#__PURE__*/function () {
|
|
20
|
-
var
|
|
21
|
-
var fields, _i, _Object$keys, key, field, _getListQuery, query, countQuery, _yield$getListData, _yield$getListData$da, result;
|
|
20
|
+
var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(params, _ref2) {
|
|
21
|
+
var scope, fields, _i, _Object$keys, key, field, _getListQuery, query, countQuery, _yield$getListData, _yield$getListData$da, result;
|
|
22
22
|
return _regeneratorRuntime().wrap(function _callee$(_context) {
|
|
23
23
|
while (1) switch (_context.prev = _context.next) {
|
|
24
24
|
case 0:
|
|
25
|
-
|
|
26
|
-
// @ts-ignore
|
|
25
|
+
scope = _ref2.scope;
|
|
26
|
+
fields = {}; // @ts-ignore
|
|
27
27
|
for (_i = 0, _Object$keys = Object.keys(bodySchema.shape); _i < _Object$keys.length; _i++) {
|
|
28
28
|
key = _Object$keys[_i];
|
|
29
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
30
29
|
// @ts-ignore
|
|
31
30
|
field = table[key];
|
|
32
31
|
if (field) {
|
|
@@ -39,9 +38,10 @@ export function createGetAction(_ref) {
|
|
|
39
38
|
jsonArrayFields: jsonArrayFields,
|
|
40
39
|
params: params,
|
|
41
40
|
relations: relations,
|
|
41
|
+
scope: scope,
|
|
42
42
|
table: table
|
|
43
43
|
}), query = _getListQuery.query, countQuery = _getListQuery.countQuery;
|
|
44
|
-
_context.next =
|
|
44
|
+
_context.next = 6;
|
|
45
45
|
return getListData({
|
|
46
46
|
bodySchema: bodySchema,
|
|
47
47
|
countQuery: countQuery,
|
|
@@ -49,19 +49,19 @@ export function createGetAction(_ref) {
|
|
|
49
49
|
pageSize: 1,
|
|
50
50
|
query: query
|
|
51
51
|
})();
|
|
52
|
-
case
|
|
52
|
+
case 6:
|
|
53
53
|
_yield$getListData = _context.sent;
|
|
54
54
|
_yield$getListData$da = _slicedToArray(_yield$getListData.data, 1);
|
|
55
55
|
result = _yield$getListData$da[0];
|
|
56
56
|
return _context.abrupt("return", result);
|
|
57
|
-
case
|
|
57
|
+
case 10:
|
|
58
58
|
case "end":
|
|
59
59
|
return _context.stop();
|
|
60
60
|
}
|
|
61
61
|
}, _callee);
|
|
62
62
|
}));
|
|
63
|
-
return function (_x) {
|
|
64
|
-
return
|
|
63
|
+
return function (_x, _x2) {
|
|
64
|
+
return _ref3.apply(this, arguments);
|
|
65
65
|
};
|
|
66
66
|
}();
|
|
67
67
|
}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { z, ZodSchema } from "zod";
|
|
2
2
|
import { BaseTable, GetListRelations } from "../types.js";
|
|
3
3
|
import { NodePgDatabase } from "drizzle-orm/node-postgres";
|
|
4
|
+
import { ScopeArg } from "../scope.js";
|
|
4
5
|
export declare function createGetListAction<T extends ZodSchema, TTable extends BaseTable>({ bodySchema, db, jsonArrayFields, relations, table, }: {
|
|
5
6
|
bodySchema: T;
|
|
6
7
|
db: NodePgDatabase<Record<string, unknown>>;
|
|
7
8
|
jsonArrayFields?: string[];
|
|
8
9
|
relations?: GetListRelations;
|
|
9
10
|
table: TTable;
|
|
10
|
-
}): (params: Partial<z.infer<T>> & Record<string, unknown
|
|
11
|
+
}): (params: Partial<z.infer<T>> & Record<string, unknown>, { scope }: {
|
|
12
|
+
scope: ScopeArg;
|
|
13
|
+
}) => Promise<{
|
|
11
14
|
data: any;
|
|
12
15
|
total: number;
|
|
13
16
|
}>;
|
|
@@ -14,17 +14,16 @@ export function createGetListAction(_ref) {
|
|
|
14
14
|
relations = _ref.relations,
|
|
15
15
|
table = _ref.table;
|
|
16
16
|
return /*#__PURE__*/function () {
|
|
17
|
-
var
|
|
18
|
-
var
|
|
17
|
+
var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(params, _ref2) {
|
|
18
|
+
var scope, _ref4, current, pageSize, other, fields, _i, _Object$keys, key, field, _getListQuery, query, countQuery;
|
|
19
19
|
return _regeneratorRuntime().wrap(function _callee$(_context) {
|
|
20
20
|
while (1) switch (_context.prev = _context.next) {
|
|
21
21
|
case 0:
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
// @ts-ignore
|
|
22
|
+
scope = _ref2.scope;
|
|
23
|
+
_ref4 = params, current = _ref4.current, pageSize = _ref4.pageSize, other = _objectWithoutProperties(_ref4, _excluded);
|
|
24
|
+
fields = {}; // @ts-ignore
|
|
25
25
|
for (_i = 0, _Object$keys = Object.keys(bodySchema.shape); _i < _Object$keys.length; _i++) {
|
|
26
26
|
key = _Object$keys[_i];
|
|
27
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
28
27
|
// @ts-ignore
|
|
29
28
|
field = table[key];
|
|
30
29
|
if (field) {
|
|
@@ -37,6 +36,7 @@ export function createGetListAction(_ref) {
|
|
|
37
36
|
jsonArrayFields: jsonArrayFields,
|
|
38
37
|
params: other,
|
|
39
38
|
relations: relations,
|
|
39
|
+
scope: scope,
|
|
40
40
|
table: table
|
|
41
41
|
}), query = _getListQuery.query, countQuery = _getListQuery.countQuery;
|
|
42
42
|
return _context.abrupt("return", getListData({
|
|
@@ -46,14 +46,14 @@ export function createGetListAction(_ref) {
|
|
|
46
46
|
pageSize: pageSize,
|
|
47
47
|
query: query
|
|
48
48
|
})());
|
|
49
|
-
case
|
|
49
|
+
case 6:
|
|
50
50
|
case "end":
|
|
51
51
|
return _context.stop();
|
|
52
52
|
}
|
|
53
53
|
}, _callee);
|
|
54
54
|
}));
|
|
55
|
-
return function (_x) {
|
|
56
|
-
return
|
|
55
|
+
return function (_x, _x2) {
|
|
56
|
+
return _ref3.apply(this, arguments);
|
|
57
57
|
};
|
|
58
58
|
}();
|
|
59
59
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { z, ZodSchema } from "zod";
|
|
2
2
|
import { NodePgDatabase } from "drizzle-orm/node-postgres";
|
|
3
3
|
import { BaseTable } from "../types.js";
|
|
4
|
+
import { ScopeArg } from "../scope.js";
|
|
4
5
|
export declare function createPutAction<T extends ZodSchema, TTable extends BaseTable>({ db, table, }: {
|
|
5
6
|
bodySchema: T;
|
|
6
7
|
db: NodePgDatabase<Record<string, unknown>>;
|
|
7
8
|
table: TTable;
|
|
8
|
-
}): (body: Partial<z.infer<T>> & Record<string, unknown>, {
|
|
9
|
-
|
|
9
|
+
}): (body: Partial<z.infer<T>> & Record<string, unknown>, { scope }: {
|
|
10
|
+
scope: ScopeArg;
|
|
10
11
|
}) => Promise<z.infer<T>>;
|
|
@@ -8,58 +8,43 @@ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" !=
|
|
|
8
8
|
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
9
9
|
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
10
10
|
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
11
|
-
import { z } from "zod";
|
|
12
11
|
import { transformBody } from "./transform-body.js";
|
|
13
|
-
import { eq } from "drizzle-orm";
|
|
14
|
-
import {
|
|
12
|
+
import { and, eq } from "drizzle-orm";
|
|
13
|
+
import { NO_SCOPE, scopeCondition } from "../scope.js";
|
|
15
14
|
import { HttpError } from "../errors.js";
|
|
16
15
|
export function createPutAction(_ref) {
|
|
17
16
|
var db = _ref.db,
|
|
18
17
|
table = _ref.table;
|
|
19
18
|
return /*#__PURE__*/function () {
|
|
20
|
-
var
|
|
21
|
-
var
|
|
22
|
-
_ref3$byCreator,
|
|
23
|
-
byCreator,
|
|
24
|
-
_data,
|
|
25
|
-
_yield$db$update$set$,
|
|
26
|
-
_yield$db$update$set$2,
|
|
27
|
-
data,
|
|
28
|
-
_args = arguments;
|
|
19
|
+
var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(body, _ref2) {
|
|
20
|
+
var scope, id, guard, _yield$db$update$set$, _yield$db$update$set$2, data;
|
|
29
21
|
return _regeneratorRuntime().wrap(function _callee$(_context) {
|
|
30
22
|
while (1) switch (_context.prev = _context.next) {
|
|
31
23
|
case 0:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
24
|
+
scope = _ref2.scope;
|
|
25
|
+
id = body.id;
|
|
26
|
+
if (id) {
|
|
27
|
+
_context.next = 4;
|
|
35
28
|
break;
|
|
36
29
|
}
|
|
37
|
-
|
|
38
|
-
return createGetAction({
|
|
39
|
-
db: db,
|
|
40
|
-
table: table,
|
|
41
|
-
bodySchema: z.object({
|
|
42
|
-
creatorId: z.string(),
|
|
43
|
-
id: z.string()
|
|
44
|
-
})
|
|
45
|
-
})({
|
|
46
|
-
creatorId: body.editorId,
|
|
47
|
-
id: body.id
|
|
48
|
-
});
|
|
30
|
+
throw new HttpError(400, "缺少 id");
|
|
49
31
|
case 4:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
32
|
+
// 归属条件直接写进 UPDATE 的 where,而不是「先查一次确认归属、再无条件更新」。
|
|
33
|
+
// 先查后改有两个问题:多一次往返,以及那一查一改之间归属可能已经变了(转移给团队、
|
|
34
|
+
// 踢出成员)。一条语句里带上归属,改不到就是改不到。
|
|
35
|
+
guard = scopeCondition(table, scope);
|
|
36
|
+
_context.next = 7;
|
|
37
|
+
return db.update(table).set(transformBody(body)).where(guard ? and(eq(table.id, id), guard) : eq(table.id, id)).returning();
|
|
56
38
|
case 7:
|
|
57
|
-
_context.next = 9;
|
|
58
|
-
return db.update(table).set(transformBody(body)).where(eq(table.id, body.id)).returning();
|
|
59
|
-
case 9:
|
|
60
39
|
_yield$db$update$set$ = _context.sent;
|
|
61
40
|
_yield$db$update$set$2 = _slicedToArray(_yield$db$update$set$, 1);
|
|
62
41
|
data = _yield$db$update$set$2[0];
|
|
42
|
+
if (!(!data && scope !== NO_SCOPE)) {
|
|
43
|
+
_context.next = 12;
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
throw new HttpError(404, "未找到编辑对象,或没有权限");
|
|
47
|
+
case 12:
|
|
63
48
|
return _context.abrupt("return", data);
|
|
64
49
|
case 13:
|
|
65
50
|
case "end":
|
|
@@ -67,8 +52,8 @@ export function createPutAction(_ref) {
|
|
|
67
52
|
}
|
|
68
53
|
}, _callee);
|
|
69
54
|
}));
|
|
70
|
-
return function (_x) {
|
|
71
|
-
return
|
|
55
|
+
return function (_x, _x2) {
|
|
56
|
+
return _ref3.apply(this, arguments);
|
|
72
57
|
};
|
|
73
58
|
}();
|
|
74
59
|
}
|
|
@@ -2,10 +2,17 @@ import { BaseTable, GetListRelations } from "../types.js";
|
|
|
2
2
|
import { SelectedFields } from "drizzle-orm/pg-core/query-builders/select.types";
|
|
3
3
|
import { SQL } from "drizzle-orm";
|
|
4
4
|
import { NodePgDatabase } from "drizzle-orm/node-postgres";
|
|
5
|
-
|
|
5
|
+
import { ScopeArg } from "../scope.js";
|
|
6
|
+
export declare function getListQuery<TTable extends BaseTable, TSelection extends SelectedFields>({ db, fields, jsonArrayFields, params, relations, scope, table, }: {
|
|
6
7
|
db: NodePgDatabase<Record<string, unknown>>;
|
|
7
8
|
fields: TSelection;
|
|
8
9
|
jsonArrayFields?: string[];
|
|
10
|
+
/**
|
|
11
|
+
* 行级作用域。**必填**,不想隔离就显式传 NO_SCOPE —— 写成可选的话,漏传就退化成查全表,
|
|
12
|
+
* 而那是静默的越权(见 scope.ts)。它不走下面 params 那条筛选通道,因为那条的规矩是
|
|
13
|
+
* 「空值跳过」,一个取不到值的作用域会让整条 where 消失。
|
|
14
|
+
*/
|
|
15
|
+
scope: ScopeArg;
|
|
9
16
|
params: {
|
|
10
17
|
[field: string]: unknown;
|
|
11
18
|
orderBy?: keyof BaseTable;
|