@ai0x0/utils 0.3.0 → 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/es/backend/schemas/index.d.ts +21 -1
- package/es/backend/schemas/index.js +33 -17
- package/es/backend/sqlite/schemas/index.d.ts +11 -0
- package/es/backend/sqlite/schemas/index.js +33 -17
- package/lib/backend/schemas/index.d.ts +21 -1
- package/lib/backend/schemas/index.js +32 -12
- package/lib/backend/sqlite/schemas/index.d.ts +11 -0
- package/lib/backend/sqlite/schemas/index.js +33 -12
- package/package.json +1 -1
|
@@ -113,13 +113,33 @@ export declare const listBodySchema: <T extends z.ZodType<unknown, unknown, z.co
|
|
|
113
113
|
total: z.ZodNumber;
|
|
114
114
|
data: z.ZodArray<T>;
|
|
115
115
|
}, z.core.$strip>;
|
|
116
|
+
/**
|
|
117
|
+
* 给 schema 上已有的字段挂说明。字段不在这个 schema 里就跳过 —— 同一张表的
|
|
118
|
+
* insert / update / select 三份含的列不一样(basicFields 只在 select 里),一份说明表要能同时
|
|
119
|
+
* 喂给三者,就不能对「字段一定存在」有要求。**不给不存在的字段凭空造一个。**
|
|
120
|
+
*/
|
|
121
|
+
export declare const describeFields: <T extends z.ZodObject<z.core.$ZodLooseShape, z.core.$strip>>(schema: T, notes: Record<string, string>) => T;
|
|
116
122
|
/**
|
|
117
123
|
* 基于 drizzle + drizzle-zod 快速生成带基础字段(id / 创建时间等)的
|
|
118
124
|
* 表定义以及 select / insert / update / query / list zod schema。
|
|
119
125
|
*/
|
|
120
|
-
export declare const createTableSchema: <TTableName extends string, TColumnsMap extends Record<string, PgColumnBuilderBase<import("drizzle-orm").ColumnBuilderBaseConfig<import("drizzle-orm").ColumnDataType, string>, object>>, TServerColumns extends Record<string, PgColumnBuilderBase<import("drizzle-orm").ColumnBuilderBaseConfig<import("drizzle-orm").ColumnDataType, string>, object>> = {}>({ name, columns, serverColumns, extraConfig, }: {
|
|
126
|
+
export declare const createTableSchema: <TTableName extends string, TColumnsMap extends Record<string, PgColumnBuilderBase<import("drizzle-orm").ColumnBuilderBaseConfig<import("drizzle-orm").ColumnDataType, string>, object>>, TServerColumns extends Record<string, PgColumnBuilderBase<import("drizzle-orm").ColumnBuilderBaseConfig<import("drizzle-orm").ColumnDataType, string>, object>> = {}>({ name, columns, serverColumns, extraConfig, describe, }: {
|
|
121
127
|
/** 客户端能写的业务列。insert / update schema 只从这里推。 */
|
|
122
128
|
columns: TColumnsMap;
|
|
129
|
+
/**
|
|
130
|
+
* 每一列的说明,键是列名。**同时挂到 insert / update / select 三份 schema 上** —— 同一列在
|
|
131
|
+
* 请求体里和响应里是同一个东西,说明没有理由写两遍。
|
|
132
|
+
*
|
|
133
|
+
* 为什么需要这个参数:drizzle 列没有「描述」这个概念,而 `.describe()` 只能挂在 zod 上。不给
|
|
134
|
+
* 这条路,业务侧就只能在每张表后面自己把三份 schema 各 `.extend()` 一遍 —— 那是三份副本,
|
|
135
|
+
* 而副本会漂。
|
|
136
|
+
*
|
|
137
|
+
* 键有类型约束(列名的联合),所以列改名了、拼错了都是编译错误,不是静默失效。
|
|
138
|
+
*
|
|
139
|
+
* 说明会出现在 OpenAPI spec 里,再流进按 spec 生成的 client 与文档 —— 所以它是写给调用方
|
|
140
|
+
* 看的:这一列是什么、合法值从哪来、不传会怎样。
|
|
141
|
+
*/
|
|
142
|
+
describe?: Partial<Record<Extract<keyof TColumnsMap, string> | Extract<keyof TServerColumns, string>, string>> | undefined;
|
|
123
143
|
name: TTableName;
|
|
124
144
|
/**
|
|
125
145
|
* 由服务端盖、**绝不接受客户端传**的业务列:承载归属的 `ownerId`(配合
|
|
@@ -99,10 +99,12 @@ export var queryListSchema = function queryListSchema(schema) {
|
|
|
99
99
|
// =============================================================================
|
|
100
100
|
// 列表返回字段
|
|
101
101
|
// =============================================================================
|
|
102
|
+
// 这两个字段出现在**每一个** list 端点的响应里,所以说明写在这儿一次就够 —— 下游那边它们是
|
|
103
|
+
// 逐个 list 命令重复一遍的(在一个 101 端点的项目上是 24 行空白)。
|
|
102
104
|
export var listBodySchema = function listBodySchema(schema) {
|
|
103
105
|
return z.object({
|
|
104
|
-
total: z.number(),
|
|
105
|
-
data: z.array(schema)
|
|
106
|
+
total: z.number().describe("Total number of rows matching the filters — not the length of `data`. Use it to decide whether another page exists."),
|
|
107
|
+
data: z.array(schema).describe("This page's rows.")
|
|
106
108
|
});
|
|
107
109
|
};
|
|
108
110
|
|
|
@@ -136,32 +138,42 @@ var BASIC_TIMESTAMP_NOTES = {
|
|
|
136
138
|
createdAt: "When this row was created.",
|
|
137
139
|
updatedAt: "When this row was last modified."
|
|
138
140
|
};
|
|
139
|
-
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* 给 schema 上已有的字段挂说明。字段不在这个 schema 里就跳过 —— 同一张表的
|
|
144
|
+
* insert / update / select 三份含的列不一样(basicFields 只在 select 里),一份说明表要能同时
|
|
145
|
+
* 喂给三者,就不能对「字段一定存在」有要求。**不给不存在的字段凭空造一个。**
|
|
146
|
+
*/
|
|
147
|
+
export var describeFields = function describeFields(schema, notes) {
|
|
140
148
|
var overlay = {};
|
|
141
|
-
for (var _i = 0, _Object$entries = Object.entries(
|
|
149
|
+
for (var _i = 0, _Object$entries = Object.entries(notes); _i < _Object$entries.length; _i++) {
|
|
142
150
|
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
143
151
|
field = _Object$entries$_i[0],
|
|
144
152
|
note = _Object$entries$_i[1];
|
|
145
153
|
var existing = schema.shape[field];
|
|
146
|
-
// 表里没这一列就跳过 —— 不给不存在的字段凭空造一个。
|
|
147
154
|
if (existing) {
|
|
148
155
|
overlay[field] = existing.describe(note);
|
|
149
156
|
}
|
|
150
157
|
}
|
|
158
|
+
return Object.keys(overlay).length ? schema.extend(overlay) : schema;
|
|
159
|
+
};
|
|
160
|
+
var describeBasicFields = function describeBasicFields(schema) {
|
|
161
|
+
var withNotes = describeFields(schema, BASIC_FIELD_NOTES);
|
|
162
|
+
var overlay = {};
|
|
151
163
|
for (var _i2 = 0, _Object$entries2 = Object.entries(BASIC_TIMESTAMP_NOTES); _i2 < _Object$entries2.length; _i2++) {
|
|
152
164
|
var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
var
|
|
156
|
-
if (
|
|
157
|
-
overlay[
|
|
158
|
-
description:
|
|
165
|
+
field = _Object$entries2$_i[0],
|
|
166
|
+
note = _Object$entries2$_i[1];
|
|
167
|
+
var existing = withNotes.shape[field];
|
|
168
|
+
if (existing) {
|
|
169
|
+
overlay[field] = existing.meta({
|
|
170
|
+
description: note,
|
|
159
171
|
format: "date-time",
|
|
160
172
|
type: "string"
|
|
161
173
|
});
|
|
162
174
|
}
|
|
163
175
|
}
|
|
164
|
-
return
|
|
176
|
+
return Object.keys(overlay).length ? withNotes.extend(overlay) : withNotes;
|
|
165
177
|
};
|
|
166
178
|
|
|
167
179
|
// =============================================================================
|
|
@@ -175,17 +187,21 @@ export var createTableSchema = function createTableSchema(_ref) {
|
|
|
175
187
|
var name = _ref.name,
|
|
176
188
|
columns = _ref.columns,
|
|
177
189
|
serverColumns = _ref.serverColumns,
|
|
178
|
-
extraConfig = _ref.extraConfig
|
|
190
|
+
extraConfig = _ref.extraConfig,
|
|
191
|
+
describe = _ref.describe;
|
|
179
192
|
var mergedColumns = _objectSpread(_objectSpread(_objectSpread({}, basicFields), serverColumns), columns);
|
|
180
193
|
var table = pgTable(name, mergedColumns, extraConfig);
|
|
181
|
-
|
|
194
|
+
|
|
195
|
+
// 同一份说明喂给三份 schema:含哪些列各不相同,describeFields 会跳过不存在的。
|
|
196
|
+
var notes = describe !== null && describe !== void 0 ? describe : {};
|
|
197
|
+
var selectSchema = describeFields(describeBasicFields(createSelectSchema(table)), notes);
|
|
182
198
|
// 只从 columns 推 —— basicFields 与 serverColumns 都由服务端写,不该出现在请求体里。
|
|
183
|
-
var insertSchema = createInsertSchema(pgTable(name, columns));
|
|
184
|
-
var updateSchema = createUpdateSchema(pgTable(name, _objectSpread({
|
|
199
|
+
var insertSchema = describeFields(createInsertSchema(pgTable(name, columns)), notes);
|
|
200
|
+
var updateSchema = describeFields(createUpdateSchema(pgTable(name, _objectSpread({
|
|
185
201
|
id: uuid("id")
|
|
186
202
|
}, columns))).extend({
|
|
187
203
|
id: z.string().describe("Id of the row to update.")
|
|
188
|
-
});
|
|
204
|
+
}), notes);
|
|
189
205
|
var querySchema = z.object({
|
|
190
206
|
id: z.string().describe("Id of the row to fetch.")
|
|
191
207
|
});
|
|
@@ -113,6 +113,12 @@ export declare const listBodySchema: <T extends z.ZodType<unknown, unknown, z.co
|
|
|
113
113
|
total: z.ZodNumber;
|
|
114
114
|
data: z.ZodArray<T>;
|
|
115
115
|
}, z.core.$strip>;
|
|
116
|
+
/**
|
|
117
|
+
* 给 schema 上已有的字段挂说明。字段不在这个 schema 里就跳过 —— 同一张表的
|
|
118
|
+
* insert / update / select 三份含的列不一样(basicFields 只在 select 里),一份说明表要能同时
|
|
119
|
+
* 喂给三者,就不能对「字段一定存在」有要求。**不给不存在的字段凭空造一个。**
|
|
120
|
+
*/
|
|
121
|
+
export declare const describeFields: <T extends z.ZodObject<z.core.$ZodLooseShape, z.core.$strip>>(schema: T, notes: Record<string, string>) => T;
|
|
116
122
|
/**
|
|
117
123
|
* 基于 drizzle + drizzle-zod 快速生成带基础字段(id / 创建时间等)的
|
|
118
124
|
* 表定义以及 select / insert / update / query / list zod schema。
|
|
@@ -121,6 +127,11 @@ export declare const createTableSchema: <TTableName extends string, TColumnsMap
|
|
|
121
127
|
name: TTableName;
|
|
122
128
|
/** 客户端能写的业务列。insert / update schema 只从这里推。 */
|
|
123
129
|
columns: TColumnsMap;
|
|
130
|
+
/**
|
|
131
|
+
* 每一列的说明,键是列名。同时挂到 insert / update / select 三份 schema 上。语义与 pg 版
|
|
132
|
+
* 一致,见那边的说明。
|
|
133
|
+
*/
|
|
134
|
+
describe?: Partial<Record<string, string>>;
|
|
124
135
|
/** 由服务端盖、绝不接受客户端传的业务列(归属、租户 id 这类)。语义与 pg 版一致,见那边的说明。 */
|
|
125
136
|
serverColumns?: Record<string, SQLiteColumnBuilderBase>;
|
|
126
137
|
extraConfig?: (_self: BuildExtraConfigColumns<TTableName, typeof basicFields & TColumnsMap, "sqlite">) => SQLiteTableExtraConfigValue[];
|
|
@@ -105,10 +105,12 @@ export var queryListSchema = function queryListSchema(schema) {
|
|
|
105
105
|
// =============================================================================
|
|
106
106
|
// 列表返回字段
|
|
107
107
|
// =============================================================================
|
|
108
|
+
// 这两个字段出现在**每一个** list 端点的响应里,所以说明写在这儿一次就够 —— 下游那边它们是
|
|
109
|
+
// 逐个 list 命令重复一遍的(在一个 101 端点的项目上是 24 行空白)。
|
|
108
110
|
export var listBodySchema = function listBodySchema(schema) {
|
|
109
111
|
return z.object({
|
|
110
|
-
total: z.number(),
|
|
111
|
-
data: z.array(schema)
|
|
112
|
+
total: z.number().describe("Total number of rows matching the filters — not the length of `data`. Use it to decide whether another page exists."),
|
|
113
|
+
data: z.array(schema).describe("This page's rows.")
|
|
112
114
|
});
|
|
113
115
|
};
|
|
114
116
|
|
|
@@ -142,32 +144,42 @@ var BASIC_TIMESTAMP_NOTES = {
|
|
|
142
144
|
createdAt: "When this row was created.",
|
|
143
145
|
updatedAt: "When this row was last modified."
|
|
144
146
|
};
|
|
145
|
-
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* 给 schema 上已有的字段挂说明。字段不在这个 schema 里就跳过 —— 同一张表的
|
|
150
|
+
* insert / update / select 三份含的列不一样(basicFields 只在 select 里),一份说明表要能同时
|
|
151
|
+
* 喂给三者,就不能对「字段一定存在」有要求。**不给不存在的字段凭空造一个。**
|
|
152
|
+
*/
|
|
153
|
+
export var describeFields = function describeFields(schema, notes) {
|
|
146
154
|
var overlay = {};
|
|
147
|
-
for (var _i = 0, _Object$entries = Object.entries(
|
|
155
|
+
for (var _i = 0, _Object$entries = Object.entries(notes); _i < _Object$entries.length; _i++) {
|
|
148
156
|
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
149
157
|
field = _Object$entries$_i[0],
|
|
150
158
|
note = _Object$entries$_i[1];
|
|
151
159
|
var existing = schema.shape[field];
|
|
152
|
-
// 表里没这一列就跳过 —— 不给不存在的字段凭空造一个。
|
|
153
160
|
if (existing) {
|
|
154
161
|
overlay[field] = existing.describe(note);
|
|
155
162
|
}
|
|
156
163
|
}
|
|
164
|
+
return Object.keys(overlay).length ? schema.extend(overlay) : schema;
|
|
165
|
+
};
|
|
166
|
+
var describeBasicFields = function describeBasicFields(schema) {
|
|
167
|
+
var withNotes = describeFields(schema, BASIC_FIELD_NOTES);
|
|
168
|
+
var overlay = {};
|
|
157
169
|
for (var _i2 = 0, _Object$entries2 = Object.entries(BASIC_TIMESTAMP_NOTES); _i2 < _Object$entries2.length; _i2++) {
|
|
158
170
|
var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
var
|
|
162
|
-
if (
|
|
163
|
-
overlay[
|
|
164
|
-
description:
|
|
171
|
+
field = _Object$entries2$_i[0],
|
|
172
|
+
note = _Object$entries2$_i[1];
|
|
173
|
+
var existing = withNotes.shape[field];
|
|
174
|
+
if (existing) {
|
|
175
|
+
overlay[field] = existing.meta({
|
|
176
|
+
description: note,
|
|
165
177
|
format: "date-time",
|
|
166
178
|
type: "string"
|
|
167
179
|
});
|
|
168
180
|
}
|
|
169
181
|
}
|
|
170
|
-
return
|
|
182
|
+
return Object.keys(overlay).length ? withNotes.extend(overlay) : withNotes;
|
|
171
183
|
};
|
|
172
184
|
|
|
173
185
|
// =============================================================================
|
|
@@ -181,17 +193,21 @@ export var createTableSchema = function createTableSchema(_ref) {
|
|
|
181
193
|
var name = _ref.name,
|
|
182
194
|
columns = _ref.columns,
|
|
183
195
|
serverColumns = _ref.serverColumns,
|
|
184
|
-
extraConfig = _ref.extraConfig
|
|
196
|
+
extraConfig = _ref.extraConfig,
|
|
197
|
+
describe = _ref.describe;
|
|
185
198
|
var mergedColumns = _objectSpread(_objectSpread(_objectSpread({}, basicFields), serverColumns), columns);
|
|
186
199
|
var table = sqliteTable(name, mergedColumns, extraConfig);
|
|
187
|
-
|
|
200
|
+
|
|
201
|
+
// 同一份说明喂给三份 schema:含哪些列各不相同,describeFields 会跳过不存在的。
|
|
202
|
+
var notes = describe !== null && describe !== void 0 ? describe : {};
|
|
203
|
+
var selectSchema = describeFields(describeBasicFields(createSelectSchema(table)), notes);
|
|
188
204
|
// 只从 columns 推 —— basicFields 与 serverColumns 都由服务端写,不该出现在请求体里。
|
|
189
|
-
var insertSchema = createInsertSchema(sqliteTable(name, columns));
|
|
190
|
-
var updateSchema = createUpdateSchema(sqliteTable(name, _objectSpread({
|
|
205
|
+
var insertSchema = describeFields(createInsertSchema(sqliteTable(name, columns)), notes);
|
|
206
|
+
var updateSchema = describeFields(createUpdateSchema(sqliteTable(name, _objectSpread({
|
|
191
207
|
id: text("id")
|
|
192
208
|
}, columns))).extend({
|
|
193
209
|
id: z.string().describe("Id of the row to update.")
|
|
194
|
-
});
|
|
210
|
+
}), notes);
|
|
195
211
|
var querySchema = z.object({
|
|
196
212
|
id: z.string().describe("Id of the row to fetch.")
|
|
197
213
|
});
|
|
@@ -113,13 +113,33 @@ export declare const listBodySchema: <T extends z.ZodType<unknown, unknown, z.co
|
|
|
113
113
|
total: z.ZodNumber;
|
|
114
114
|
data: z.ZodArray<T>;
|
|
115
115
|
}, z.core.$strip>;
|
|
116
|
+
/**
|
|
117
|
+
* 给 schema 上已有的字段挂说明。字段不在这个 schema 里就跳过 —— 同一张表的
|
|
118
|
+
* insert / update / select 三份含的列不一样(basicFields 只在 select 里),一份说明表要能同时
|
|
119
|
+
* 喂给三者,就不能对「字段一定存在」有要求。**不给不存在的字段凭空造一个。**
|
|
120
|
+
*/
|
|
121
|
+
export declare const describeFields: <T extends z.ZodObject<z.core.$ZodLooseShape, z.core.$strip>>(schema: T, notes: Record<string, string>) => T;
|
|
116
122
|
/**
|
|
117
123
|
* 基于 drizzle + drizzle-zod 快速生成带基础字段(id / 创建时间等)的
|
|
118
124
|
* 表定义以及 select / insert / update / query / list zod schema。
|
|
119
125
|
*/
|
|
120
|
-
export declare const createTableSchema: <TTableName extends string, TColumnsMap extends Record<string, PgColumnBuilderBase<import("drizzle-orm").ColumnBuilderBaseConfig<import("drizzle-orm").ColumnDataType, string>, object>>, TServerColumns extends Record<string, PgColumnBuilderBase<import("drizzle-orm").ColumnBuilderBaseConfig<import("drizzle-orm").ColumnDataType, string>, object>> = {}>({ name, columns, serverColumns, extraConfig, }: {
|
|
126
|
+
export declare const createTableSchema: <TTableName extends string, TColumnsMap extends Record<string, PgColumnBuilderBase<import("drizzle-orm").ColumnBuilderBaseConfig<import("drizzle-orm").ColumnDataType, string>, object>>, TServerColumns extends Record<string, PgColumnBuilderBase<import("drizzle-orm").ColumnBuilderBaseConfig<import("drizzle-orm").ColumnDataType, string>, object>> = {}>({ name, columns, serverColumns, extraConfig, describe, }: {
|
|
121
127
|
/** 客户端能写的业务列。insert / update schema 只从这里推。 */
|
|
122
128
|
columns: TColumnsMap;
|
|
129
|
+
/**
|
|
130
|
+
* 每一列的说明,键是列名。**同时挂到 insert / update / select 三份 schema 上** —— 同一列在
|
|
131
|
+
* 请求体里和响应里是同一个东西,说明没有理由写两遍。
|
|
132
|
+
*
|
|
133
|
+
* 为什么需要这个参数:drizzle 列没有「描述」这个概念,而 `.describe()` 只能挂在 zod 上。不给
|
|
134
|
+
* 这条路,业务侧就只能在每张表后面自己把三份 schema 各 `.extend()` 一遍 —— 那是三份副本,
|
|
135
|
+
* 而副本会漂。
|
|
136
|
+
*
|
|
137
|
+
* 键有类型约束(列名的联合),所以列改名了、拼错了都是编译错误,不是静默失效。
|
|
138
|
+
*
|
|
139
|
+
* 说明会出现在 OpenAPI spec 里,再流进按 spec 生成的 client 与文档 —— 所以它是写给调用方
|
|
140
|
+
* 看的:这一列是什么、合法值从哪来、不传会怎样。
|
|
141
|
+
*/
|
|
142
|
+
describe?: Partial<Record<Extract<keyof TColumnsMap, string> | Extract<keyof TServerColumns, string>, string>> | undefined;
|
|
123
143
|
name: TTableName;
|
|
124
144
|
/**
|
|
125
145
|
* 由服务端盖、**绝不接受客户端传**的业务列:承载归属的 `ownerId`(配合
|
|
@@ -23,6 +23,7 @@ __export(schemas_exports, {
|
|
|
23
23
|
BASIC_UPDATE_OMIT: () => BASIC_UPDATE_OMIT,
|
|
24
24
|
basicFields: () => basicFields,
|
|
25
25
|
createTableSchema: () => createTableSchema,
|
|
26
|
+
describeFields: () => describeFields,
|
|
26
27
|
listBodySchema: () => listBodySchema,
|
|
27
28
|
queryListSchema: () => queryListSchema
|
|
28
29
|
});
|
|
@@ -75,8 +76,10 @@ var queryListSchema = (schema) => import_zod.z.object({
|
|
|
75
76
|
orderDir: import_zod.z.enum(["asc", "desc"]).optional().describe("Sort ascending or descending.")
|
|
76
77
|
}).merge(schema);
|
|
77
78
|
var listBodySchema = (schema) => import_zod.z.object({
|
|
78
|
-
total: import_zod.z.number()
|
|
79
|
-
|
|
79
|
+
total: import_zod.z.number().describe(
|
|
80
|
+
"Total number of rows matching the filters — not the length of `data`. Use it to decide whether another page exists."
|
|
81
|
+
),
|
|
82
|
+
data: import_zod.z.array(schema).describe("This page's rows.")
|
|
80
83
|
});
|
|
81
84
|
var BASIC_FIELD_NOTES = {
|
|
82
85
|
creatorId: "User id of the creator. Stamped by the server; clients cannot send it.",
|
|
@@ -88,16 +91,21 @@ var BASIC_TIMESTAMP_NOTES = {
|
|
|
88
91
|
createdAt: "When this row was created.",
|
|
89
92
|
updatedAt: "When this row was last modified."
|
|
90
93
|
};
|
|
91
|
-
var
|
|
94
|
+
var describeFields = (schema, notes) => {
|
|
92
95
|
const overlay = {};
|
|
93
|
-
for (const [field, note] of Object.entries(
|
|
96
|
+
for (const [field, note] of Object.entries(notes)) {
|
|
94
97
|
const existing = schema.shape[field];
|
|
95
98
|
if (existing) {
|
|
96
99
|
overlay[field] = existing.describe(note);
|
|
97
100
|
}
|
|
98
101
|
}
|
|
102
|
+
return Object.keys(overlay).length ? schema.extend(overlay) : schema;
|
|
103
|
+
};
|
|
104
|
+
var describeBasicFields = (schema) => {
|
|
105
|
+
const withNotes = describeFields(schema, BASIC_FIELD_NOTES);
|
|
106
|
+
const overlay = {};
|
|
99
107
|
for (const [field, note] of Object.entries(BASIC_TIMESTAMP_NOTES)) {
|
|
100
|
-
const existing =
|
|
108
|
+
const existing = withNotes.shape[field];
|
|
101
109
|
if (existing) {
|
|
102
110
|
overlay[field] = existing.meta({
|
|
103
111
|
description: note,
|
|
@@ -106,13 +114,14 @@ var describeBasicFields = (schema) => {
|
|
|
106
114
|
});
|
|
107
115
|
}
|
|
108
116
|
}
|
|
109
|
-
return
|
|
117
|
+
return Object.keys(overlay).length ? withNotes.extend(overlay) : withNotes;
|
|
110
118
|
};
|
|
111
119
|
var createTableSchema = ({
|
|
112
120
|
name,
|
|
113
121
|
columns,
|
|
114
122
|
serverColumns,
|
|
115
|
-
extraConfig
|
|
123
|
+
extraConfig,
|
|
124
|
+
describe
|
|
116
125
|
}) => {
|
|
117
126
|
const mergedColumns = {
|
|
118
127
|
...basicFields,
|
|
@@ -120,11 +129,21 @@ var createTableSchema = ({
|
|
|
120
129
|
...columns
|
|
121
130
|
};
|
|
122
131
|
const table = (0, import_pg_core.pgTable)(name, mergedColumns, extraConfig);
|
|
123
|
-
const
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
)
|
|
132
|
+
const notes = describe ?? {};
|
|
133
|
+
const selectSchema = describeFields(
|
|
134
|
+
describeBasicFields((0, import_drizzle_zod.createSelectSchema)(table)),
|
|
135
|
+
notes
|
|
136
|
+
);
|
|
137
|
+
const insertSchema = describeFields(
|
|
138
|
+
(0, import_drizzle_zod.createInsertSchema)((0, import_pg_core.pgTable)(name, columns)),
|
|
139
|
+
notes
|
|
140
|
+
);
|
|
141
|
+
const updateSchema = describeFields(
|
|
142
|
+
(0, import_drizzle_zod.createUpdateSchema)((0, import_pg_core.pgTable)(name, { id: (0, import_pg_core.uuid)("id"), ...columns })).extend({
|
|
143
|
+
id: import_zod.z.string().describe("Id of the row to update.")
|
|
144
|
+
}),
|
|
145
|
+
notes
|
|
146
|
+
);
|
|
128
147
|
const querySchema = import_zod.z.object({
|
|
129
148
|
id: import_zod.z.string().describe("Id of the row to fetch.")
|
|
130
149
|
});
|
|
@@ -147,6 +166,7 @@ var createTableSchema = ({
|
|
|
147
166
|
BASIC_UPDATE_OMIT,
|
|
148
167
|
basicFields,
|
|
149
168
|
createTableSchema,
|
|
169
|
+
describeFields,
|
|
150
170
|
listBodySchema,
|
|
151
171
|
queryListSchema
|
|
152
172
|
});
|
|
@@ -113,6 +113,12 @@ export declare const listBodySchema: <T extends z.ZodType<unknown, unknown, z.co
|
|
|
113
113
|
total: z.ZodNumber;
|
|
114
114
|
data: z.ZodArray<T>;
|
|
115
115
|
}, z.core.$strip>;
|
|
116
|
+
/**
|
|
117
|
+
* 给 schema 上已有的字段挂说明。字段不在这个 schema 里就跳过 —— 同一张表的
|
|
118
|
+
* insert / update / select 三份含的列不一样(basicFields 只在 select 里),一份说明表要能同时
|
|
119
|
+
* 喂给三者,就不能对「字段一定存在」有要求。**不给不存在的字段凭空造一个。**
|
|
120
|
+
*/
|
|
121
|
+
export declare const describeFields: <T extends z.ZodObject<z.core.$ZodLooseShape, z.core.$strip>>(schema: T, notes: Record<string, string>) => T;
|
|
116
122
|
/**
|
|
117
123
|
* 基于 drizzle + drizzle-zod 快速生成带基础字段(id / 创建时间等)的
|
|
118
124
|
* 表定义以及 select / insert / update / query / list zod schema。
|
|
@@ -121,6 +127,11 @@ export declare const createTableSchema: <TTableName extends string, TColumnsMap
|
|
|
121
127
|
name: TTableName;
|
|
122
128
|
/** 客户端能写的业务列。insert / update schema 只从这里推。 */
|
|
123
129
|
columns: TColumnsMap;
|
|
130
|
+
/**
|
|
131
|
+
* 每一列的说明,键是列名。同时挂到 insert / update / select 三份 schema 上。语义与 pg 版
|
|
132
|
+
* 一致,见那边的说明。
|
|
133
|
+
*/
|
|
134
|
+
describe?: Partial<Record<string, string>>;
|
|
124
135
|
/** 由服务端盖、绝不接受客户端传的业务列(归属、租户 id 这类)。语义与 pg 版一致,见那边的说明。 */
|
|
125
136
|
serverColumns?: Record<string, SQLiteColumnBuilderBase>;
|
|
126
137
|
extraConfig?: (_self: BuildExtraConfigColumns<TTableName, typeof basicFields & TColumnsMap, "sqlite">) => SQLiteTableExtraConfigValue[];
|
|
@@ -23,6 +23,7 @@ __export(schemas_exports, {
|
|
|
23
23
|
BASIC_UPDATE_OMIT: () => BASIC_UPDATE_OMIT,
|
|
24
24
|
basicFields: () => basicFields,
|
|
25
25
|
createTableSchema: () => createTableSchema,
|
|
26
|
+
describeFields: () => describeFields,
|
|
26
27
|
listBodySchema: () => listBodySchema,
|
|
27
28
|
queryListSchema: () => queryListSchema
|
|
28
29
|
});
|
|
@@ -77,8 +78,10 @@ var queryListSchema = (schema) => import_zod.z.object({
|
|
|
77
78
|
orderDir: import_zod.z.enum(["asc", "desc"]).optional().describe("Sort ascending or descending.")
|
|
78
79
|
}).merge(schema);
|
|
79
80
|
var listBodySchema = (schema) => import_zod.z.object({
|
|
80
|
-
total: import_zod.z.number()
|
|
81
|
-
|
|
81
|
+
total: import_zod.z.number().describe(
|
|
82
|
+
"Total number of rows matching the filters — not the length of `data`. Use it to decide whether another page exists."
|
|
83
|
+
),
|
|
84
|
+
data: import_zod.z.array(schema).describe("This page's rows.")
|
|
82
85
|
});
|
|
83
86
|
var BASIC_FIELD_NOTES = {
|
|
84
87
|
creatorId: "User id of the creator. Stamped by the server; clients cannot send it.",
|
|
@@ -90,16 +93,21 @@ var BASIC_TIMESTAMP_NOTES = {
|
|
|
90
93
|
createdAt: "When this row was created.",
|
|
91
94
|
updatedAt: "When this row was last modified."
|
|
92
95
|
};
|
|
93
|
-
var
|
|
96
|
+
var describeFields = (schema, notes) => {
|
|
94
97
|
const overlay = {};
|
|
95
|
-
for (const [field, note] of Object.entries(
|
|
98
|
+
for (const [field, note] of Object.entries(notes)) {
|
|
96
99
|
const existing = schema.shape[field];
|
|
97
100
|
if (existing) {
|
|
98
101
|
overlay[field] = existing.describe(note);
|
|
99
102
|
}
|
|
100
103
|
}
|
|
104
|
+
return Object.keys(overlay).length ? schema.extend(overlay) : schema;
|
|
105
|
+
};
|
|
106
|
+
var describeBasicFields = (schema) => {
|
|
107
|
+
const withNotes = describeFields(schema, BASIC_FIELD_NOTES);
|
|
108
|
+
const overlay = {};
|
|
101
109
|
for (const [field, note] of Object.entries(BASIC_TIMESTAMP_NOTES)) {
|
|
102
|
-
const existing =
|
|
110
|
+
const existing = withNotes.shape[field];
|
|
103
111
|
if (existing) {
|
|
104
112
|
overlay[field] = existing.meta({
|
|
105
113
|
description: note,
|
|
@@ -108,9 +116,9 @@ var describeBasicFields = (schema) => {
|
|
|
108
116
|
});
|
|
109
117
|
}
|
|
110
118
|
}
|
|
111
|
-
return
|
|
119
|
+
return Object.keys(overlay).length ? withNotes.extend(overlay) : withNotes;
|
|
112
120
|
};
|
|
113
|
-
var createTableSchema = ({ name, columns, serverColumns, extraConfig }) => {
|
|
121
|
+
var createTableSchema = ({ name, columns, serverColumns, extraConfig, describe }) => {
|
|
114
122
|
const mergedColumns = {
|
|
115
123
|
...basicFields,
|
|
116
124
|
...serverColumns,
|
|
@@ -121,11 +129,23 @@ var createTableSchema = ({ name, columns, serverColumns, extraConfig }) => {
|
|
|
121
129
|
mergedColumns,
|
|
122
130
|
extraConfig
|
|
123
131
|
);
|
|
124
|
-
const
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
)
|
|
132
|
+
const notes = describe ?? {};
|
|
133
|
+
const selectSchema = describeFields(
|
|
134
|
+
describeBasicFields((0, import_drizzle_zod.createSelectSchema)(table)),
|
|
135
|
+
notes
|
|
136
|
+
);
|
|
137
|
+
const insertSchema = describeFields(
|
|
138
|
+
(0, import_drizzle_zod.createInsertSchema)((0, import_sqlite_core.sqliteTable)(name, columns)),
|
|
139
|
+
notes
|
|
140
|
+
);
|
|
141
|
+
const updateSchema = describeFields(
|
|
142
|
+
(0, import_drizzle_zod.createUpdateSchema)(
|
|
143
|
+
(0, import_sqlite_core.sqliteTable)(name, { id: (0, import_sqlite_core.text)("id"), ...columns })
|
|
144
|
+
).extend({
|
|
145
|
+
id: import_zod.z.string().describe("Id of the row to update.")
|
|
146
|
+
}),
|
|
147
|
+
notes
|
|
148
|
+
);
|
|
129
149
|
const querySchema = import_zod.z.object({
|
|
130
150
|
id: import_zod.z.string().describe("Id of the row to fetch.")
|
|
131
151
|
});
|
|
@@ -148,6 +168,7 @@ var createTableSchema = ({ name, columns, serverColumns, extraConfig }) => {
|
|
|
148
168
|
BASIC_UPDATE_OMIT,
|
|
149
169
|
basicFields,
|
|
150
170
|
createTableSchema,
|
|
171
|
+
describeFields,
|
|
151
172
|
listBodySchema,
|
|
152
173
|
queryListSchema
|
|
153
174
|
});
|