@ai0x0/utils 0.5.0 → 0.6.1
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/es/backend/actions/create-delete-action.d.ts +2 -3
- package/es/backend/actions/create-delete-action.js +8 -44
- package/es/backend/actions/create-put-action.d.ts +1 -1
- package/es/backend/actions/create-put-action.js +15 -39
- package/es/backend/actions/get-list-query-core.d.ts +46 -0
- package/es/backend/actions/get-list-query-core.js +236 -0
- package/es/backend/actions/get-list-query.d.ts +5 -18
- package/es/backend/actions/get-list-query.js +20 -220
- package/es/backend/actions/write-action-core.d.ts +18 -0
- package/es/backend/actions/write-action-core.js +119 -0
- package/es/backend/route-operation/operation-common.d.ts +13 -1
- package/es/backend/route-operation/operation-common.js +25 -0
- package/es/backend/route-operation/read-operation-core.js +46 -33
- package/es/backend/route-operation/write-operation-core.d.ts +3 -1
- package/es/backend/route-operation/write-operation-core.js +69 -26
- package/es/backend/schemas/common.d.ts +112 -0
- package/es/backend/schemas/common.js +158 -0
- package/es/backend/schemas/index.d.ts +735 -364
- package/es/backend/schemas/index.js +8 -139
- package/es/backend/sqlite/actions/create-delete-action.d.ts +1 -2
- package/es/backend/sqlite/actions/create-delete-action.js +7 -43
- package/es/backend/sqlite/actions/create-put-action.d.ts +1 -1
- package/es/backend/sqlite/actions/create-put-action.js +13 -36
- package/es/backend/sqlite/actions/get-list-query.d.ts +4 -9
- package/es/backend/sqlite/actions/get-list-query.js +20 -217
- package/es/backend/sqlite/errors.d.ts +1 -4
- package/es/backend/sqlite/errors.js +6 -31
- package/es/backend/sqlite/schemas/index.d.ts +1 -111
- package/es/backend/sqlite/schemas/index.js +8 -139
- package/lib/backend/actions/create-delete-action.d.ts +2 -3
- package/lib/backend/actions/create-delete-action.js +2 -14
- package/lib/backend/actions/create-put-action.d.ts +1 -1
- package/lib/backend/actions/create-put-action.js +3 -16
- package/lib/backend/actions/get-list-query-core.d.ts +46 -0
- package/lib/backend/actions/get-list-query-core.js +151 -0
- package/lib/backend/actions/get-list-query.d.ts +5 -18
- package/lib/backend/actions/get-list-query.js +16 -141
- package/lib/backend/actions/write-action-core.d.ts +18 -0
- package/lib/backend/actions/write-action-core.js +70 -0
- package/lib/backend/route-operation/operation-common.d.ts +13 -1
- package/lib/backend/route-operation/operation-common.js +8 -0
- package/lib/backend/route-operation/read-operation-core.js +14 -4
- package/lib/backend/route-operation/write-operation-core.d.ts +3 -1
- package/lib/backend/route-operation/write-operation-core.js +24 -4
- package/lib/backend/schemas/common.d.ts +112 -0
- package/lib/backend/schemas/common.js +112 -0
- package/lib/backend/schemas/index.d.ts +735 -364
- package/lib/backend/schemas/index.js +12 -83
- package/lib/backend/sqlite/actions/create-delete-action.d.ts +1 -2
- package/lib/backend/sqlite/actions/create-delete-action.js +2 -14
- package/lib/backend/sqlite/actions/create-put-action.d.ts +1 -1
- package/lib/backend/sqlite/actions/create-put-action.js +3 -16
- package/lib/backend/sqlite/actions/get-list-query.d.ts +4 -9
- package/lib/backend/sqlite/actions/get-list-query.js +16 -141
- package/lib/backend/sqlite/errors.d.ts +1 -4
- package/lib/backend/sqlite/errors.js +2 -8
- package/lib/backend/sqlite/schemas/index.d.ts +1 -111
- package/lib/backend/sqlite/schemas/index.js +12 -83
- package/package.json +1 -1
|
@@ -1,223 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
var _templateObject, _templateObject2, _templateObject3;
|
|
3
|
-
var _excluded = ["page", "pageSize", "orderBy", "orderDir"];
|
|
4
|
-
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
5
|
-
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
6
|
-
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
7
|
-
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
1
|
+
var _templateObject;
|
|
8
2
|
function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); } return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); }
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
function
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
export function getListQuery(_ref) {
|
|
26
|
-
var db = _ref.db,
|
|
27
|
-
fields = _ref.fields,
|
|
28
|
-
jsonArrayFields = _ref.jsonArrayFields,
|
|
29
|
-
params = _ref.params,
|
|
30
|
-
relations = _ref.relations,
|
|
31
|
-
scope = _ref.scope,
|
|
32
|
-
table = _ref.table;
|
|
33
|
-
var _params$page = params.page,
|
|
34
|
-
page = _params$page === void 0 ? 1 : _params$page,
|
|
35
|
-
_params$pageSize = params.pageSize,
|
|
36
|
-
pageSize = _params$pageSize === void 0 ? 10 : _params$pageSize,
|
|
37
|
-
_params$orderBy = params.orderBy,
|
|
38
|
-
orderBy = _params$orderBy === void 0 ? "createdAt" : _params$orderBy,
|
|
39
|
-
_params$orderDir = params.orderDir,
|
|
40
|
-
orderDir = _params$orderDir === void 0 ? "desc" : _params$orderDir,
|
|
41
|
-
filters = _objectWithoutProperties(params, _excluded);
|
|
42
|
-
|
|
43
|
-
// 构建基础查询
|
|
44
|
-
function buildBaseQuery(table, fields, relations) {
|
|
45
|
-
var queryFields = _objectSpread({}, fields);
|
|
46
|
-
|
|
47
|
-
// 添加关联字段
|
|
48
|
-
if (relations !== null && relations !== void 0 && relations.length) {
|
|
49
|
-
var _iterator = _createForOfIteratorHelper(relations),
|
|
50
|
-
_step;
|
|
51
|
-
try {
|
|
52
|
-
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
53
|
-
var select = _step.value.select;
|
|
54
|
-
queryFields = _objectSpread(_objectSpread({}, queryFields), select);
|
|
55
|
-
}
|
|
56
|
-
} catch (err) {
|
|
57
|
-
_iterator.e(err);
|
|
58
|
-
} finally {
|
|
59
|
-
_iterator.f();
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
var query = db.select(queryFields).from(table);
|
|
63
|
-
|
|
64
|
-
// 添加分组
|
|
65
|
-
if (relations !== null && relations !== void 0 && relations.length) {
|
|
66
|
-
query.groupBy.apply(query, [table.id].concat(_toConsumableArray(relations.filter(function (_ref2) {
|
|
67
|
-
var groupBy = _ref2.groupBy;
|
|
68
|
-
return groupBy;
|
|
69
|
-
}).filter(function (_ref3) {
|
|
70
|
-
var table = _ref3.table;
|
|
71
|
-
return table;
|
|
72
|
-
}).map(function (_ref4) {
|
|
73
|
-
var table = _ref4.table;
|
|
74
|
-
return table.id;
|
|
75
|
-
}))));
|
|
76
|
-
}
|
|
77
|
-
return query;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// 查找目标列
|
|
81
|
-
function findTargetColumn(key, table, relations) {
|
|
82
|
-
var _concat$find;
|
|
83
|
-
return (_concat$find = [table].concat((relations === null || relations === void 0 ? void 0 : relations.filter(function (_ref5) {
|
|
84
|
-
var table = _ref5.table;
|
|
85
|
-
return table;
|
|
86
|
-
}).map(function (_ref6) {
|
|
87
|
-
var table = _ref6.table;
|
|
88
|
-
return table;
|
|
89
|
-
})) || []).find(function (table) {
|
|
90
|
-
return table[key];
|
|
91
|
-
})) === null || _concat$find === void 0 ? void 0 : _concat$find[key];
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// 添加条件
|
|
95
|
-
function addCondition(conditions, key, value, targetColumn) {
|
|
96
|
-
var isIdField = /id/i.test(key);
|
|
97
|
-
var isJsonArray = jsonArrayFields === null || jsonArrayFields === void 0 ? void 0 : jsonArrayFields.includes(key);
|
|
98
|
-
if (typeof value === "string") {
|
|
99
|
-
if (value.includes(",")) {
|
|
100
|
-
// 处理多值
|
|
101
|
-
var values = value.split(",").map(function (val) {
|
|
102
|
-
return val.trim();
|
|
103
|
-
}).filter(Boolean);
|
|
104
|
-
if (values.length > 0) {
|
|
105
|
-
if (isJsonArray) {
|
|
106
|
-
// 处理JSONB数组字段
|
|
107
|
-
conditions.push(sql(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n EXISTS (\n SELECT 1 FROM jsonb_array_elements_text(", ") tag\n WHERE tag LIKE ", "\n )\n "])), targetColumn, "%".concat(values[0], "%")));
|
|
108
|
-
} else if (isIdField) {
|
|
109
|
-
conditions.push(inArray(targetColumn, values));
|
|
110
|
-
} else {
|
|
111
|
-
conditions.push(or.apply(void 0, _toConsumableArray(values.map(function (val) {
|
|
112
|
-
return ilike(targetColumn, "%".concat(val, "%"));
|
|
113
|
-
}))));
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
} else {
|
|
117
|
-
// 处理单值
|
|
118
|
-
if (isJsonArray) {
|
|
119
|
-
// 处理JSONB数组字段
|
|
120
|
-
conditions.push(sql(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n EXISTS (\n SELECT 1 FROM jsonb_array_elements_text(", ") tag\n WHERE tag LIKE ", "\n )\n "])), targetColumn, "%".concat(value, "%")));
|
|
121
|
-
} else if (isIdField) {
|
|
122
|
-
conditions.push(eq(targetColumn, value));
|
|
123
|
-
} else {
|
|
124
|
-
conditions.push(ilike(targetColumn, "%".concat(value, "%")));
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
} else {
|
|
128
|
-
conditions.push(eq(targetColumn, value));
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// 构建查询条件
|
|
133
|
-
function buildConditions(filters, table, relations) {
|
|
134
|
-
var conditions = [];
|
|
135
|
-
|
|
136
|
-
// 处理过滤条件
|
|
137
|
-
for (var _i = 0, _Object$entries = Object.entries(filters); _i < _Object$entries.length; _i++) {
|
|
138
|
-
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
139
|
-
key = _Object$entries$_i[0],
|
|
140
|
-
value = _Object$entries$_i[1];
|
|
141
|
-
if (!value) {
|
|
142
|
-
continue;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// 处理日期范围字段
|
|
146
|
-
if (key.endsWith("AtFrom") || key.endsWith("AtTo")) {
|
|
147
|
-
var baseFieldName = key.replace(/(AtFrom|AtTo)$/, "");
|
|
148
|
-
var _targetColumn = findTargetColumn("".concat(baseFieldName, "At"), table, relations);
|
|
149
|
-
if (!_targetColumn) {
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
if (key.endsWith("AtFrom")) {
|
|
153
|
-
conditions.push(gte(_targetColumn, new Date(value)));
|
|
154
|
-
} else if (key.endsWith("AtTo")) {
|
|
155
|
-
conditions.push(lte(_targetColumn, new Date(value)));
|
|
156
|
-
}
|
|
157
|
-
continue;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// 处理其他普通过滤条件
|
|
161
|
-
var targetColumn = findTargetColumn(key, table, relations);
|
|
162
|
-
if (!targetColumn) {
|
|
163
|
-
continue;
|
|
164
|
-
}
|
|
165
|
-
addCondition(conditions, key, value, targetColumn);
|
|
166
|
-
}
|
|
167
|
-
return conditions;
|
|
3
|
+
// ==============================================================================
|
|
4
|
+
// 列表查询(Postgres)
|
|
5
|
+
// ==============================================================================
|
|
6
|
+
// 实现在 get-list-query-core,两套方言共用。这里只给它两条 pg 专属的原语,外加把签名收紧到
|
|
7
|
+
// pg 的类型上 —— 核心为了同时喂 sqlite,db 那一栏是宽的,调用方不该跟着变宽。
|
|
8
|
+
|
|
9
|
+
import { ilike, sql } from "drizzle-orm";
|
|
10
|
+
import { createGetListQuery } from "./get-list-query-core.js";
|
|
11
|
+
var run = createGetListQuery({
|
|
12
|
+
contains: function contains(column, keyword) {
|
|
13
|
+
return ilike(column, "%".concat(keyword, "%"));
|
|
14
|
+
},
|
|
15
|
+
// jsonb 数组展开成行再逐个 LIKE。列存的是 text[] 形状的 jsonb(见 createTableSchema 的
|
|
16
|
+
// jsonArrayFields),所以用 _text 那个变体,取到的 tag 直接就是字符串。
|
|
17
|
+
jsonArrayContains: function jsonArrayContains(column, keyword) {
|
|
18
|
+
return sql(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n EXISTS (\n SELECT 1 FROM jsonb_array_elements_text(", ") tag\n WHERE tag LIKE ", "\n )\n "])), column, "%".concat(keyword, "%"));
|
|
168
19
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
var orderColumn = table[orderBy];
|
|
173
|
-
return orderDir === "asc" ? asc(orderColumn) : desc(orderColumn);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// 构建基础查询
|
|
177
|
-
var baseQuery = buildBaseQuery(table, fields, relations);
|
|
178
|
-
|
|
179
|
-
// 构建条件。**作用域先于筛选加进去**,且它不受 buildConditions 里「空值跳过」那条规矩管:
|
|
180
|
-
// 那条规矩对 `?name=` 这种空参数是对的,对归属则是灾难性的 —— 条件消失即全表可见。
|
|
181
|
-
var scopeSql = scopeCondition(table, scope);
|
|
182
|
-
var conditions = scopeSql ? [scopeSql] : [];
|
|
183
|
-
conditions.push.apply(conditions, _toConsumableArray(buildConditions(filters, table, relations)));
|
|
184
|
-
|
|
185
|
-
// 构建主查询
|
|
186
|
-
var query = baseQuery.where(conditions.length > 0 ? and.apply(void 0, conditions) : undefined).orderBy(buildOrderBy(table, orderBy, orderDir))
|
|
187
|
-
|
|
188
|
-
// @ts-ignore
|
|
189
|
-
.limit(pageSize).offset((page - 1) * pageSize);
|
|
190
|
-
|
|
191
|
-
// 构建计数查询(优化后)
|
|
192
|
-
var countQuery = db.select({
|
|
193
|
-
count: sql(_templateObject3 || (_templateObject3 = _taggedTemplateLiteral(["COUNT(DISTINCT ", ")"])), table.id)
|
|
194
|
-
}).from(table).where(conditions.length > 0 ? and.apply(void 0, conditions) : undefined);
|
|
195
|
-
|
|
196
|
-
// 添加关联
|
|
197
|
-
if (relations !== null && relations !== void 0 && relations.length) {
|
|
198
|
-
var _iterator2 = _createForOfIteratorHelper(relations),
|
|
199
|
-
_step2;
|
|
200
|
-
try {
|
|
201
|
-
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
202
|
-
var _step2$value = _step2.value,
|
|
203
|
-
relationTable = _step2$value.table,
|
|
204
|
-
joinSql = _step2$value.sql;
|
|
205
|
-
if (relationTable) {
|
|
206
|
-
query.leftJoin(relationTable, joinSql);
|
|
207
|
-
countQuery.leftJoin(relationTable, joinSql);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
} catch (err) {
|
|
211
|
-
_iterator2.e(err);
|
|
212
|
-
} finally {
|
|
213
|
-
_iterator2.f();
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// console.log(query.prepare("a").getQuery());
|
|
218
|
-
|
|
219
|
-
return {
|
|
220
|
-
countQuery: countQuery,
|
|
221
|
-
query: query
|
|
222
|
-
};
|
|
20
|
+
});
|
|
21
|
+
export function getListQuery(args) {
|
|
22
|
+
return run(args);
|
|
223
23
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ScopeArg } from "../scope.js";
|
|
2
|
+
/** 核心用得到表的哪一部分:只有 id。dialect 各自的 Table 类型不进来。 */
|
|
3
|
+
export interface WriteActionTable {
|
|
4
|
+
id: unknown;
|
|
5
|
+
}
|
|
6
|
+
interface WriteActionDeps<TTable extends WriteActionTable> {
|
|
7
|
+
db: any;
|
|
8
|
+
table: TTable;
|
|
9
|
+
}
|
|
10
|
+
export declare function createPutActionCore<TTable extends WriteActionTable>({ db, table, }: WriteActionDeps<TTable>): (body: Record<string, unknown>, { scope }: {
|
|
11
|
+
scope: ScopeArg;
|
|
12
|
+
}) => Promise<unknown>;
|
|
13
|
+
export declare function createDeleteActionCore<TTable extends WriteActionTable>({ db, table, }: WriteActionDeps<TTable>): ({ id }: {
|
|
14
|
+
id: string;
|
|
15
|
+
}, { scope }: {
|
|
16
|
+
scope: ScopeArg;
|
|
17
|
+
}) => Promise<any>;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
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
|
+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
4
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
5
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
6
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
7
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
8
|
+
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
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
|
+
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
|
+
// ==============================================================================
|
|
12
|
+
// 单行写操作的公共实现(pg / sqlite 共用)
|
|
13
|
+
// ==============================================================================
|
|
14
|
+
// 改一行、删一行,两套方言的函数体逐字相同 —— 差的只有 db 的类型(NodePgDatabase vs any)
|
|
15
|
+
// 和一句给 scopeCondition 的断言。而这两个函数里恰恰藏着三条**安全性质**,抄两份意味着
|
|
16
|
+
// 三条都要在两棵树上各维护一遍:
|
|
17
|
+
//
|
|
18
|
+
// 1. **归属写进 where,不先查后改**。先查一次确认归属、再无条件写,中间那一瞬归属可能已经
|
|
19
|
+
// 变了(转移给团队、被踢出成员);一条语句里带上归属,改不到就是改不到。
|
|
20
|
+
// 2. **作用域必填**(不隔离要显式传 NO_SCOPE)。这里原先是可选的 creatorId + `if (有值)
|
|
21
|
+
// 才校验`,于是未登录传下来的空值直接变成「不校验、按 id 删任意行」。
|
|
22
|
+
// 3. **不区分「不存在」与「不归你」**。分得清就等于给了一个探测接口:拿 id 挨个试就能问出
|
|
23
|
+
// 某条记录存不存在。
|
|
24
|
+
//
|
|
25
|
+
// 这三条现在只有一份。两个方言各自的薄封装只负责把签名收紧回本方言的类型。
|
|
26
|
+
|
|
27
|
+
import { and, eq } from "drizzle-orm";
|
|
28
|
+
import { NO_SCOPE, scopeCondition } from "../scope.js";
|
|
29
|
+
import { HttpError } from "../errors.js";
|
|
30
|
+
import { transformBody } from "./transform-body.js";
|
|
31
|
+
|
|
32
|
+
/** 核心用得到表的哪一部分:只有 id。dialect 各自的 Table 类型不进来。 */
|
|
33
|
+
|
|
34
|
+
// id 那一列在两边都是 Column,但类型不同;比较条件交给 drizzle 自己去解。
|
|
35
|
+
function byId(table, id, scope) {
|
|
36
|
+
var guard = scopeCondition(table, scope);
|
|
37
|
+
var same = eq(table.id, id);
|
|
38
|
+
return guard ? and(same, guard) : same;
|
|
39
|
+
}
|
|
40
|
+
export function createPutActionCore(_ref) {
|
|
41
|
+
var db = _ref.db,
|
|
42
|
+
table = _ref.table;
|
|
43
|
+
return /*#__PURE__*/function () {
|
|
44
|
+
var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(body, _ref2) {
|
|
45
|
+
var scope, id, _yield$db$update$set$, _yield$db$update$set$2, data;
|
|
46
|
+
return _regeneratorRuntime().wrap(function _callee$(_context) {
|
|
47
|
+
while (1) switch (_context.prev = _context.next) {
|
|
48
|
+
case 0:
|
|
49
|
+
scope = _ref2.scope;
|
|
50
|
+
id = body.id;
|
|
51
|
+
if (id) {
|
|
52
|
+
_context.next = 4;
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
throw new HttpError(400, "缺少 id");
|
|
56
|
+
case 4:
|
|
57
|
+
_context.next = 6;
|
|
58
|
+
return db.update(table).set(transformBody(body)).where(byId(table, id, scope)).returning();
|
|
59
|
+
case 6:
|
|
60
|
+
_yield$db$update$set$ = _context.sent;
|
|
61
|
+
_yield$db$update$set$2 = _slicedToArray(_yield$db$update$set$, 1);
|
|
62
|
+
data = _yield$db$update$set$2[0];
|
|
63
|
+
if (!(!data && scope !== NO_SCOPE)) {
|
|
64
|
+
_context.next = 11;
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
throw new HttpError(404, "未找到编辑对象,或没有权限");
|
|
68
|
+
case 11:
|
|
69
|
+
return _context.abrupt("return", data);
|
|
70
|
+
case 12:
|
|
71
|
+
case "end":
|
|
72
|
+
return _context.stop();
|
|
73
|
+
}
|
|
74
|
+
}, _callee);
|
|
75
|
+
}));
|
|
76
|
+
return function (_x, _x2) {
|
|
77
|
+
return _ref3.apply(this, arguments);
|
|
78
|
+
};
|
|
79
|
+
}();
|
|
80
|
+
}
|
|
81
|
+
export function createDeleteActionCore(_ref4) {
|
|
82
|
+
var db = _ref4.db,
|
|
83
|
+
table = _ref4.table;
|
|
84
|
+
return /*#__PURE__*/function () {
|
|
85
|
+
var _ref7 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(_ref5, _ref6) {
|
|
86
|
+
var id, scope, rows;
|
|
87
|
+
return _regeneratorRuntime().wrap(function _callee2$(_context2) {
|
|
88
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
89
|
+
case 0:
|
|
90
|
+
id = _ref5.id;
|
|
91
|
+
scope = _ref6.scope;
|
|
92
|
+
if (id) {
|
|
93
|
+
_context2.next = 4;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
throw new HttpError(400, "缺少 id");
|
|
97
|
+
case 4:
|
|
98
|
+
_context2.next = 6;
|
|
99
|
+
return db.delete(table).where(byId(table, id, scope)).returning();
|
|
100
|
+
case 6:
|
|
101
|
+
rows = _context2.sent;
|
|
102
|
+
if (!(rows.length === 0 && scope !== NO_SCOPE)) {
|
|
103
|
+
_context2.next = 9;
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
throw new HttpError(404, "未找到删除对象,或没有权限");
|
|
107
|
+
case 9:
|
|
108
|
+
return _context2.abrupt("return", rows);
|
|
109
|
+
case 10:
|
|
110
|
+
case "end":
|
|
111
|
+
return _context2.stop();
|
|
112
|
+
}
|
|
113
|
+
}, _callee2);
|
|
114
|
+
}));
|
|
115
|
+
return function (_x3, _x4) {
|
|
116
|
+
return _ref7.apply(this, arguments);
|
|
117
|
+
};
|
|
118
|
+
}();
|
|
119
|
+
}
|
|
@@ -8,6 +8,18 @@ export type RouteCatch = (error: Error) => Promise<JsonResponse | undefined>;
|
|
|
8
8
|
export interface DefaultSession {
|
|
9
9
|
userId?: string;
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* 「这次请求是谁发的」。四个方法都会把它盖进 params.callerId,自定义 handler 判权、署名、
|
|
13
|
+
* 判「是不是本人」一律读它。
|
|
14
|
+
*
|
|
15
|
+
* **不要拿 params.creatorId 当调用者用。** 那是另一件事:POST 上的 creatorId 是**归属戳**
|
|
16
|
+
* (access.scope 指的那一列,换成 ownerId 时它就不叫 creatorId 了),PUT 上的 editorId 是要
|
|
17
|
+
* 写进行里的**审计列**。两者都恰好等于调用者只是默认配置下的巧合。
|
|
18
|
+
*
|
|
19
|
+
* 会话形状是泛型的(调用方可以塞自己的 Scope 进来),所以这里按 DefaultSession 取 userId ——
|
|
20
|
+
* 自定义会话只要带着这个字段就通用。
|
|
21
|
+
*/
|
|
22
|
+
export declare function callerIdOf(session: unknown): string | undefined;
|
|
11
23
|
/**
|
|
12
24
|
* 会话读取器。泛型化是为了让调用方能在这里一次性解析出「你是谁 + 你现在站在哪个空间 +
|
|
13
25
|
* 你在那个空间里是什么角色」,后面 access.scope / access.can 都读同一份,不必各自再查一遍库。
|
|
@@ -99,7 +111,7 @@ export declare function getDefaultTags<TTable>({ getTableName, table, }: {
|
|
|
99
111
|
table?: TTable;
|
|
100
112
|
}): string[];
|
|
101
113
|
export type GetOperationParams<Q extends ZodSchema> = z.infer<Q> & Record<string, unknown> & {
|
|
102
|
-
|
|
114
|
+
callerId?: string;
|
|
103
115
|
};
|
|
104
116
|
/**
|
|
105
117
|
* 读操作的参数与作用域。
|
|
@@ -17,6 +17,21 @@ import { isEmptyScopeValue, NO_SCOPE } from "../scope.js";
|
|
|
17
17
|
|
|
18
18
|
/** 默认的会话形状。够用于「一条记录属于一个人」的场景。 */
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* 「这次请求是谁发的」。四个方法都会把它盖进 params.callerId,自定义 handler 判权、署名、
|
|
22
|
+
* 判「是不是本人」一律读它。
|
|
23
|
+
*
|
|
24
|
+
* **不要拿 params.creatorId 当调用者用。** 那是另一件事:POST 上的 creatorId 是**归属戳**
|
|
25
|
+
* (access.scope 指的那一列,换成 ownerId 时它就不叫 creatorId 了),PUT 上的 editorId 是要
|
|
26
|
+
* 写进行里的**审计列**。两者都恰好等于调用者只是默认配置下的巧合。
|
|
27
|
+
*
|
|
28
|
+
* 会话形状是泛型的(调用方可以塞自己的 Scope 进来),所以这里按 DefaultSession 取 userId ——
|
|
29
|
+
* 自定义会话只要带着这个字段就通用。
|
|
30
|
+
*/
|
|
31
|
+
export function callerIdOf(session) {
|
|
32
|
+
return session === null || session === void 0 ? void 0 : session.userId;
|
|
33
|
+
}
|
|
34
|
+
|
|
20
35
|
/**
|
|
21
36
|
* 会话读取器。泛型化是为了让调用方能在这里一次性解析出「你是谁 + 你现在站在哪个空间 +
|
|
22
37
|
* 你在那个空间里是什么角色」,后面 access.scope / access.can 都读同一份,不必各自再查一遍库。
|
|
@@ -245,6 +260,13 @@ export function getDefaultTags(_ref3) {
|
|
|
245
260
|
// 读操作的参数
|
|
246
261
|
// ==============================================================================
|
|
247
262
|
|
|
263
|
+
// callerId 是服务端盖的,**不是** query 里来的:调用方在地址栏上写 `?callerId=别人`
|
|
264
|
+
// 覆盖不了它(下面 getReadParams 里它最后展开)。
|
|
265
|
+
//
|
|
266
|
+
// 这里原先声明的是 `creatorId?: string`,而读操作从来没有填过它 —— 类型说有、运行时没有,
|
|
267
|
+
// 于是 `if (!params.creatorId) throw 401` 这种判权写法编译绿灯、线上对所有人 401。
|
|
268
|
+
// 那个字段已经删掉:要调用者就用 callerId,要按创建者筛就在 query schema 里显式声明一个。
|
|
269
|
+
|
|
248
270
|
/**
|
|
249
271
|
* 读操作的参数与作用域。
|
|
250
272
|
*
|
|
@@ -284,6 +306,9 @@ function _getReadParams() {
|
|
|
284
306
|
session = _yield$resolveAccess.session;
|
|
285
307
|
queryParams = schemas.query.parse(Object.fromEntries(new URL(req.url).searchParams));
|
|
286
308
|
return _context4.abrupt("return", {
|
|
309
|
+
// 这一份**不带 callerId**:它会被当成筛选条件送进查询构造器,而 callerId 不是任何表的列。
|
|
310
|
+
// 列表那边认不出的键会跳过(get-list-query 的 `if (!targetColumn) continue`),但别指望
|
|
311
|
+
// 这条兜底 —— 交给 handler 的那一份在 read-operation-core 里单独拼,见那里。
|
|
287
312
|
params: _objectSpread(_objectSpread({}, queryParams), extraParams),
|
|
288
313
|
scope: scope,
|
|
289
314
|
session: session
|