ts-prorm-orm 1.1.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.
Files changed (310) hide show
  1. package/CHANGELOG.md +1111 -0
  2. package/LICENSE +21 -0
  3. package/README.md +573 -0
  4. package/dist/audit/history-query.js +180 -0
  5. package/dist/audit/index.js +23 -0
  6. package/dist/audit/logger.js +236 -0
  7. package/dist/cache/cache-manager.js +84 -0
  8. package/dist/cache/index.js +16 -0
  9. package/dist/cache/redis-cluster-cache.js +557 -0
  10. package/dist/cli.js +2200 -0
  11. package/dist/compliance/audit-trail.js +68 -0
  12. package/dist/compliance/backup-verification.js +685 -0
  13. package/dist/compliance/breach-detector.js +505 -0
  14. package/dist/compliance/consent-record.js +227 -0
  15. package/dist/compliance/consent-versioning.js +331 -0
  16. package/dist/compliance/cross-border-log.js +530 -0
  17. package/dist/compliance/data-classifier.js +258 -0
  18. package/dist/compliance/data-lineage.js +565 -0
  19. package/dist/compliance/data-masker.js +303 -0
  20. package/dist/compliance/data-portability.js +265 -0
  21. package/dist/compliance/data-retention.js +195 -0
  22. package/dist/compliance/dsar-workflow.js +342 -0
  23. package/dist/compliance/field-encryption.js +223 -0
  24. package/dist/compliance/immutable-record.js +148 -0
  25. package/dist/compliance/index.js +260 -0
  26. package/dist/compliance/privacy-impact-assessment.js +364 -0
  27. package/dist/compliance/pseudonymization.js +269 -0
  28. package/dist/compliance/query-firewall.js +1182 -0
  29. package/dist/compliance/rate-limiter.js +580 -0
  30. package/dist/compliance/right-to-erasure.js +117 -0
  31. package/dist/compliance/row-level-security.js +246 -0
  32. package/dist/compliance/security-decorator.js +574 -0
  33. package/dist/compliance/security-monitor.js +525 -0
  34. package/dist/compliance/sensitive-data-discovery.js +476 -0
  35. package/dist/compliance/session-isolation.js +472 -0
  36. package/dist/compliance/tls-enforcer.js +108 -0
  37. package/dist/compliance/worm-storage.js +712 -0
  38. package/dist/connection-manager.js +198 -0
  39. package/dist/connection-pool.js +519 -0
  40. package/dist/decorators/audit.js +136 -0
  41. package/dist/decorators/belongs-to-many.js +115 -0
  42. package/dist/decorators/belongs-to.js +115 -0
  43. package/dist/decorators/check.js +435 -0
  44. package/dist/decorators/collate.js +329 -0
  45. package/dist/decorators/comment.js +205 -0
  46. package/dist/decorators/database-settings.js +236 -0
  47. package/dist/decorators/default.js +244 -0
  48. package/dist/decorators/encryption.js +235 -0
  49. package/dist/decorators/engine.js +97 -0
  50. package/dist/decorators/fk-constraints.js +594 -0
  51. package/dist/decorators/foreign-table.js +136 -0
  52. package/dist/decorators/generated.js +274 -0
  53. package/dist/decorators/has-many.js +127 -0
  54. package/dist/decorators/has-one.js +116 -0
  55. package/dist/decorators/hstore.js +129 -0
  56. package/dist/decorators/index.js +355 -0
  57. package/dist/decorators/json-column.js +83 -0
  58. package/dist/decorators/jsonb.js +101 -0
  59. package/dist/decorators/orm-decorators.js +425 -0
  60. package/dist/decorators/permissions.js +294 -0
  61. package/dist/decorators/procedure.js +210 -0
  62. package/dist/decorators/query-options.js +556 -0
  63. package/dist/decorators/range.js +167 -0
  64. package/dist/decorators/set-column.js +83 -0
  65. package/dist/decorators/spatial.js +114 -0
  66. package/dist/decorators/storage.js +580 -0
  67. package/dist/decorators/timezone.js +512 -0
  68. package/dist/decorators/trigger.js +90 -0
  69. package/dist/decorators/uuid.js +135 -0
  70. package/dist/decorators/view.js +258 -0
  71. package/dist/diagrams/chen-diagram.js +354 -0
  72. package/dist/diagrams/class-diagram.js +384 -0
  73. package/dist/diagrams/dependency-diagram.js +432 -0
  74. package/dist/diagrams/er-diagram.js +605 -0
  75. package/dist/diagrams/flow-diagram.js +394 -0
  76. package/dist/diagrams/gantt-diagram.js +411 -0
  77. package/dist/diagrams/index-diagram.js +353 -0
  78. package/dist/diagrams/index.js +184 -0
  79. package/dist/diagrams/migration-diagram.js +316 -0
  80. package/dist/diagrams/model-diagram.js +616 -0
  81. package/dist/diagrams/package-diagram.js +376 -0
  82. package/dist/diagrams/palette.js +85 -0
  83. package/dist/diagrams/relational-diagram.js +455 -0
  84. package/dist/diagrams/schemadoc-diagram.js +309 -0
  85. package/dist/diagrams/sequence-diagram.js +307 -0
  86. package/dist/diagrams/state-diagram.js +344 -0
  87. package/dist/diagrams/svg-dom.js +111 -0
  88. package/dist/diagrams/tree-diagram.js +250 -0
  89. package/dist/dialects/clickhouse/index.js +1742 -0
  90. package/dist/dialects/cockroachdb/index.js +4677 -0
  91. package/dist/dialects/cratedb/index.js +441 -0
  92. package/dist/dialects/databricks/index.js +517 -0
  93. package/dist/dialects/db2/index.js +2225 -0
  94. package/dist/dialects/dialect.js +720 -0
  95. package/dist/dialects/duckdb/index.js +2014 -0
  96. package/dist/dialects/exasol/index.js +357 -0
  97. package/dist/dialects/firebird/index.js +495 -0
  98. package/dist/dialects/greenplum/index.js +457 -0
  99. package/dist/dialects/hana/index.js +1741 -0
  100. package/dist/dialects/mariadb/index.js +3590 -0
  101. package/dist/dialects/mssql/index.js +2296 -0
  102. package/dist/dialects/mysql/index.js +4058 -0
  103. package/dist/dialects/oracle/index.js +2999 -0
  104. package/dist/dialects/postgres/index.js +5319 -0
  105. package/dist/dialects/query-stream-helper.js +152 -0
  106. package/dist/dialects/questdb/index.js +433 -0
  107. package/dist/dialects/redshift/index.js +2277 -0
  108. package/dist/dialects/singlestore/index.js +354 -0
  109. package/dist/dialects/snowflake/index.js +2082 -0
  110. package/dist/dialects/spanner/index.js +1768 -0
  111. package/dist/dialects/sqlite/index.js +3382 -0
  112. package/dist/dialects/tidb/index.js +377 -0
  113. package/dist/dialects/timescaledb/index.js +164 -0
  114. package/dist/dialects/trino/index.js +420 -0
  115. package/dist/dialects/turso/index.js +227 -0
  116. package/dist/dialects/vertica/index.js +317 -0
  117. package/dist/dialects/yugabytedb/index.js +424 -0
  118. package/dist/errors/index.js +472 -0
  119. package/dist/errors/utils.js +340 -0
  120. package/dist/errors.js +21 -0
  121. package/dist/extensions/catalog/cloud-warehouse-features.js +207 -0
  122. package/dist/extensions/catalog/mssql-features.js +147 -0
  123. package/dist/extensions/catalog/mysql-mariadb-plugins.js +229 -0
  124. package/dist/extensions/catalog/oracle-db2-features.js +196 -0
  125. package/dist/extensions/catalog/postgres-extensions.js +516 -0
  126. package/dist/extensions/index.js +71 -0
  127. package/dist/extensions/types.js +13 -0
  128. package/dist/foreign-data.js +173 -0
  129. package/dist/hooks/hooks-manager.js +350 -0
  130. package/dist/hooks/index.js +37 -0
  131. package/dist/index.js +463 -0
  132. package/dist/logging.js +335 -0
  133. package/dist/migrations/index.js +40 -0
  134. package/dist/migrations/migration.js +196 -0
  135. package/dist/migrations/migrator.js +411 -0
  136. package/dist/migrations/prormmigration.js +275 -0
  137. package/dist/migrations/query-interface.js +435 -0
  138. package/dist/migrations/seeder.js +353 -0
  139. package/dist/models/associations.js +852 -0
  140. package/dist/models/constraints.js +288 -0
  141. package/dist/models/data-types.js +2518 -0
  142. package/dist/models/decorators.js +445 -0
  143. package/dist/models/index.js +33 -0
  144. package/dist/models/indexes.js +531 -0
  145. package/dist/models/methods.js +382 -0
  146. package/dist/models/model-manager.js +103 -0
  147. package/dist/models/model.js +5349 -0
  148. package/dist/models/operators.js +67 -0
  149. package/dist/models/scopes.js +189 -0
  150. package/dist/models/typescript-types.js +26 -0
  151. package/dist/nosql/aerospike/index.js +205 -0
  152. package/dist/nosql/allegrograph/index.js +169 -0
  153. package/dist/nosql/arangodb/index.js +364 -0
  154. package/dist/nosql/azure-blob/index.js +206 -0
  155. package/dist/nosql/beanstalkd/index.js +231 -0
  156. package/dist/nosql/beequeue/index.js +210 -0
  157. package/dist/nosql/bigchaindb/index.js +195 -0
  158. package/dist/nosql/bigtable/index.js +224 -0
  159. package/dist/nosql/blazegraph/index.js +173 -0
  160. package/dist/nosql/bullmq/index.js +191 -0
  161. package/dist/nosql/cassandra/index.js +174 -0
  162. package/dist/nosql/chroma/index.js +190 -0
  163. package/dist/nosql/cloudflare-kv/index.js +220 -0
  164. package/dist/nosql/coherence/index.js +200 -0
  165. package/dist/nosql/cosmosdb/index.js +157 -0
  166. package/dist/nosql/couchbase/index.js +213 -0
  167. package/dist/nosql/dax/index.js +212 -0
  168. package/dist/nosql/deno-kv/index.js +206 -0
  169. package/dist/nosql/dgraph/index.js +171 -0
  170. package/dist/nosql/doris/index.js +169 -0
  171. package/dist/nosql/druid/index.js +162 -0
  172. package/dist/nosql/dynamodb/index.js +937 -0
  173. package/dist/nosql/elasticsearch/index.js +377 -0
  174. package/dist/nosql/etcd/index.js +502 -0
  175. package/dist/nosql/eventhubs/index.js +213 -0
  176. package/dist/nosql/eventstore/index.js +254 -0
  177. package/dist/nosql/faunadb/index.js +188 -0
  178. package/dist/nosql/firestore/index.js +177 -0
  179. package/dist/nosql/fluree/index.js +148 -0
  180. package/dist/nosql/fuseki/index.js +170 -0
  181. package/dist/nosql/gcs/index.js +172 -0
  182. package/dist/nosql/gearman/index.js +160 -0
  183. package/dist/nosql/geode/index.js +196 -0
  184. package/dist/nosql/graphdb/index.js +169 -0
  185. package/dist/nosql/graylog/index.js +188 -0
  186. package/dist/nosql/gridgain/index.js +171 -0
  187. package/dist/nosql/hazelcast/index.js +162 -0
  188. package/dist/nosql/hbase/index.js +230 -0
  189. package/dist/nosql/ignite/index.js +173 -0
  190. package/dist/nosql/immudb/index.js +184 -0
  191. package/dist/nosql/index.js +232 -0
  192. package/dist/nosql/infinispan/index.js +200 -0
  193. package/dist/nosql/influxdb/index.js +0 -0
  194. package/dist/nosql/kafka/index.js +234 -0
  195. package/dist/nosql/keyspaces/index.js +189 -0
  196. package/dist/nosql/kinesis/index.js +253 -0
  197. package/dist/nosql/leveldb/index.js +153 -0
  198. package/dist/nosql/lmdb/index.js +160 -0
  199. package/dist/nosql/loki/index.js +201 -0
  200. package/dist/nosql/marklogic/index.js +204 -0
  201. package/dist/nosql/materialize/index.js +145 -0
  202. package/dist/nosql/meilisearch/index.js +154 -0
  203. package/dist/nosql/memcached/index.js +223 -0
  204. package/dist/nosql/milvus/index.js +410 -0
  205. package/dist/nosql/minio/index.js +265 -0
  206. package/dist/nosql/momento/index.js +179 -0
  207. package/dist/nosql/mongodb/index.js +461 -0
  208. package/dist/nosql/nats/index.js +247 -0
  209. package/dist/nosql/nedb/index.js +164 -0
  210. package/dist/nosql/neo4j/index.js +450 -0
  211. package/dist/nosql/neptune/index.js +470 -0
  212. package/dist/nosql/nsq/index.js +200 -0
  213. package/dist/nosql/opensearch/index.js +186 -0
  214. package/dist/nosql/orientdb/index.js +175 -0
  215. package/dist/nosql/papertrail/index.js +200 -0
  216. package/dist/nosql/pinecone/index.js +0 -0
  217. package/dist/nosql/pinot/index.js +133 -0
  218. package/dist/nosql/pouchdb/index.js +172 -0
  219. package/dist/nosql/prometheus/index.js +174 -0
  220. package/dist/nosql/provendb/index.js +147 -0
  221. package/dist/nosql/pubsub/index.js +187 -0
  222. package/dist/nosql/pulsar/index.js +232 -0
  223. package/dist/nosql/qdrant/index.js +295 -0
  224. package/dist/nosql/qldb/index.js +192 -0
  225. package/dist/nosql/r2/index.js +281 -0
  226. package/dist/nosql/rabbitmq/index.js +237 -0
  227. package/dist/nosql/ravendb/index.js +175 -0
  228. package/dist/nosql/redis/index.js +607 -0
  229. package/dist/nosql/redpanda/index.js +237 -0
  230. package/dist/nosql/resque/index.js +203 -0
  231. package/dist/nosql/rethinkdb/index.js +232 -0
  232. package/dist/nosql/rocksdb/index.js +152 -0
  233. package/dist/nosql/rockset/index.js +126 -0
  234. package/dist/nosql/s3/index.js +298 -0
  235. package/dist/nosql/scylladb/index.js +178 -0
  236. package/dist/nosql/signoz/index.js +227 -0
  237. package/dist/nosql/sns/index.js +201 -0
  238. package/dist/nosql/solr/index.js +231 -0
  239. package/dist/nosql/splunk/index.js +227 -0
  240. package/dist/nosql/sqs/index.js +246 -0
  241. package/dist/nosql/stardog/index.js +169 -0
  242. package/dist/nosql/starrocks/index.js +170 -0
  243. package/dist/nosql/store.js +2 -0
  244. package/dist/nosql/sumologic/index.js +213 -0
  245. package/dist/nosql/surrealdb/index.js +179 -0
  246. package/dist/nosql/terminusdb/index.js +151 -0
  247. package/dist/nosql/tigergraph/index.js +469 -0
  248. package/dist/nosql/typesense/index.js +148 -0
  249. package/dist/nosql/unqlite/index.js +157 -0
  250. package/dist/nosql/upstash/index.js +167 -0
  251. package/dist/nosql/vercel-kv/index.js +166 -0
  252. package/dist/nosql/victoriametrics/index.js +213 -0
  253. package/dist/nosql/virtuoso/index.js +169 -0
  254. package/dist/nosql/weaviate/index.js +276 -0
  255. package/dist/operators/index.js +108 -0
  256. package/dist/operators.js +2690 -0
  257. package/dist/prisma-migrate/index.js +38 -0
  258. package/dist/prisma-migrate/migration-generator.js +125 -0
  259. package/dist/prisma-migrate/model-generator.js +172 -0
  260. package/dist/prisma-migrate/relations.js +100 -0
  261. package/dist/prisma-migrate/schema-parser.js +167 -0
  262. package/dist/prisma-migrate/type-mapper.js +40 -0
  263. package/dist/prorm.js +6832 -0
  264. package/dist/query-builders/cte-builder.js +80 -0
  265. package/dist/query-builders/functions/aggregate.js +390 -0
  266. package/dist/query-builders/functions/conditional.js +503 -0
  267. package/dist/query-builders/functions/datetime.js +695 -0
  268. package/dist/query-builders/functions/fulltext.js +439 -0
  269. package/dist/query-builders/functions/index.js +93 -0
  270. package/dist/query-builders/functions/json.js +427 -0
  271. package/dist/query-builders/functions/math.js +399 -0
  272. package/dist/query-builders/functions/string.js +518 -0
  273. package/dist/query-builders/functions/window.js +328 -0
  274. package/dist/query-builders/include-builder.js +323 -0
  275. package/dist/query-builders/index-expression-builder.js +242 -0
  276. package/dist/query-builders/index.js +161 -0
  277. package/dist/query-builders/insert-builder.js +164 -0
  278. package/dist/query-builders/model-helpers.js +38 -0
  279. package/dist/query-builders/order-limit-builder.js +239 -0
  280. package/dist/query-builders/sql-compiler.js +2040 -0
  281. package/dist/query-builders/subquery-builder.js +152 -0
  282. package/dist/query-builders/update-builder.js +182 -0
  283. package/dist/query-builders/view-builder.js +218 -0
  284. package/dist/query-builders/where-builder.js +1532 -0
  285. package/dist/query-interface.js +622 -0
  286. package/dist/query-optimizers/batch-optimizer.js +426 -0
  287. package/dist/query-optimizers/explain-plans.js +415 -0
  288. package/dist/query-optimizers/index.js +51 -0
  289. package/dist/query-optimizers/prepared-statement-cache.js +423 -0
  290. package/dist/query-optimizers/query-hints.js +438 -0
  291. package/dist/query-optimizers/query-optimizer.js +278 -0
  292. package/dist/query-optimizers/slow-query-logger.js +271 -0
  293. package/dist/replica-manager.js +507 -0
  294. package/dist/schema/index.js +15 -0
  295. package/dist/schema/migration-generator.js +374 -0
  296. package/dist/schema/schema-differ.js +549 -0
  297. package/dist/schema/types.js +6 -0
  298. package/dist/sql-constants.js +300 -0
  299. package/dist/sqlite-advanced.js +1047 -0
  300. package/dist/streams/index.js +12 -0
  301. package/dist/streams/transforms.js +178 -0
  302. package/dist/transaction.js +456 -0
  303. package/dist/types/index.js +180 -0
  304. package/dist/user-management.js +127 -0
  305. package/dist/utils/date.js +300 -0
  306. package/dist/utils/index.js +1079 -0
  307. package/dist/utils/string.js +161 -0
  308. package/dist/validators/index.js +19 -0
  309. package/dist/validators/validator.js +911 -0
  310. package/package.json +190 -0
