nicot 1.4.0 → 1.4.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/README-CN.md CHANGED
@@ -192,6 +192,7 @@ content: string;
192
192
  | QueryGreater/Less | 数值比较 |
193
193
  | QueryIn / QueryNotIn| IN / NOT IN |
194
194
  | QueryMatchBoolean | 自动解析 true/false |
195
+ | QueryBase64Equal / QueryBase64NotEqual | base64 字符串解码为二进制后比较(配合 `@Base64BinaryColumn()`) |
195
196
  | QueryOperator | 自定义操作符 |
196
197
  | QueryWrap | 自定义表达式 |
197
198
  | QueryAnd / QueryOr | 条件组合 |
@@ -199,6 +200,45 @@ content: string;
199
200
 
200
201
  ---
201
202
 
203
+ ## Base64 二进制列:`@Base64BinaryColumn()`
204
+
205
+ `@Base64BinaryColumn()` 让你在**数据库里存原始二进制**,而在 实体 / DTO /
206
+ OpenAPI 层面统统“伪装成”一个普通的 base64 `string` 字段:
207
+
208
+ - 实体属性类型是 `string`(base64 字符串)。
209
+ - OpenAPI 中以 `{ type: String, format: 'byte' }` 展示。
210
+ - 通过 TypeORM `ValueTransformer`:写库时把 base64 字符串解码成 `Buffer`
211
+ (默认列类型 `bytea`),读取时再编码回 base64 字符串。
212
+
213
+ ```ts
214
+ @Entity()
215
+ export class Attachment extends IdBase() {
216
+ @Base64BinaryColumn({ required: true })
217
+ data: string; // 接口里是 base64,PostgreSQL 里是 bytea
218
+
219
+ // MySQL 可指定 blob 系列类型:
220
+ @Base64BinaryColumn({ columnType: 'longblob' })
221
+ thumbnail: string;
222
+ }
223
+ ```
224
+
225
+ **直接赋二进制也合法。** 虽然类型是 base64 `string`,但如果在你自己的代码里
226
+ (例如 `repo.save`)直接赋了 `Buffer` / `Uint8Array` / `ArrayBuffer`,会被认为
227
+ “这就是那段二进制”原样入库,校验同样通过;读出来时依然是 base64 字符串。
228
+
229
+ **查询。** base64 二进制列本身就是可查询字段(不需要 `GetMutator`)。想在
230
+ `findAll` 中按它过滤,给它挂上 `@QueryBase64Equal()`(或
231
+ `@QueryBase64NotEqual()`)即可:传入的 base64 查询串会在绑定参数前被解码成
232
+ `Buffer`,从而与列里存的二进制匹配。
233
+
234
+ ```ts
235
+ @Base64BinaryColumn()
236
+ @QueryBase64Equal()
237
+ signature: string; // GET /attachment?signature=3q2+7w==
238
+ ```
239
+
240
+ ---
241
+
202
242
  ## GET Mutator(URL → 类型转换)
203
243
 
204
244
  URL 参数永远是 string。
package/README.md CHANGED
@@ -289,6 +289,7 @@ Common ones:
289
289
  | `@SimpleJsonColumn` | `json` | same as above |
290
290
  | `@StringJsonColumn` | `text` (stringified JSON) | same as above |
291
291
  | `@EnumColumn(Enum)` | enum or text | enum validation |
292
+ | `@Base64BinaryColumn()` | `bytea` (binary)| base64 string / binary |
292
293
 
293
294
  All of them accept an `options` parameter:
294
295
 
@@ -301,6 +302,46 @@ All of them accept an `options` parameter:
301
302
  displayName: string;
