nicot 1.4.2 → 1.4.4

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
@@ -207,8 +207,9 @@ OpenAPI 层面统统“伪装成”一个普通的 base64 `string` 字段:
207
207
 
208
208
  - 实体属性类型是 `string`(base64 字符串)。
209
209
  - OpenAPI 中以 `{ type: String, format: 'byte' }` 展示。
210
- - 通过 TypeORM `ValueTransformer`:写库时把 base64 字符串解码成 `Buffer`
211
- (默认列类型 `bytea`),读取时再编码回 base64 字符串。
210
+ - 通过 TypeORM `ValueTransformer`:写库时把 base64 字符串解码成
211
+ PostgreSQL 安全的 bytea 参数(默认列类型 `bytea`),读取时再编码回
212
+ base64 字符串。
212
213
 
213
214
  ```ts
214
215
  @Entity()
@@ -229,7 +230,7 @@ export class Attachment extends IdBase() {
229
230
  **查询。** base64 二进制列本身就是可查询字段(不需要 `GetMutator`)。想在
230
231
  `findAll` 中按它过滤,给它挂上 `@QueryBase64Equal()`(或
231
232
  `@QueryBase64NotEqual()`)即可:传入的 base64 查询串会在绑定参数前被解码成
232
- `Buffer`,从而与列里存的二进制匹配。
233
+ PostgreSQL 安全的 bytea 参数,从而与列里存的二进制匹配。
233
234
 
234
235
  ```ts
235
236
  @Base64BinaryColumn()
package/README.md CHANGED
@@ -309,8 +309,9 @@ entity / DTO / OpenAPI surface all behave like a plain **base64 `string`**:
309
309
 
310
310
  - The TS property type is `string` (a base64 string).
311
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.
312
+ - A TypeORM `ValueTransformer` decodes the base64 string into a PostgreSQL-safe
313
+ bytea parameter on the way into the DB (`bytea` by default) and encodes it
314
+ back to base64 on read.
314
315
 
315
316
  ```ts
316
317
  @Entity()
@@ -333,8 +334,8 @@ API.
333
334
  **Querying.** A base64 binary column is a normal queryable field (no
334
335
  `GetMutator` required). To filter on it in `findAll`, attach
335
336
  `@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:
337
+ string is decoded to a PostgreSQL-safe bytea parameter right before it is bound,
338
+ so it matches the binary stored in the column:
338
339
 
