@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.
@@ -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
- var describeBasicFields = function describeBasicFields(schema) {
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(BASIC_FIELD_NOTES); _i < _Object$entries.length; _i++) {
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
- _field = _Object$entries2$_i[0],
154
- _note = _Object$entries2$_i[1];
155
- var _existing = schema.shape[_field];
156
- if (_existing) {
157
- overlay[_field] = _existing.meta({
158
- description: _note,
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 schema.extend(overlay);
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
- var selectSchema = describeBasicFields(createSelectSchema(table));
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
- var describeBasicFields = function describeBasicFields(schema) {
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(BASIC_FIELD_NOTES); _i < _Object$entries.length; _i++) {
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
- _field = _Object$entries2$_i[0],
160
- _note = _Object$entries2$_i[1];
161
- var _existing = schema.shape[_field];
162
- if (_existing) {
163
- overlay[_field] = _existing.meta({
164
- description: _note,
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 schema.extend(overlay);
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
- var selectSchema = describeBasicFields(createSelectSchema(table));
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
- data: import_zod.z.array(schema)
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 describeBasicFields = (schema) => {
94
+ var describeFields = (schema, notes) => {
92
95
  const overlay = {};
93
- for (const [field, note] of Object.entries(BASIC_FIELD_NOTES)) {
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 = schema.shape[field];
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 schema.extend(overlay);
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 selectSchema = describeBasicFields((0, import_drizzle_zod.createSelectSchema)(table));
124
- const insertSchema = (0, import_drizzle_zod.createInsertSchema)((0, import_pg_core.pgTable)(name, columns));
125
- const updateSchema = (0, import_drizzle_zod.createUpdateSchema)(
126
- (0, import_pg_core.pgTable)(name, { id: (0, import_pg_core.uuid)("id"), ...columns })
127
- ).extend({ id: import_zod.z.string().describe("Id of the row to update.") });
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
- data: import_zod.z.array(schema)
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 describeBasicFields = (schema) => {
96
+ var describeFields = (schema, notes) => {
94
97
  const overlay = {};
95
- for (const [field, note] of Object.entries(BASIC_FIELD_NOTES)) {
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 = schema.shape[field];
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 schema.extend(overlay);
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 selectSchema = describeBasicFields((0, import_drizzle_zod.createSelectSchema)(table));
125
- const insertSchema = (0, import_drizzle_zod.createInsertSchema)((0, import_sqlite_core.sqliteTable)(name, columns));
126
- const updateSchema = (0, import_drizzle_zod.createUpdateSchema)(
127
- (0, import_sqlite_core.sqliteTable)(name, { id: (0, import_sqlite_core.text)("id"), ...columns })
128
- ).extend({ id: import_zod.z.string().describe("Id of the row to update.") });
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
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai0x0/utils",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "AI0x0 utils",
5
5
  "keywords": [
6
6
  "ai0x0"