302
303
  ```
303
304
 
305
+ ### `@Base64BinaryColumn()` — base64 over the wire, binary in the database
306
+
307
+ `@Base64BinaryColumn()` lets you store **raw binary** in the database while the
308
+ entity / DTO / OpenAPI surface all behave like a plain **base64 `string`**:
309
+
310
+ - The TS property type is `string` (a base64 string).
311
+ - It is exposed to OpenAPI as `{ type: String, format: 'byte' }`.
312
+ - A TypeORM `ValueTransformer` decodes the base64 string into a `Buffer` on the
313
+ way into the DB (`bytea` by default) and encodes it back to base64 on read.
314
+
315
+ ```ts
316
+ @Entity()
317
+ export class Attachment extends IdBase() {
318
+ @Base64BinaryColumn({ required: true })
319
+ data: string; // base64 in the API, bytea in PostgreSQL
320
+
321
+ // MySQL? pick a blob type:
322
+ @Base64BinaryColumn({ columnType: 'longblob' })
323
+ thumbnail: string;
324
+ }
325
+ ```
326
+
327
+ **Assigning raw binary directly.** Even though the type is a base64 `string`,
328
+ if you assign a `Buffer` / `Uint8Array` / `ArrayBuffer` (e.g. from `repo.save`
329
+ in your own code), it is treated as *the binary itself* and stored as-is —
330
+ validation accepts it too. It still comes back out as a base64 string over the
331
+ API.
332
+
333
+ **Querying.** A base64 binary column is a normal queryable field (no
334
+ `GetMutator` required). To filter on it in `findAll`, attach
335
+ `@QueryBase64Equal()` (or `@QueryBase64NotEqual()`); the incoming base64 query
336
+ string is decoded to a `Buffer` right before it is bound, so it matches the
337
+ binary stored in the column:
338
+
339
+ ```ts
340
+ @Base64BinaryColumn()
341
+ @QueryBase64Equal()
342
+ signature: string; // GET /attachment?signature=3q2+7w==
343
+ ```
344
+
304
345
  ---
305
346
 
306
347
  ## Access control decorators
package/dist/index.cjs CHANGED
@@ -572,6 +572,8 @@ var require_typeorm = __commonJS({
572
572
  // index.ts
573
573
  var index_exports = {};
574
574
  __export(index_exports, {
575
+ Base64BinaryColumn: () => Base64BinaryColumn,
576
+ Base64BinaryTransformer: () => Base64BinaryTransformer,
575
577
  BindingColumn: () => BindingColumn,
576
578
  BindingValue: () => BindingValue,
577
579
  BlankCursorPaginationReturnMessageDto: () => BlankCursorPaginationReturnMessageDto,
@@ -604,6 +606,7 @@ __export(index_exports, {
604
606
  Inner: () => Inner,
605
607
  IntColumn: () => IntColumn,
606
608
  InternalColumn: () => InternalColumn,
609
+ IsBase64OrBinary: () => IsBase64OrBinary,
607
610
  JsonColumn: () => JsonColumn,
608
611
  NotChangeable: () => NotChangeable,
609
612
  NotColumn: () => NotColumn,
@@ -617,6 +620,8 @@ __export(index_exports, {
617
620
  PageSettingsDto: () => PageSettingsDto,
618
621
  PickPipe: () => PickPipe,
619
622
  QueryAnd: () => QueryAnd,
623
+ QueryBase64Equal: () => QueryBase64Equal,
624
+ QueryBase64NotEqual: () => QueryBase64NotEqual,
620
625
  QueryColumn: () => QueryColumn,
621
626
  QueryCondition: () => QueryCondition,
622
627
  QueryEqual: () => QueryEqual,
@@ -660,8 +665,10 @@ __export(index_exports, {
660
665
  applyQueryPropertyLike: () => applyQueryPropertyLike,
661
666
  applyQueryPropertySearch: () => applyQueryPropertySearch,
662
667
  applyQueryPropertyZeroNullable: () => applyQueryPropertyZeroNullable,
668
+ binaryToBuffer: () => binaryToBuffer,
663
669
  createGetMutator: () => createGetMutator,
664
670
  createQueryArrayify: () => createQueryArrayify,
671
+ createQueryBase64Operator: () => createQueryBase64Operator,
665
672
  createQueryCondition: () => createQueryCondition,
666
673
  createQueryOperator: () => createQueryOperator,
667
674
  createQueryOperatorArrayify: () => createQueryOperatorArrayify,
@@ -669,7 +676,8 @@ __export(index_exports, {
669
676
  getTransactionalEntityManagerProvider: () => getTransactionalEntityManagerProvider,
670
677
  getTransactionalEntityManagerToken: () => getTransactionalEntityManagerToken,
671
678
  getTransactionalRepositoryProvider: () => getTransactionalRepositoryProvider,
672
- getTransactionalRepositoryToken: () => getTransactionalRepositoryToken
679
+ getTransactionalRepositoryToken: () => getTransactionalRepositoryToken,
680
+ isBinaryLike: () => isBinaryLike
673
681
  });
674
682
  module.exports = __toCommonJS(index_exports);
675
683
  var import_reflect_metadata = require("reflect-metadata");
@@ -914,6 +922,40 @@ var GetMutatorJson = createGetMutator((s) => JSON.parse(s), {
914
922
  example: `{"key1":"value1","key2":2,"key3":[1,2,3]}`
915
923
  });
916
924
 
925
+ // src/utility/base64-binary.ts
926
+ function isBinaryLike(value) {
927
+ return Buffer.isBuffer(value) || value instanceof Uint8Array || value instanceof ArrayBuffer;
928
+ }
929
+ function binaryToBuffer(value) {
930
+ if (Buffer.isBuffer(value)) {
931
+ return value;
932
+ }
933
+ if (value instanceof Uint8Array) {
934
+ return Buffer.from(value.buffer, value.byteOffset, value.byteLength);
935
+ }
936
+ return Buffer.from(new Uint8Array(value));
937
+ }
938
+ var Base64BinaryTransformer = class {
939
+ to(entValue) {
940
+ if (entValue == null) {
941
+ return entValue;
942
+ }
943
+ if (isBinaryLike(entValue)) {
944
+ return binaryToBuffer(entValue);
945
+ }
946
+ return Buffer.from(String(entValue), "base64");
947
+ }
948
+ from(dbValue) {
949
+ if (dbValue == null) {
950
+ return dbValue;
951
+ }
952
+ if (isBinaryLike(dbValue)) {
953
+ return binaryToBuffer(dbValue).toString("base64");
954
+ }
955
+ return Buffer.from(String(dbValue)).toString("base64");
956
+ }
957
+ };
958
+
917
959
  // src/decorators/property.ts
918
960
  var NotRequiredButHasDefaultDec = () => Metadata.set(
919
961
  "notRequiredButHasDefault",
@@ -1136,6 +1178,29 @@ var StringJsonColumn = createJsonColumnDef(
1136
1178
  "text",
1137
1179
  TypeTransformerString
1138
1180
  );
1181
+ var IsBase64OrBinary = (validationOptions) => (0, import_class_validator3.ValidateBy)(
1182
+ {
1183
+ name: "isBase64OrBinary",
1184
+ validator: {
1185
+ validate: (value) => isBinaryLike(value) || typeof value === "string" && (0, import_class_validator3.isBase64)(value),
1186
+ defaultMessage: (0, import_class_validator3.buildMessage)(
1187
+ (eachPrefix) => `${eachPrefix}$property must be a base64 string or binary data (Buffer / Uint8Array / ArrayBuffer)`,
1188
+ validationOptions
1189
+ )
1190
+ }
1191
+ },
1192
+ validationOptions
1193
+ );
1194
+ var Base64BinaryColumn = (options = {}) => (0, import_nesties4.MergePropertyDecorators)([
1195
+ (0, import_typeorm.Column)(options.columnType || "bytea", {
1196
+ ...columnDecoratorOptions(options),
1197
+ default: void 0,
1198
+ transformer: new Base64BinaryTransformer()
1199
+ }),
1200
+ IsBase64OrBinary(),
1201
+ validatorDecorator(options),
1202
+ swaggerDecorator(options, { type: String, format: "byte" })
1203
+ ]);
1139
1204
  var NotColumn = (options = {}, specials = {}) => (0, import_nesties4.MergePropertyDecorators)([
1140
1205
  (0, import_class_transformer2.Exclude)(),
1141
1206
  swaggerDecorator({
@@ -1359,6 +1424,21 @@ var createQueryOperatorArrayify = (operator, singleFallback) => createQueryArray
1359
1424
  );
1360
1425
  var QueryIn = createQueryOperatorArrayify("IN", "=");
1361
1426
  var QueryNotIn = createQueryOperatorArrayify("NOT IN", "!=");
1427
+ var toBase64QueryBuffer = (value) => {
1428
+ if (value == null) {
1429
+ return value;
1430
+ }
1431
+ if (isBinaryLike(value)) {
1432
+ return binaryToBuffer(value);
1433
+ }
1434
+ return Buffer.from(String(value), "base64");
1435
+ };
1436
+ var createQueryBase64Operator = (operator) => (field) => QueryWrap((entityExpr, varExpr, info) => {
1437
+ info.mutateValue(toBase64QueryBuffer(info.value));
1438
+ return `${entityExpr} ${operator} ${varExpr}`;
1439
+ }, field);
1440
+ var QueryBase64Equal = createQueryBase64Operator("=");
1441
+ var QueryBase64NotEqual = createQueryBase64Operator("!=");
1362
1442
  var QueryFullText = (options = {}) => {
1363
1443
  const configurationName = options.parser ? `nicot_parser_${options.parser}` : options.configuration || "english";
1364
1444
  const tsQueryFunction = options.tsQueryFunction || "websearch_to_tsquery";
@@ -4139,6 +4219,8 @@ TransactionalTypeOrmModule = __decorateClass([
4139
4219
  ], TransactionalTypeOrmModule);
4140
4220
  // Annotate the CommonJS export names for ESM import in node:
4141
4221
  0 && (module.exports = {
4222
+ Base64BinaryColumn,
4223
+ Base64BinaryTransformer,
4142
4224
  BindingColumn,
4143
4225
  BindingValue,
4144
4226
  BlankCursorPaginationReturnMessageDto,
@@ -4171,6 +4253,7 @@ TransactionalTypeOrmModule = __decorateClass([
4171
4253
  Inner,
4172
4254
  IntColumn,
4173
4255
  InternalColumn,
4256
+ IsBase64OrBinary,
4174
4257
  JsonColumn,
4175
4258
  NotChangeable,
4176
4259
  NotColumn,
@@ -4184,6 +4267,8 @@ TransactionalTypeOrmModule = __decorateClass([
4184
4267
  PageSettingsDto,
4185
4268
  PickPipe,
4186
4269
  QueryAnd,
4270
+ QueryBase64Equal,
4271
+ QueryBase64NotEqual,
4187
4272
  QueryColumn,
4188
4273
  QueryCondition,
4189
4274
  QueryEqual,
@@ -4227,8 +4312,10 @@ TransactionalTypeOrmModule = __decorateClass([
4227
4312
  applyQueryPropertyLike,
4228
4313
  applyQueryPropertySearch,
4229
4314
  applyQueryPropertyZeroNullable,
4315
+ binaryToBuffer,
4230
4316
  createGetMutator,
4231
4317
  createQueryArrayify,
4318
+ createQueryBase64Operator,
4232
4319
  createQueryCondition,
4233
4320
  createQueryOperator,
4234
4321
  createQueryOperatorArrayify,
@@ -4237,6 +4324,7 @@ TransactionalTypeOrmModule = __decorateClass([
4237
4324
  getTransactionalEntityManagerToken,
4238
4325
  getTransactionalRepositoryProvider,
4239
4326
  getTransactionalRepositoryToken,
4327
+ isBinaryLike,
4240
4328
  ...require("nesties")
4241
4329
  });
4242
4330
  //# sourceMappingURL=index.cjs.map