339
340
  ```ts
340
341
  @Base64BinaryColumn()
package/dist/index.cjs CHANGED
@@ -665,7 +665,10 @@ __export(index_exports, {
665
665
  applyQueryPropertyLike: () => applyQueryPropertyLike,
666
666
  applyQueryPropertySearch: () => applyQueryPropertySearch,
667
667
  applyQueryPropertyZeroNullable: () => applyQueryPropertyZeroNullable,
668
+ base64OrBinaryToBuffer: () => base64OrBinaryToBuffer,
669
+ base64OrBinaryToDatabaseValue: () => base64OrBinaryToDatabaseValue,
668
670
  binaryToBuffer: () => binaryToBuffer,
671
+ binaryToPostgresByteaHex: () => binaryToPostgresByteaHex,
669
672
  createGetMutator: () => createGetMutator,
670
673
  createQueryArrayify: () => createQueryArrayify,
671
674
  createQueryBase64Operator: () => createQueryBase64Operator,
@@ -935,15 +938,31 @@ function binaryToBuffer(value) {
935
938
  }
936
939
  return Buffer.from(new Uint8Array(value));
937
940
  }
941
+ function binaryToPostgresByteaHex(value) {
942
+ return `\\x${binaryToBuffer(value).toString("hex")}`;
943
+ }
944
+ function base64OrBinaryToBuffer(value) {
945
+ if (isBinaryLike(value)) {
946
+ return binaryToBuffer(value);
947
+ }
948
+ return Buffer.from(String(value), "base64");
949
+ }
950
+ function base64OrBinaryToDatabaseValue(value, storage = "postgres-bytea") {
951
+ const buffer = base64OrBinaryToBuffer(value);
952
+ if (storage === "postgres-bytea") {
953
+ return binaryToPostgresByteaHex(buffer);
954
+ }
955
+ return buffer;
956
+ }
938
957
  var Base64BinaryTransformer = class {
958
+ constructor(storage = "postgres-bytea") {
959
+ this.storage = storage;
960
+ }
939
961
  to(entValue) {
940
962
  if (entValue == null) {
941
963
  return entValue;
942
964
  }
943
- if (isBinaryLike(entValue)) {
944
- return binaryToBuffer(entValue);
945
- }
946
- return Buffer.from(String(entValue), "base64");
965
+ return base64OrBinaryToDatabaseValue(entValue, this.storage);
947
966
  }
948
967
  from(dbValue) {
949
968
  if (dbValue == null) {
@@ -952,7 +971,11 @@ var Base64BinaryTransformer = class {
952
971
  if (isBinaryLike(dbValue)) {
953
972
  return binaryToBuffer(dbValue).toString("base64");
954
973
  }
955
- return Buffer.from(String(dbValue)).toString("base64");
974
+ const text = String(dbValue);
975
+ if (/^\\x[0-9a-f]*$/i.test(text)) {
976
+ return Buffer.from(text.slice(2), "hex").toString("base64");
977
+ }
978
+ return Buffer.from(text).toString("base64");
956
979
  }
957
980
  };
958
981
 
@@ -1158,12 +1181,30 @@ var BoolColumn = (options = {}) => (0, import_nesties4.MergePropertyDecorators)(
1158
1181
  swaggerDecorator(options, { type: Boolean }),
1159
1182
  GetMutatorBool()
1160
1183
  ]);
1184
+ var jsonColumnValidators = (definition) => {
1185
+ const isArray = Array.isArray(definition);
1186
+ const cl = (0, import_nesties5.getClassFromClassOrArray)(definition);
1187
+ const validationOptions = isArray ? { each: true } : {};
1188
+ const decorators = isArray ? [(0, import_class_validator3.IsArray)()] : [];
1189
+ if (cl === String) {
1190
+ decorators.push((0, import_class_validator3.IsString)(validationOptions));
1191
+ } else if (cl === Number) {
1192
+ decorators.push((0, import_class_validator3.IsNumber)({}, validationOptions));
1193
+ } else if (cl === Boolean) {
1194
+ decorators.push((0, import_class_validator3.IsBoolean)(validationOptions));
1195
+ } else if (cl === Date) {
1196
+ decorators.push((0, import_class_validator3.IsDate)(validationOptions));
1197
+ } else {
1198
+ decorators.push((0, import_class_validator3.ValidateNested)(validationOptions));
1199
+ }
1200
+ return decorators;
1201
+ };
1161
1202
  var createJsonColumnDef = (columnType = "jsonb", typeTransformerClass = TypeTransformer) => (definition, options = {}) => {
1162
1203
  const cl = (0, import_nesties5.getClassFromClassOrArray)(definition);
1163
1204
  return (0, import_nesties4.MergePropertyDecorators)([
1164
1205
  RequireGetMutator(),
1165
1206
  (0, import_class_transformer2.Type)(() => cl),
1166
- (0, import_class_validator3.ValidateNested)(),
1207
+ ...jsonColumnValidators(definition),
1167
1208
  (0, import_typeorm.Column)(options.columnType || columnType, {
1168
1209
  ...columnDecoratorOptions(options),
1169
1210
  transformer: new typeTransformerClass(definition)
@@ -1195,7 +1236,9 @@ var Base64BinaryColumn = (options = {}) => (0, import_nesties4.MergePropertyDeco
1195
1236
  (0, import_typeorm.Column)(options.columnType || "bytea", {
1196
1237
  ...columnDecoratorOptions(options),
1197
1238
  default: void 0,
1198
- transformer: new Base64BinaryTransformer()
1239
+ transformer: new Base64BinaryTransformer(
1240
+ options.binaryStorage ?? (options.columnType && options.columnType !== "bytea" ? "binary" : "postgres-bytea")
1241
+ )
1199
1242
  }),
1200
1243
  IsBase64OrBinary(),
1201
1244
  validatorDecorator(options),
@@ -1424,19 +1467,20 @@ var createQueryOperatorArrayify = (operator, singleFallback) => createQueryArray
1424
1467
  );
1425
1468
  var QueryIn = createQueryOperatorArrayify("IN", "=");
1426
1469
  var QueryNotIn = createQueryOperatorArrayify("NOT IN", "!=");
1427
- var toBase64QueryBuffer = (value) => {
1470
+ var normalizeQueryBase64Options = (fieldOrOptions) => typeof fieldOrOptions === "string" ? { field: fieldOrOptions } : fieldOrOptions ?? {};
1471
+ var toBase64QueryValue = (value, storage = "postgres-bytea") => {
1428
1472
  if (value == null) {
1429
1473
  return value;
1430
1474
  }
1431
- if (isBinaryLike(value)) {
1432
- return binaryToBuffer(value);
1433
- }
1434
- return Buffer.from(String(value), "base64");
1475
+ return base64OrBinaryToDatabaseValue(value, storage);
1476
+ };
1477
+ var createQueryBase64Operator = (operator) => (fieldOrOptions) => {
1478
+ const options = normalizeQueryBase64Options(fieldOrOptions);
1479
+ return QueryWrap((entityExpr, varExpr, info) => {
1480
+ info.mutateValue(toBase64QueryValue(info.value, options.binaryStorage));
1481
+ return `${entityExpr} ${operator} ${varExpr}`;
1482
+ }, options.field);
1435
1483
  };
1436
- var createQueryBase64Operator = (operator) => (field) => QueryWrap((entityExpr, varExpr, info) => {
1437
- info.mutateValue(toBase64QueryBuffer(info.value));
1438
- return `${entityExpr} ${operator} ${varExpr}`;
1439
- }, field);
1440
1484
  var QueryBase64Equal = createQueryBase64Operator("=");
1441
1485
  var QueryBase64NotEqual = createQueryBase64Operator("!=");
1442
1486
  var QueryFullText = (options = {}) => {
@@ -4366,7 +4410,10 @@ TransactionalTypeOrmModule = __decorateClass([
4366
4410
  applyQueryPropertyLike,
4367
4411
  applyQueryPropertySearch,
4368
4412
  applyQueryPropertyZeroNullable,
4413
+ base64OrBinaryToBuffer,
4414
+ base64OrBinaryToDatabaseValue,
4369
4415
  binaryToBuffer,
4416
+ binaryToPostgresByteaHex,
4370
4417
  createGetMutator,
4371
4418
  createQueryArrayify,
4372
4419
  createQueryBase64Operator,