@@ -0,0 +1,911 @@
1
+ "use strict";
2
+ /**
3
+ * Validator System for the TypeScript ORM
4
+ * Provides comprehensive validation methods and utilities
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.Validator = exports.ValidationError = void 0;
8
+ exports.registerValidatorModel = registerValidatorModel;
9
+ exports.unregisterValidatorModel = unregisterValidatorModel;
10
+ exports.getValidatorModel = getValidatorModel;
11
+ exports.validate = validate;
12
+ exports.validateField = validateField;
13
+ exports.validateAsync = validateAsync;
14
+ exports.validateFieldAsync = validateFieldAsync;
15
+ exports.createValidationError = createValidationError;
16
+ exports.getValidatorsForDataType = getValidatorsForDataType;
17
+ const operators_1 = require("../models/operators");
18
+ // ==================== Validation Error ====================
19
+ /**
20
+ * Custom validation error class that extends Error
21
+ * Contains an array of validation error items
22
+ */
23
+ class ValidationError extends Error {
24
+ constructor(message = 'Validation error', errors = []) {
25
+ super(message);
26
+ this.name = 'PrormValidationError';
27
+ this.errors = errors;
28
+ // Maintains proper stack trace for where error was thrown (V8 engines)
29
+ if (Error.captureStackTrace) {
30
+ Error.captureStackTrace(this, ValidationError);
31
+ }
32
+ }
33
+ /**
34
+ * Add an error to the validation errors array
35
+ */
36
+ addError(error) {
37
+ this.errors.push(error);
38
+ }
39
+ /**
40
+ * Check if there are any validation errors
41
+ */
42
+ hasErrors() {
43
+ return this.errors.length > 0;
44
+ }
45
+ /**
46
+ * Get errors for a specific field
47
+ */
48
+ getErrorsForField(path) {
49
+ return this.errors.filter((error) => error.path === path);
50
+ }
51
+ }
52
+ exports.ValidationError = ValidationError;
53
+ /**
54
+ * Registry mapping a model name to a live model class reference.
55
+ *
56
+ * Validators run inside `src/validators/**` and, by design, have no
57
+ * built-in access to a live `Prorm` instance or model classes. To let
58
+ * `isUnique` perform a real `findOne` uniqueness check without validators
59
+ * importing `src/models/model.ts` (which would create a circular
60
+ * dependency: model.ts -> validators -> model.ts), model classes must be
61
+ * registered here - typically when a model is defined/initialized.
62
+ *
63
+ * NOTE: as of this fix, nothing in `src/models/model.ts` calls
64
+ * `registerValidatorModel` yet. Until it does, `isUnique`/`isUniqueAsync`
65
+ * cannot resolve a `model: 'SomeModelName'` string reference and will fall
66
+ * back to a safe no-op (see `isUniqueAsync` below). Callers can work around
67
+ * this today by passing a live model class directly as `options.model`
68
+ * instead of a string name.
69
+ */
70
+ const modelRegistry = new Map();
71
+ /**
72
+ * Register a live model class so `isUnique`/`isUniqueAsync` validators can
73
+ * resolve a `model: 'SomeModelName'` string reference to a real class with
74
+ * a working `findOne`.
75
+ */
76
+ function registerValidatorModel(name, model) {
77
+ modelRegistry.set(name, model);
78
+ }
79
+ /**
80
+ * Remove a previously registered model reference.
81
+ */
82
+ function unregisterValidatorModel(name) {
83
+ modelRegistry.delete(name);
84
+ }
85
+ /**
86
+ * Look up a registered model reference by name.
87
+ */
88
+ function getValidatorModel(name) {
89
+ return modelRegistry.get(name);
90
+ }
91
+ // ==================== Validator Class ====================
92
+ /**
93
+ * Validator class with built-in validation methods
94
+ * Provides comprehensive validation for various data types
95
+ */
96
+ class Validator {
97
+ /**
98
+ * Check if value is a valid email address
99
+ */
100
+ static isEmail(value) {
101
+ if (value === null || value === undefined || value === '') {
102
+ return true; // Use notEmpty for required fields
103
+ }
104
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
105
+ return emailRegex.test(String(value));
106
+ }
107
+ /**
108
+ * Check if value is a valid URL
109
+ */
110
+ static isUrl(value) {
111
+ if (value === null || value === undefined || value === '') {
112
+ return true;
113
+ }
114
+ try {
115
+ new URL(String(value));
116
+ return true;
117
+ }
118
+ catch {
119
+ return false;
120
+ }
121
+ }
122
+ /**
123
+ * Check if value is a valid IP address (IPv4 or IPv6)
124
+ */
125
+ static isIP(value) {
126
+ if (value === null || value === undefined || value === '') {
127
+ return true;
128
+ }
129
+ const ipValue = String(value);
130
+ // IPv4
131
+ const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
132
+ if (ipv4Regex.test(ipValue)) {
133
+ const parts = ipValue.split('.');
134
+ return parts.every((part) => {
135
+ const num = parseInt(part, 10);
136
+ return num >= 0 && num <= 255;
137
+ });
138
+ }
139
+ // IPv6
140
+ const ipv6Regex = /^([\da-f]{1,4}:){7}[\da-f]{1,4}$/i;
141
+ return ipv6Regex.test(ipValue);
142
+ }
143
+ /**
144
+ * Check if value contains only alphabetic characters
145
+ */
146
+ static isAlpha(value) {
147
+ if (value === null || value === undefined || value === '') {
148
+ return true;
149
+ }
150
+ const alphaRegex = /^[a-zA-Z]+$/;
151
+ return alphaRegex.test(String(value));
152
+ }
153
+ /**
154
+ * Check if value contains only alphanumeric characters
155
+ */
156
+ static isAlphanumeric(value) {
157
+ if (value === null || value === undefined || value === '') {
158
+ return true;
159
+ }
160
+ const alphanumericRegex = /^[a-zA-Z0-9]+$/;
161
+ return alphanumericRegex.test(String(value));
162
+ }
163
+ /**
164
+ * Check if value contains only numeric characters
165
+ */
166
+ static isNumeric(value) {
167
+ if (value === null || value === undefined || value === '') {
168
+ return true;
169
+ }
170
+ const numericRegex = /^[0-9]+$/;
171
+ return numericRegex.test(String(value));
172
+ }
173
+ /**
174
+ * Check if value is an integer
175
+ */
176
+ static isInt(value) {
177
+ if (value === null || value === undefined || value === '') {
178
+ return true;
179
+ }
180
+ if (typeof value === 'number') {
181
+ return Number.isInteger(value);
182
+ }
183
+ const intRegex = /^-?\d+$/;
184
+ return intRegex.test(String(value));
185
+ }
186
+ /**
187
+ * Check if value is a floating-point number
188
+ */
189
+ static isFloat(value) {
190
+ if (value === null || value === undefined || value === '') {
191
+ return true;
192
+ }
193
+ if (typeof value === 'number') {
194
+ return !isNaN(value);
195
+ }
196
+ return !isNaN(parseFloat(String(value)));
197
+ }
198
+ /**
199
+ * Check if value is a decimal number
200
+ */
201
+ static isDecimal(value) {
202
+ if (value === null || value === undefined || value === '') {
203
+ return true;
204
+ }
205
+ const decimalRegex = /^\d+\.\d+$/;
206
+ return decimalRegex.test(String(value));
207
+ }
208
+ /**
209
+ * Check if value is a boolean
210
+ */
211
+ static isBoolean(value) {
212
+ if (value === null || value === undefined || value === '') {
213
+ return true;
214
+ }
215
+ if (typeof value === 'boolean') {
216
+ return true;
217
+ }
218
+ if (typeof value === 'string') {
219
+ const lower = value.toLowerCase();
220
+ return lower === 'true' || lower === 'false' || lower === '1' || lower === '0';
221
+ }
222
+ return typeof value === 'number' && (value === 0 || value === 1);
223
+ }
224
+ /**
225
+ * Check if value is a valid date
226
+ */
227
+ static isDate(value) {
228
+ if (value === null || value === undefined || value === '') {
229
+ return true;
230
+ }
231
+ if (value instanceof Date) {
232
+ return !isNaN(value.getTime());
233
+ }
234
+ const date = new Date(String(value));
235
+ return !isNaN(date.getTime());
236
+ }
237
+ /**
238
+ * Check if value is a valid time string (HH:MM or HH:MM:SS)
239
+ */
240
+ static isTime(value) {
241
+ if (value === null || value === undefined || value === '') {
242
+ return true;
243
+ }
244
+ const timeRegex = /^([01]?[0-9]|2[0-3]):([0-5][0-9])(:([0-5][0-9]))?$/;
245
+ return timeRegex.test(String(value));
246
+ }
247
+ /**
248
+ * Check if value is a valid date string (ISO 8601)
249
+ */
250
+ static isDateString(value) {
251
+ if (value === null || value === undefined || value === '') {
252
+ return true;
253
+ }
254
+ const dateStr = String(value);
255
+ const isoDateRegex = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d{3})?(Z|[+-]\d{2}:\d{2})?)?$/;
256
+ return isoDateRegex.test(dateStr) && Validator.isDate(value);
257
+ }
258
+ /**
259
+ * Check if value is a valid UUID (version 1, 4, 5)
260
+ */
261
+ static isUUID(value) {
262
+ if (value === null || value === undefined || value === '') {
263
+ return true;
264
+ }
265
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
266
+ return uuidRegex.test(String(value));
267
+ }
268
+ /**
269
+ * Check if value is valid JSON
270
+ */
271
+ static isJSON(value) {
272
+ if (value === null || value === undefined || value === '') {
273
+ return true;
274
+ }
275
+ if (typeof value === 'object' && value !== null) {
276
+ try {
277
+ JSON.stringify(value);
278
+ return true;
279
+ }
280
+ catch {
281
+ return false;
282
+ }
283
+ }
284
+ try {
285
+ JSON.parse(String(value));
286
+ return true;
287
+ }
288
+ catch {
289
+ return false;
290
+ }
291
+ }
292
+ /**
293
+ * Check if value is empty (null, undefined, or empty string)
294
+ */
295
+ static isEmpty(value) {
296
+ if (value === null || value === undefined) {
297
+ return true;
298
+ }
299
+ if (typeof value === 'string') {
300
+ return value.trim() === '';
301
+ }
302
+ if (Array.isArray(value)) {
303
+ return value.length === 0;
304
+ }
305
+ return false;
306
+ }
307
+ /**
308
+ * Check if value is not empty
309
+ */
310
+ static notEmpty(value) {
311
+ return !Validator.isEmpty(value);
312
+ }
313
+ /**
314
+ * Check if string length is within bounds
315
+ * @param value - The value to check
316
+ * @param len - Single number for exact length, or [min, max] tuple
317
+ */
318
+ static len(value, len) {
319
+ if (value === null || value === undefined) {
320
+ return true;
321
+ }
322
+ const strValue = String(value);
323
+ const strLen = strValue.length;
324
+ if (typeof len === 'number') {
325
+ return strLen === len;
326
+ }
327
+ const [min, max] = len;
328
+ if (max !== undefined) {
329
+ return strLen >= min && strLen <= max;
330
+ }
331
+ return strLen >= min;
332
+ }
333
+ /**
334
+ * Check if numeric value is >= minimum
335
+ */
336
+ static min(value, minVal) {
337
+ if (value === null || value === undefined || value === '') {
338
+ return true;
339
+ }
340
+ const num = typeof value === 'number' ? value : parseFloat(String(value));
341
+ return !isNaN(num) && num >= minVal;
342
+ }
343
+ /**
344
+ * Check if numeric value is <= maximum
345
+ */
346
+ static max(value, maxVal) {
347
+ if (value === null || value === undefined || value === '') {
348
+ return true;
349
+ }
350
+ const num = typeof value === 'number' ? value : parseFloat(String(value));
351
+ return !isNaN(num) && num <= maxVal;
352
+ }
353
+ /**
354
+ * Check if numeric value is within range
355
+ */
356
+ static range(value, range) {
357
+ const [min, max] = range;
358
+ return Validator.min(value, min) && Validator.max(value, max);
359
+ }
360
+ /**
361
+ * Check if value is in the allowed list
362
+ */
363
+ static isIn(value, values) {
364
+ if (value === null || value === undefined) {
365
+ return true;
366
+ }
367
+ return values.includes(value);
368
+ }
369
+ /**
370
+ * Check if value is not in the disallowed list
371
+ */
372
+ static notIn(value, values) {
373
+ if (value === null || value === undefined) {
374
+ return true;
375
+ }
376
+ return !values.includes(value);
377
+ }
378
+ /**
379
+ * Synchronous uniqueness check.
380
+ *
381
+ * A real uniqueness check requires an async database query, which cannot
382
+ * be performed from a synchronous function. This method exists only for
383
+ * backwards compatibility with call sites that still use the
384
+ * synchronous `validate()`/`validateField()` entry points; it always
385
+ * returns `true` (never fails validation) and logs a warning so silent
386
+ * false-passes are visible.
387
+ *
388
+ * Prefer `Validator.isUniqueAsync()` (via `validateAsync()`/
389
+ * `validateFieldAsync()`) wherever a real database uniqueness check is
390
+ * required.
391
+ */
392
+ static isUnique(value, options) {
393
+ if (value === null || value === undefined) {
394
+ return true;
395
+ }
396
+ if (typeof console !== 'undefined' && console.warn) {
397
+ console.warn('[Validator.isUnique] Synchronous uniqueness checks cannot query the database and ' +
398
+ 'always pass. Use Validator.isUniqueAsync (via validateAsync/validateFieldAsync) for ' +
399
+ `a real uniqueness check${options?.field ? ` on field "${options.field}"` : ''}.`);
400
+ }
401
+ return true;
402
+ }
403
+ /**
404
+ * Check if value is unique by performing a real database lookup via
405
+ * `Model.findOne()`.
406
+ *
407
+ * @param value - The value to check for uniqueness
408
+ * @param options.model - Either a model name registered via
409
+ * `registerValidatorModel()`, or a live model reference (any object
410
+ * exposing an async `findOne({ where })` method, e.g. a Model class).
411
+ * @param options.field - The column/attribute name to check. Defaults to
412
+ * the field the rule was declared on when used via `validateAsync`.
413
+ * @param options.where - Extra where conditions to scope the lookup
414
+ * (e.g. multi-column uniqueness, soft-delete scoping).
415
+ * @param options.exclude - Primary-key (or other) conditions identifying
416
+ * the current instance, so an update does not fail uniqueness against
417
+ * itself. Each entry is turned into a `{ [Op.ne]: value }` condition.
418
+ */
419
+ static async isUniqueAsync(value, options) {
420
+ if (value === null || value === undefined) {
421
+ return true;
422
+ }
423
+ if (!options || !options.field) {
424
+ // Without knowing which column to check, there is nothing to query.
425
+ return true;
426
+ }
427
+ const modelRef = typeof options.model === 'string' ? modelRegistry.get(options.model) : options.model;
428
+ if (!modelRef || typeof modelRef.findOne !== 'function') {
429
+ // No live model reference available (e.g. model not registered).
430
+ // Fail open rather than silently rejecting otherwise-valid data.
431
+ return true;
432
+ }
433
+ const where = {
434
+ [options.field]: value,
435
+ ...(options.where ?? {}),
436
+ };
437
+ if (options.exclude) {
438
+ for (const [key, excludeValue] of Object.entries(options.exclude)) {
439
+ if (excludeValue !== undefined && excludeValue !== null) {
440
+ where[key] = { [operators_1.Op.ne]: excludeValue };
441
+ }
442
+ }
443
+ }
444
+ const existing = await modelRef.findOne({ where });
445
+ return existing === null || existing === undefined;
446
+ }
447
+ /**
448
+ * Check if value equals the expected value
449
+ */
450
+ static equals(value, expected) {
451
+ if (value === null || value === undefined) {
452
+ return expected === null || expected === undefined;
453
+ }
454
+ return value === expected;
455
+ }
456
+ /**
457
+ * Check if value does not equal the expected value
458
+ */
459
+ static notEquals(value, expected) {
460
+ return !Validator.equals(value, expected);
461
+ }
462
+ /**
463
+ * Check if value matches a regular expression
464
+ */
465
+ static matches(value, pattern) {
466
+ if (value === null || value === undefined || value === '') {
467
+ return true;
468
+ }
469
+ const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern;
470
+ return regex.test(String(value));
471
+ }
472
+ /**
473
+ * Check if value does not match a regular expression
474
+ */
475
+ static notMatches(value, pattern) {
476
+ return !Validator.matches(value, pattern);
477
+ }
478
+ // Additional useful validators
479
+ /**
480
+ * Check if value is a valid credit card number (Luhn algorithm)
481
+ */
482
+ static isCreditCard(value) {
483
+ if (value === null || value === undefined || value === '') {
484
+ return true;
485
+ }
486
+ const card = String(value).replace(/\s+/g, '');
487
+ if (!/^\d{13,19}$/.test(card)) {
488
+ return false;
489
+ }
490
+ // Luhn algorithm
491
+ let sum = 0;
492
+ let isEven = false;
493
+ for (let i = card.length - 1; i >= 0; i--) {
494
+ let digit = parseInt(card[i], 10);
495
+ if (isEven) {
496
+ digit *= 2;
497
+ if (digit > 9) {
498
+ digit -= 9;
499
+ }
500
+ }
501
+ sum += digit;
502
+ isEven = !isEven;
503
+ }
504
+ return sum % 10 === 0;
505
+ }
506
+ /**
507
+ * Check if value is a valid postal code
508
+ */
509
+ static isPostalCode(value, locale = 'US') {
510
+ if (value === null || value === undefined || value === '') {
511
+ return true;
512
+ }
513
+ const postalCode = String(value);
514
+ const patterns = {
515
+ US: /^\d{5}(-\d{4})?$/,
516
+ CA: /^[A-Z]\d[A-Z]\s?\d[A-Z]\d$/i,
517
+ UK: /^[A-Z]{1,2}\d{1,2}[A-Z]?\s?\d[A-Z]{2}$/i,
518
+ DE: /^\d{5}$/,
519
+ FR: /^\d{5}$/,
520
+ JP: /^\d{3}-?\d{4}$/,
521
+ };
522
+ const pattern = patterns[locale.toUpperCase()] || /^.+$/;
523
+ return pattern.test(postalCode);
524
+ }
525
+ /**
526
+ * Check if value is a valid phone number
527
+ */
528
+ static isMobilePhone(value, locale = 'en-US') {
529
+ if (value === null || value === undefined || value === '') {
530
+ return true;
531
+ }
532
+ const phone = String(value).replace(/[\s\-\(\)]/g, '');
533
+ const patterns = {
534
+ 'en-US': /^(\+1)?\d{10}$/,
535
+ 'en-GB': /^(\+44)?\d{10}$/,
536
+ 'de-DE': /^(\+49)?\d{10,11}$/,
537
+ 'fr-FR': /^(\+33)?\d{9}$/,
538
+ 'jp-JP': /^(\+81)?\d{9,10}$/,
539
+ };
540
+ const pattern = patterns[locale.toLowerCase()] || /^\+?\d{7,15}$/;
541
+ return pattern.test(phone);
542
+ }
543
+ /**
544
+ * Check if value is a valid hexadecimal color
545
+ */
546
+ static isHexColor(value) {
547
+ if (value === null || value === undefined || value === '') {
548
+ return true;
549
+ }
550
+ const hexColorRegex = /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/;
551
+ return hexColorRegex.test(String(value));
552
+ }
553
+ /**
554
+ * Check if string contains only lowercase characters
555
+ */
556
+ static isLowercase(value) {
557
+ if (value === null || value === undefined || value === '') {
558
+ return true;
559
+ }
560
+ return String(value) === String(value).toLowerCase();
561
+ }
562
+ /**
563
+ * Check if string contains only uppercase characters
564
+ */
565
+ static isUppercase(value) {
566
+ if (value === null || value === undefined || value === '') {
567
+ return true;
568
+ }
569
+ return String(value) === String(value).toUpperCase();
570
+ }
571
+ }
572
+ exports.Validator = Validator;
573
+ // ==================== Validate Function ====================
574
+ /**
575
+ * Validator method map for dynamic method lookup
576
+ */
577
+ const validatorMethods = {
578
+ isEmail: Validator.isEmail,
579
+ isUrl: Validator.isUrl,
580
+ isIP: Validator.isIP,
581
+ isAlpha: Validator.isAlpha,
582
+ isAlphanumeric: Validator.isAlphanumeric,
583
+ isNumeric: Validator.isNumeric,
584
+ isInt: Validator.isInt,
585
+ isFloat: Validator.isFloat,
586
+ isDecimal: Validator.isDecimal,
587
+ isBoolean: Validator.isBoolean,
588
+ isDate: Validator.isDate,
589
+ isTime: Validator.isTime,
590
+ isDateString: Validator.isDateString,
591
+ isUUID: Validator.isUUID,
592
+ isJSON: Validator.isJSON,
593
+ isEmpty: Validator.isEmpty,
594
+ notEmpty: Validator.notEmpty,
595
+ isIn: (value, ...args) => Validator.isIn(value, args),
596
+ notIn: (value, ...args) => Validator.notIn(value, args),
597
+ isUnique: (value, ...args) => Validator.isUnique(value, args[0]),
598
+ equals: Validator.equals,
599
+ notEquals: Validator.notEquals,
600
+ matches: (value, ...args) => Validator.matches(value, args[0]),
601
+ notMatches: (value, ...args) => Validator.notMatches(value, args[0]),
602
+ isCreditCard: Validator.isCreditCard,
603
+ isPostalCode: (value, ...args) => Validator.isPostalCode(value, args[0]),
604
+ isMobilePhone: (value, ...args) => Validator.isMobilePhone(value, args[0]),
605
+ isHexColor: Validator.isHexColor,
606
+ isLowercase: Validator.isLowercase,
607
+ isUppercase: Validator.isUppercase,
608
+ };
609
+ /**
610
+ * Get error message for a validation rule
611
+ */
612
+ function getErrorMessage(rule, field, ruleValue, customMessage) {
613
+ if (customMessage) {
614
+ return customMessage;
615
+ }
616
+ const messages = {
617
+ isEmail: 'Invalid email address',
618
+ isUrl: 'Invalid URL',
619
+ isIP: 'Invalid IP address',
620
+ isAlpha: 'Must contain only letters',
621
+ isAlphanumeric: 'Must contain only letters and numbers',
622
+ isNumeric: 'Must contain only numbers',
623
+ isInt: 'Must be an integer',
624
+ isFloat: 'Must be a number',
625
+ isDecimal: 'Must be a decimal number',
626
+ isBoolean: 'Must be a boolean',
627
+ isDate: 'Invalid date',
628
+ isTime: 'Invalid time format',
629
+ isDateString: 'Invalid date string',
630
+ isUUID: 'Invalid UUID',
631
+ isJSON: 'Invalid JSON',
632
+ isEmpty: 'Cannot be empty',
633
+ notEmpty: 'Cannot be empty',
634
+ isIn: `Must be one of: ${Array.isArray(ruleValue) ? ruleValue.join(', ') : ruleValue}`,
635
+ notIn: `Must not be one of: ${Array.isArray(ruleValue) ? ruleValue.join(', ') : ruleValue}`,
636
+ isUnique: 'Value must be unique',
637
+ equals: `Must equal ${ruleValue}`,
638
+ notEquals: `Must not equal ${ruleValue}`,
639
+ matches: 'Does not match required pattern',
640
+ notMatches: 'Must not match the pattern',
641
+ len: `Length must be ${Array.isArray(ruleValue) ? `${ruleValue[0]}-${ruleValue[1]}` : ruleValue}`,
642
+ min: `Must be at least ${ruleValue}`,
643
+ max: `Must be at most ${ruleValue}`,
644
+ range: `Must be between ${Array.isArray(ruleValue) ? ruleValue.join(' and ') : ruleValue}`,
645
+ isCreditCard: 'Invalid credit card number',
646
+ isPostalCode: 'Invalid postal code',
647
+ isMobilePhone: 'Invalid phone number',
648
+ isHexColor: 'Invalid hex color',
649
+ isLowercase: 'Must be lowercase',
650
+ isUppercase: 'Must be uppercase',
651
+ };
652
+ return messages[rule] || `Validation failed for ${field}`;
653
+ }
654
+ /**
655
+ * Evaluate every synchronous rule except `isUnique` (which needs an async
656
+ * database query - see `Validator.isUniqueAsync`). Shared by `validate`,
657
+ * `validateField`, `validateAsync`, and `validateFieldAsync` so the rule
658
+ * dispatch logic only lives in one place.
659
+ */
660
+ function evaluateSyncRule(rule, value, ruleValue) {
661
+ switch (rule) {
662
+ case 'len':
663
+ return Validator.len(value, ruleValue);
664
+ case 'min':
665
+ return Validator.min(value, ruleValue);
666
+ case 'max':
667
+ return Validator.max(value, ruleValue);
668
+ case 'range':
669
+ return Validator.range(value, ruleValue);
670
+ case 'isIn':
671
+ return Array.isArray(ruleValue) ? Validator.isIn(value, ruleValue) : true;
672
+ case 'notIn':
673
+ return Array.isArray(ruleValue) ? Validator.notIn(value, ruleValue) : true;
674
+ case 'equals':
675
+ return Validator.equals(value, ruleValue);
676
+ case 'notEquals':
677
+ return Validator.notEquals(value, ruleValue);
678
+ case 'matches':
679
+ return Validator.matches(value, ruleValue);
680
+ case 'notMatches':
681
+ return Validator.notMatches(value, ruleValue);
682
+ case 'isUnique':
683
+ // Synchronous fallback only - always passes. Use validateAsync /
684
+ // validateFieldAsync for a real database uniqueness check.
685
+ return Validator.isUnique(value, ruleValue);
686
+ default: {
687
+ const method = validatorMethods[rule];
688
+ return method ? method(value) : true;
689
+ }
690
+ }
691
+ }
692
+ function shouldSkipRule(ruleValue) {
693
+ return ruleValue === false;
694
+ }
695
+ function getCustomMessage(rule, ruleValue) {
696
+ if (typeof ruleValue === 'string' && rule !== 'isIn' && rule !== 'notIn') {
697
+ return ruleValue;
698
+ }
699
+ return undefined;
700
+ }
701
+ /**
702
+ * Run all validators on data and return validation result
703
+ * @param data - The data object to validate
704
+ * @param validators - The validator configuration
705
+ * @returns Validation result with valid flag and errors array
706
+ */
707
+ function validate(data, validators) {
708
+ const errors = [];
709
+ for (const [field, rules] of Object.entries(validators)) {
710
+ const value = data[field];
711
+ for (const [rule, ruleValue] of Object.entries(rules)) {
712
+ // Skip if ruleValue is false (validation disabled)
713
+ if (shouldSkipRule(ruleValue)) {
714
+ continue;
715
+ }
716
+ const isValid = evaluateSyncRule(rule, value, ruleValue);
717
+ if (!isValid) {
718
+ const customMessage = getCustomMessage(rule, ruleValue);
719
+ const message = getErrorMessage(rule, field, ruleValue, customMessage);
720
+ errors.push({
721
+ message,
722
+ type: 'Validation error',
723
+ path: field,
724
+ value: value,
725
+ });
726
+ }
727
+ }
728
+ }
729
+ return {
730
+ valid: errors.length === 0,
731
+ errors,
732
+ };
733
+ }
734
+ /**
735
+ * Validate a single field with given rules
736
+ */
737
+ function validateField(value, rules) {
738
+ const errors = [];
739
+ for (const [rule, ruleValue] of Object.entries(rules)) {
740
+ if (shouldSkipRule(ruleValue)) {
741
+ continue;
742
+ }
743
+ const isValid = evaluateSyncRule(rule, value, ruleValue);
744
+ if (!isValid) {
745
+ const customMessage = getCustomMessage(rule, ruleValue);
746
+ const message = getErrorMessage(rule, 'value', ruleValue, customMessage);
747
+ errors.push({
748
+ message,
749
+ type: 'Validation error',
750
+ path: 'value',
751
+ value: value,
752
+ });
753
+ }
754
+ }
755
+ return {
756
+ valid: errors.length === 0,
757
+ errors,
758
+ };
759
+ }
760
+ /**
761
+ * Async counterpart to `validate()` that performs a real database
762
+ * uniqueness check for `isUnique` rules (via `Validator.isUniqueAsync`)
763
+ * instead of always passing.
764
+ *
765
+ * @param data - The data object to validate
766
+ * @param validators - The validator configuration
767
+ * @param context - Optional async context, e.g. `{ exclude: { id: 5 } }`
768
+ * to exclude the current record from the uniqueness lookup on update.
769
+ */
770
+ async function validateAsync(data, validators, context) {
771
+ const errors = [];
772
+ for (const [field, rules] of Object.entries(validators)) {
773
+ const value = data[field];
774
+ for (const [rule, ruleValue] of Object.entries(rules)) {
775
+ if (shouldSkipRule(ruleValue)) {
776
+ continue;
777
+ }
778
+ let isValid;
779
+ if (rule === 'isUnique') {
780
+ const opts = (typeof ruleValue === 'object' && ruleValue !== null && !Array.isArray(ruleValue)
781
+ ? ruleValue
782
+ : {});
783
+ isValid = await Validator.isUniqueAsync(value, {
784
+ model: opts.model,
785
+ field: opts.field ?? field,
786
+ where: opts.where,
787
+ exclude: context?.exclude,
788
+ });
789
+ }
790
+ else {
791
+ isValid = evaluateSyncRule(rule, value, ruleValue);
792
+ }
793
+ if (!isValid) {
794
+ const customMessage = getCustomMessage(rule, ruleValue);
795
+ const message = getErrorMessage(rule, field, ruleValue, customMessage);
796
+ errors.push({
797
+ message,
798
+ type: 'Validation error',
799
+ path: field,
800
+ value: value,
801
+ });
802
+ }
803
+ }
804
+ }
805
+ return {
806
+ valid: errors.length === 0,
807
+ errors,
808
+ };
809
+ }
810
+ /**
811
+ * Async counterpart to `validateField()` - see `validateAsync`.
812
+ */
813
+ async function validateFieldAsync(value, rules, context) {
814
+ const errors = [];
815
+ for (const [rule, ruleValue] of Object.entries(rules)) {
816
+ if (shouldSkipRule(ruleValue)) {
817
+ continue;
818
+ }
819
+ let isValid;
820
+ if (rule === 'isUnique') {
821
+ const opts = (typeof ruleValue === 'object' && ruleValue !== null && !Array.isArray(ruleValue)
822
+ ? ruleValue
823
+ : {});
824
+ isValid = await Validator.isUniqueAsync(value, {
825
+ model: opts.model,
826
+ field: opts.field ?? context?.field,
827
+ where: opts.where,
828
+ exclude: context?.exclude,
829
+ });
830
+ }
831
+ else {
832
+ isValid = evaluateSyncRule(rule, value, ruleValue);
833
+ }
834
+ if (!isValid) {
835
+ const customMessage = getCustomMessage(rule, ruleValue);
836
+ const message = getErrorMessage(rule, 'value', ruleValue, customMessage);
837
+ errors.push({
838
+ message,
839
+ type: 'Validation error',
840
+ path: 'value',
841
+ value: value,
842
+ });
843
+ }
844
+ }
845
+ return {
846
+ valid: errors.length === 0,
847
+ errors,
848
+ };
849
+ }
850
+ /**
851
+ * Create a ValidationError from validation result
852
+ */
853
+ function createValidationError(result) {
854
+ const error = new ValidationError(result.errors.length > 0 ? result.errors[0].message : 'Validation error', result.errors);
855
+ return error;
856
+ }
857
+ // ==================== DataType Integration ====================
858
+ /**
859
+ * Get validation rules based on DataType
860
+ * Useful for automatic validation based on column type
861
+ */
862
+ function getValidatorsForDataType(dataType) {
863
+ const validators = {};
864
+ switch (dataType.toUpperCase()) {
865
+ case 'INTEGER':
866
+ case 'BIGINT':
867
+ validators.isInt = true;
868
+ break;
869
+ case 'FLOAT':
870
+ case 'DOUBLE':
871
+ case 'DECIMAL':
872
+ validators.isFloat = true;
873
+ break;
874
+ case 'BOOLEAN':
875
+ validators.isBoolean = true;
876
+ break;
877
+ case 'DATE':
878
+ case 'DATETIME':
879
+ validators.isDate = true;
880
+ break;
881
+ case 'DATEONLY':
882
+ validators.isDateString = true;
883
+ break;
884
+ case 'TIME':
885
+ validators.isTime = true;
886
+ break;
887
+ case 'UUID':
888
+ case 'UUIDV4':
889
+ validators.isUUID = true;
890
+ break;
891
+ case 'JSON':
892
+ case 'JSONB':
893
+ validators.isJSON = true;
894
+ break;
895
+ case 'TEXT':
896
+ case 'VARCHAR':
897
+ case 'CHAR':
898
+ case 'STRING':
899
+ // No specific validators for string types
900
+ break;
901
+ }
902
+ return validators;
903
+ }
904
+ exports.default = {
905
+ Validator,
906
+ ValidationError,
907
+ validate,
908
+ validateField,
909
+ createValidationError,
910
+ getValidatorsForDataType,
911
+ };