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.
- package/CHANGELOG.md +1111 -0
- package/LICENSE +21 -0
- package/README.md +573 -0
- package/dist/audit/history-query.js +180 -0
- package/dist/audit/index.js +23 -0
- package/dist/audit/logger.js +236 -0
- package/dist/cache/cache-manager.js +84 -0
- package/dist/cache/index.js +16 -0
- package/dist/cache/redis-cluster-cache.js +557 -0
- package/dist/cli.js +2200 -0
- package/dist/compliance/audit-trail.js +68 -0
- package/dist/compliance/backup-verification.js +685 -0
- package/dist/compliance/breach-detector.js +505 -0
- package/dist/compliance/consent-record.js +227 -0
- package/dist/compliance/consent-versioning.js +331 -0
- package/dist/compliance/cross-border-log.js +530 -0
- package/dist/compliance/data-classifier.js +258 -0
- package/dist/compliance/data-lineage.js +565 -0
- package/dist/compliance/data-masker.js +303 -0
- package/dist/compliance/data-portability.js +265 -0
- package/dist/compliance/data-retention.js +195 -0
- package/dist/compliance/dsar-workflow.js +342 -0
- package/dist/compliance/field-encryption.js +223 -0
- package/dist/compliance/immutable-record.js +148 -0
- package/dist/compliance/index.js +260 -0
- package/dist/compliance/privacy-impact-assessment.js +364 -0
- package/dist/compliance/pseudonymization.js +269 -0
- package/dist/compliance/query-firewall.js +1182 -0
- package/dist/compliance/rate-limiter.js +580 -0
- package/dist/compliance/right-to-erasure.js +117 -0
- package/dist/compliance/row-level-security.js +246 -0
- package/dist/compliance/security-decorator.js +574 -0
- package/dist/compliance/security-monitor.js +525 -0
- package/dist/compliance/sensitive-data-discovery.js +476 -0
- package/dist/compliance/session-isolation.js +472 -0
- package/dist/compliance/tls-enforcer.js +108 -0
- package/dist/compliance/worm-storage.js +712 -0
- package/dist/connection-manager.js +198 -0
- package/dist/connection-pool.js +519 -0
- package/dist/decorators/audit.js +136 -0
- package/dist/decorators/belongs-to-many.js +115 -0
- package/dist/decorators/belongs-to.js +115 -0
- package/dist/decorators/check.js +435 -0
- package/dist/decorators/collate.js +329 -0
- package/dist/decorators/comment.js +205 -0
- package/dist/decorators/database-settings.js +236 -0
- package/dist/decorators/default.js +244 -0
- package/dist/decorators/encryption.js +235 -0
- package/dist/decorators/engine.js +97 -0
- package/dist/decorators/fk-constraints.js +594 -0
- package/dist/decorators/foreign-table.js +136 -0
- package/dist/decorators/generated.js +274 -0
- package/dist/decorators/has-many.js +127 -0
- package/dist/decorators/has-one.js +116 -0
- package/dist/decorators/hstore.js +129 -0
- package/dist/decorators/index.js +355 -0
- package/dist/decorators/json-column.js +83 -0
- package/dist/decorators/jsonb.js +101 -0
- package/dist/decorators/orm-decorators.js +425 -0
- package/dist/decorators/permissions.js +294 -0
- package/dist/decorators/procedure.js +210 -0
- package/dist/decorators/query-options.js +556 -0
- package/dist/decorators/range.js +167 -0
- package/dist/decorators/set-column.js +83 -0
- package/dist/decorators/spatial.js +114 -0
- package/dist/decorators/storage.js +580 -0
- package/dist/decorators/timezone.js +512 -0
- package/dist/decorators/trigger.js +90 -0
- package/dist/decorators/uuid.js +135 -0
- package/dist/decorators/view.js +258 -0
- package/dist/diagrams/chen-diagram.js +354 -0
- package/dist/diagrams/class-diagram.js +384 -0
- package/dist/diagrams/dependency-diagram.js +432 -0
- package/dist/diagrams/er-diagram.js +605 -0
- package/dist/diagrams/flow-diagram.js +394 -0
- package/dist/diagrams/gantt-diagram.js +411 -0
- package/dist/diagrams/index-diagram.js +353 -0
- package/dist/diagrams/index.js +184 -0
- package/dist/diagrams/migration-diagram.js +316 -0
- package/dist/diagrams/model-diagram.js +616 -0
- package/dist/diagrams/package-diagram.js +376 -0
- package/dist/diagrams/palette.js +85 -0
- package/dist/diagrams/relational-diagram.js +455 -0
- package/dist/diagrams/schemadoc-diagram.js +309 -0
- package/dist/diagrams/sequence-diagram.js +307 -0
- package/dist/diagrams/state-diagram.js +344 -0
- package/dist/diagrams/svg-dom.js +111 -0
- package/dist/diagrams/tree-diagram.js +250 -0
- package/dist/dialects/clickhouse/index.js +1742 -0
- package/dist/dialects/cockroachdb/index.js +4677 -0
- package/dist/dialects/cratedb/index.js +441 -0
- package/dist/dialects/databricks/index.js +517 -0
- package/dist/dialects/db2/index.js +2225 -0
- package/dist/dialects/dialect.js +720 -0
- package/dist/dialects/duckdb/index.js +2014 -0
- package/dist/dialects/exasol/index.js +357 -0
- package/dist/dialects/firebird/index.js +495 -0
- package/dist/dialects/greenplum/index.js +457 -0
- package/dist/dialects/hana/index.js +1741 -0
- package/dist/dialects/mariadb/index.js +3590 -0
- package/dist/dialects/mssql/index.js +2296 -0
- package/dist/dialects/mysql/index.js +4058 -0
- package/dist/dialects/oracle/index.js +2999 -0
- package/dist/dialects/postgres/index.js +5319 -0
- package/dist/dialects/query-stream-helper.js +152 -0
- package/dist/dialects/questdb/index.js +433 -0
- package/dist/dialects/redshift/index.js +2277 -0
- package/dist/dialects/singlestore/index.js +354 -0
- package/dist/dialects/snowflake/index.js +2082 -0
- package/dist/dialects/spanner/index.js +1768 -0
- package/dist/dialects/sqlite/index.js +3382 -0
- package/dist/dialects/tidb/index.js +377 -0
- package/dist/dialects/timescaledb/index.js +164 -0
- package/dist/dialects/trino/index.js +420 -0
- package/dist/dialects/turso/index.js +227 -0
- package/dist/dialects/vertica/index.js +317 -0
- package/dist/dialects/yugabytedb/index.js +424 -0
- package/dist/errors/index.js +472 -0
- package/dist/errors/utils.js +340 -0
- package/dist/errors.js +21 -0
- package/dist/extensions/catalog/cloud-warehouse-features.js +207 -0
- package/dist/extensions/catalog/mssql-features.js +147 -0
- package/dist/extensions/catalog/mysql-mariadb-plugins.js +229 -0
- package/dist/extensions/catalog/oracle-db2-features.js +196 -0
- package/dist/extensions/catalog/postgres-extensions.js +516 -0
- package/dist/extensions/index.js +71 -0
- package/dist/extensions/types.js +13 -0
- package/dist/foreign-data.js +173 -0
- package/dist/hooks/hooks-manager.js +350 -0
- package/dist/hooks/index.js +37 -0
- package/dist/index.js +463 -0
- package/dist/logging.js +335 -0
- package/dist/migrations/index.js +40 -0
- package/dist/migrations/migration.js +196 -0
- package/dist/migrations/migrator.js +411 -0
- package/dist/migrations/prormmigration.js +275 -0
- package/dist/migrations/query-interface.js +435 -0
- package/dist/migrations/seeder.js +353 -0
- package/dist/models/associations.js +852 -0
- package/dist/models/constraints.js +288 -0
- package/dist/models/data-types.js +2518 -0
- package/dist/models/decorators.js +445 -0
- package/dist/models/index.js +33 -0
- package/dist/models/indexes.js +531 -0
- package/dist/models/methods.js +382 -0
- package/dist/models/model-manager.js +103 -0
- package/dist/models/model.js +5349 -0
- package/dist/models/operators.js +67 -0
- package/dist/models/scopes.js +189 -0
- package/dist/models/typescript-types.js +26 -0
- package/dist/nosql/aerospike/index.js +205 -0
- package/dist/nosql/allegrograph/index.js +169 -0
- package/dist/nosql/arangodb/index.js +364 -0
- package/dist/nosql/azure-blob/index.js +206 -0
- package/dist/nosql/beanstalkd/index.js +231 -0
- package/dist/nosql/beequeue/index.js +210 -0
- package/dist/nosql/bigchaindb/index.js +195 -0
- package/dist/nosql/bigtable/index.js +224 -0
- package/dist/nosql/blazegraph/index.js +173 -0
- package/dist/nosql/bullmq/index.js +191 -0
- package/dist/nosql/cassandra/index.js +174 -0
- package/dist/nosql/chroma/index.js +190 -0
- package/dist/nosql/cloudflare-kv/index.js +220 -0
- package/dist/nosql/coherence/index.js +200 -0
- package/dist/nosql/cosmosdb/index.js +157 -0
- package/dist/nosql/couchbase/index.js +213 -0
- package/dist/nosql/dax/index.js +212 -0
- package/dist/nosql/deno-kv/index.js +206 -0
- package/dist/nosql/dgraph/index.js +171 -0
- package/dist/nosql/doris/index.js +169 -0
- package/dist/nosql/druid/index.js +162 -0
- package/dist/nosql/dynamodb/index.js +937 -0
- package/dist/nosql/elasticsearch/index.js +377 -0
- package/dist/nosql/etcd/index.js +502 -0
- package/dist/nosql/eventhubs/index.js +213 -0
- package/dist/nosql/eventstore/index.js +254 -0
- package/dist/nosql/faunadb/index.js +188 -0
- package/dist/nosql/firestore/index.js +177 -0
- package/dist/nosql/fluree/index.js +148 -0
- package/dist/nosql/fuseki/index.js +170 -0
- package/dist/nosql/gcs/index.js +172 -0
- package/dist/nosql/gearman/index.js +160 -0
- package/dist/nosql/geode/index.js +196 -0
- package/dist/nosql/graphdb/index.js +169 -0
- package/dist/nosql/graylog/index.js +188 -0
- package/dist/nosql/gridgain/index.js +171 -0
- package/dist/nosql/hazelcast/index.js +162 -0
- package/dist/nosql/hbase/index.js +230 -0
- package/dist/nosql/ignite/index.js +173 -0
- package/dist/nosql/immudb/index.js +184 -0
- package/dist/nosql/index.js +232 -0
- package/dist/nosql/infinispan/index.js +200 -0
- package/dist/nosql/influxdb/index.js +0 -0
- package/dist/nosql/kafka/index.js +234 -0
- package/dist/nosql/keyspaces/index.js +189 -0
- package/dist/nosql/kinesis/index.js +253 -0
- package/dist/nosql/leveldb/index.js +153 -0
- package/dist/nosql/lmdb/index.js +160 -0
- package/dist/nosql/loki/index.js +201 -0
- package/dist/nosql/marklogic/index.js +204 -0
- package/dist/nosql/materialize/index.js +145 -0
- package/dist/nosql/meilisearch/index.js +154 -0
- package/dist/nosql/memcached/index.js +223 -0
- package/dist/nosql/milvus/index.js +410 -0
- package/dist/nosql/minio/index.js +265 -0
- package/dist/nosql/momento/index.js +179 -0
- package/dist/nosql/mongodb/index.js +461 -0
- package/dist/nosql/nats/index.js +247 -0
- package/dist/nosql/nedb/index.js +164 -0
- package/dist/nosql/neo4j/index.js +450 -0
- package/dist/nosql/neptune/index.js +470 -0
- package/dist/nosql/nsq/index.js +200 -0
- package/dist/nosql/opensearch/index.js +186 -0
- package/dist/nosql/orientdb/index.js +175 -0
- package/dist/nosql/papertrail/index.js +200 -0
- package/dist/nosql/pinecone/index.js +0 -0
- package/dist/nosql/pinot/index.js +133 -0
- package/dist/nosql/pouchdb/index.js +172 -0
- package/dist/nosql/prometheus/index.js +174 -0
- package/dist/nosql/provendb/index.js +147 -0
- package/dist/nosql/pubsub/index.js +187 -0
- package/dist/nosql/pulsar/index.js +232 -0
- package/dist/nosql/qdrant/index.js +295 -0
- package/dist/nosql/qldb/index.js +192 -0
- package/dist/nosql/r2/index.js +281 -0
- package/dist/nosql/rabbitmq/index.js +237 -0
- package/dist/nosql/ravendb/index.js +175 -0
- package/dist/nosql/redis/index.js +607 -0
- package/dist/nosql/redpanda/index.js +237 -0
- package/dist/nosql/resque/index.js +203 -0
- package/dist/nosql/rethinkdb/index.js +232 -0
- package/dist/nosql/rocksdb/index.js +152 -0
- package/dist/nosql/rockset/index.js +126 -0
- package/dist/nosql/s3/index.js +298 -0
- package/dist/nosql/scylladb/index.js +178 -0
- package/dist/nosql/signoz/index.js +227 -0
- package/dist/nosql/sns/index.js +201 -0
- package/dist/nosql/solr/index.js +231 -0
- package/dist/nosql/splunk/index.js +227 -0
- package/dist/nosql/sqs/index.js +246 -0
- package/dist/nosql/stardog/index.js +169 -0
- package/dist/nosql/starrocks/index.js +170 -0
- package/dist/nosql/store.js +2 -0
- package/dist/nosql/sumologic/index.js +213 -0
- package/dist/nosql/surrealdb/index.js +179 -0
- package/dist/nosql/terminusdb/index.js +151 -0
- package/dist/nosql/tigergraph/index.js +469 -0
- package/dist/nosql/typesense/index.js +148 -0
- package/dist/nosql/unqlite/index.js +157 -0
- package/dist/nosql/upstash/index.js +167 -0
- package/dist/nosql/vercel-kv/index.js +166 -0
- package/dist/nosql/victoriametrics/index.js +213 -0
- package/dist/nosql/virtuoso/index.js +169 -0
- package/dist/nosql/weaviate/index.js +276 -0
- package/dist/operators/index.js +108 -0
- package/dist/operators.js +2690 -0
- package/dist/prisma-migrate/index.js +38 -0
- package/dist/prisma-migrate/migration-generator.js +125 -0
- package/dist/prisma-migrate/model-generator.js +172 -0
- package/dist/prisma-migrate/relations.js +100 -0
- package/dist/prisma-migrate/schema-parser.js +167 -0
- package/dist/prisma-migrate/type-mapper.js +40 -0
- package/dist/prorm.js +6832 -0
- package/dist/query-builders/cte-builder.js +80 -0
- package/dist/query-builders/functions/aggregate.js +390 -0
- package/dist/query-builders/functions/conditional.js +503 -0
- package/dist/query-builders/functions/datetime.js +695 -0
- package/dist/query-builders/functions/fulltext.js +439 -0
- package/dist/query-builders/functions/index.js +93 -0
- package/dist/query-builders/functions/json.js +427 -0
- package/dist/query-builders/functions/math.js +399 -0
- package/dist/query-builders/functions/string.js +518 -0
- package/dist/query-builders/functions/window.js +328 -0
- package/dist/query-builders/include-builder.js +323 -0
- package/dist/query-builders/index-expression-builder.js +242 -0
- package/dist/query-builders/index.js +161 -0
- package/dist/query-builders/insert-builder.js +164 -0
- package/dist/query-builders/model-helpers.js +38 -0
- package/dist/query-builders/order-limit-builder.js +239 -0
- package/dist/query-builders/sql-compiler.js +2040 -0
- package/dist/query-builders/subquery-builder.js +152 -0
- package/dist/query-builders/update-builder.js +182 -0
- package/dist/query-builders/view-builder.js +218 -0
- package/dist/query-builders/where-builder.js +1532 -0
- package/dist/query-interface.js +622 -0
- package/dist/query-optimizers/batch-optimizer.js +426 -0
- package/dist/query-optimizers/explain-plans.js +415 -0
- package/dist/query-optimizers/index.js +51 -0
- package/dist/query-optimizers/prepared-statement-cache.js +423 -0
- package/dist/query-optimizers/query-hints.js +438 -0
- package/dist/query-optimizers/query-optimizer.js +278 -0
- package/dist/query-optimizers/slow-query-logger.js +271 -0
- package/dist/replica-manager.js +507 -0
- package/dist/schema/index.js +15 -0
- package/dist/schema/migration-generator.js +374 -0
- package/dist/schema/schema-differ.js +549 -0
- package/dist/schema/types.js +6 -0
- package/dist/sql-constants.js +300 -0
- package/dist/sqlite-advanced.js +1047 -0
- package/dist/streams/index.js +12 -0
- package/dist/streams/transforms.js +178 -0
- package/dist/transaction.js +456 -0
- package/dist/types/index.js +180 -0
- package/dist/user-management.js +127 -0
- package/dist/utils/date.js +300 -0
- package/dist/utils/index.js +1079 -0
- package/dist/utils/string.js +161 -0
- package/dist/validators/index.js +19 -0
- package/dist/validators/validator.js +911 -0
- package/package.json +190 -0
|
@@ -0,0 +1,2518 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Data Types for the ORM
|
|
4
|
+
* Provides all standard data types with proper class implementations
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.GEOMETRYCOLLECTION = exports.MULTIPOLYGON = exports.MULTILINESTRING = exports.MULTIPOINT = exports.POLYGON = exports.LINESTRING = exports.POINT = exports.GEOGRAPHY = exports.GEOMETRY = exports.DUCKDB_UNION = exports.MAP = exports.STRUCT = exports.LIST = exports.ARRAY = exports.ENUM = exports.VARBINARY = exports.BINARY = exports.LONGBLOB = exports.MEDIUMBLOB = exports.TINYBLOB = exports.BLOB = exports.JSONB = exports.JSON = exports.UUIDV4 = exports.UUIDV1 = exports.UUID = exports.TIME = exports.NOW = exports.TIMESTAMP = exports.DATETIME = exports.DATEONLY = exports.DATE = exports.BOOLEAN = exports.REAL = exports.DECIMAL = exports.DOUBLE = exports.FLOAT = exports.BIGINT = exports.MEDIUMINT = exports.SMALLINT = exports.TINYINT = exports.INTEGER = exports.LONGTEXT = exports.MEDIUMTEXT = exports.TINYTEXT = exports.TEXT = exports.CHAR = exports.VARCHAR = exports.STRING = exports.DataTypes = void 0;
|
|
8
|
+
exports.AbstractDataType = exports.MACADDR = exports.CIDR = exports.INET = exports.RANGE = exports.HSTORE = exports.ALGORITHM = exports.VIRTUALSTRING = exports.VIRTUAL = exports.JSONColumn = exports.SET = void 0;
|
|
9
|
+
/**
|
|
10
|
+
* Base class for all data types
|
|
11
|
+
*/
|
|
12
|
+
class AbstractDataType {
|
|
13
|
+
toSqlString(dialect) {
|
|
14
|
+
return this.key;
|
|
15
|
+
}
|
|
16
|
+
toSQL() {
|
|
17
|
+
return this.toSqlString();
|
|
18
|
+
}
|
|
19
|
+
// Alias for toSQL for compatibility
|
|
20
|
+
toSql() {
|
|
21
|
+
return this.toSqlString();
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Compare this DataType with another DataType for equality
|
|
25
|
+
* @param other - The DataType to compare with
|
|
26
|
+
* @returns true if the types are equal, false otherwise
|
|
27
|
+
*/
|
|
28
|
+
equals(other) {
|
|
29
|
+
if (!other || typeof other !== 'object') {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
return this.key === other.key;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Serialize a value for storage based on this DataType
|
|
36
|
+
* @param value - The value to serialize
|
|
37
|
+
* @returns The serialized value
|
|
38
|
+
*/
|
|
39
|
+
serialize(value) {
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.AbstractDataType = AbstractDataType;
|
|
44
|
+
// STRING types
|
|
45
|
+
class STRING extends AbstractDataType {
|
|
46
|
+
/**
|
|
47
|
+
* Create a STRING data type
|
|
48
|
+
* @param length - Optional length (1-65535). If not provided, defaults to TEXT
|
|
49
|
+
* @param binary - Whether to use BINARY collation
|
|
50
|
+
* @example
|
|
51
|
+
* // STRING with length (VARCHAR)
|
|
52
|
+
* DataTypes.STRING(100) // VARCHAR(100)
|
|
53
|
+
* // STRING without length (TEXT)
|
|
54
|
+
* DataTypes.STRING // TEXT
|
|
55
|
+
*/
|
|
56
|
+
constructor(length, binary = false) {
|
|
57
|
+
super();
|
|
58
|
+
this.key = 'STRING';
|
|
59
|
+
this.length = length;
|
|
60
|
+
this.binary = binary;
|
|
61
|
+
}
|
|
62
|
+
toSqlString() {
|
|
63
|
+
// If no length specified, return TEXT
|
|
64
|
+
if (this.length === undefined || this.length === null) {
|
|
65
|
+
return 'TEXT';
|
|
66
|
+
}
|
|
67
|
+
const binaryStr = this.binary ? ' BINARY' : '';
|
|
68
|
+
return `VARCHAR(${this.length})${binaryStr}`;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.STRING = STRING;
|
|
72
|
+
class VARCHAR extends AbstractDataType {
|
|
73
|
+
constructor(length = 255, binary = false) {
|
|
74
|
+
super();
|
|
75
|
+
this.key = 'VARCHAR';
|
|
76
|
+
this.length = length;
|
|
77
|
+
this.binary = binary;
|
|
78
|
+
}
|
|
79
|
+
toSqlString() {
|
|
80
|
+
const binaryStr = this.binary ? ' BINARY' : '';
|
|
81
|
+
return `VARCHAR(${this.length})${binaryStr}`;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
exports.VARCHAR = VARCHAR;
|
|
85
|
+
class CHAR extends AbstractDataType {
|
|
86
|
+
constructor(length = 1) {
|
|
87
|
+
super();
|
|
88
|
+
this.key = 'CHAR';
|
|
89
|
+
this.length = length;
|
|
90
|
+
}
|
|
91
|
+
toSqlString() {
|
|
92
|
+
return `CHAR(${this.length})`;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
exports.CHAR = CHAR;
|
|
96
|
+
// TEXT types
|
|
97
|
+
class TEXT extends AbstractDataType {
|
|
98
|
+
constructor(length) {
|
|
99
|
+
super();
|
|
100
|
+
this.key = 'TEXT';
|
|
101
|
+
this.length = length;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Get the TEXT type string based on length variant for MySQL/MariaDB
|
|
105
|
+
*/
|
|
106
|
+
getTextType() {
|
|
107
|
+
if (!this.length) {
|
|
108
|
+
return 'TEXT';
|
|
109
|
+
}
|
|
110
|
+
// MySQL/MariaDB format: TINYTEXT, MEDIUMTEXT, LONGTEXT
|
|
111
|
+
if (this.length === 'tiny')
|
|
112
|
+
return 'TINYTEXT';
|
|
113
|
+
if (this.length === 'medium')
|
|
114
|
+
return 'MEDIUMTEXT';
|
|
115
|
+
if (this.length === 'long')
|
|
116
|
+
return 'LONGTEXT';
|
|
117
|
+
return 'TEXT';
|
|
118
|
+
}
|
|
119
|
+
toSqlString(dialect) {
|
|
120
|
+
switch (dialect) {
|
|
121
|
+
case 'postgres':
|
|
122
|
+
// PostgreSQL: Use TEXT for all variants
|
|
123
|
+
return 'TEXT';
|
|
124
|
+
case 'mysql':
|
|
125
|
+
case 'mariadb':
|
|
126
|
+
// MySQL/MariaDB: TINYTEXT, TEXT, MEDIUMTEXT, LONGTEXT
|
|
127
|
+
return this.getTextType();
|
|
128
|
+
case 'sqlite':
|
|
129
|
+
// SQLite: Use TEXT for all variants
|
|
130
|
+
return 'TEXT';
|
|
131
|
+
case 'mssql':
|
|
132
|
+
case 'sqlserver':
|
|
133
|
+
// SQL Server: Use TEXT (deprecated) or NVARCHAR(MAX) for large text
|
|
134
|
+
return 'NVARCHAR(MAX)';
|
|
135
|
+
default:
|
|
136
|
+
// Default to standard TEXT
|
|
137
|
+
return this.getTextType();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
exports.TEXT = TEXT;
|
|
142
|
+
// Convenience classes for specific TEXT length variants (MySQL/MariaDB)
|
|
143
|
+
class TINYTEXT extends AbstractDataType {
|
|
144
|
+
constructor() {
|
|
145
|
+
super(...arguments);
|
|
146
|
+
this.key = 'TINYTEXT';
|
|
147
|
+
}
|
|
148
|
+
toSqlString(dialect) {
|
|
149
|
+
switch (dialect) {
|
|
150
|
+
case 'postgres':
|
|
151
|
+
case 'sqlite':
|
|
152
|
+
return 'TEXT';
|
|
153
|
+
case 'mysql':
|
|
154
|
+
case 'mariadb':
|
|
155
|
+
return 'TINYTEXT';
|
|
156
|
+
case 'mssql':
|
|
157
|
+
case 'sqlserver':
|
|
158
|
+
return 'NVARCHAR(MAX)';
|
|
159
|
+
default:
|
|
160
|
+
return 'TINYTEXT';
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
exports.TINYTEXT = TINYTEXT;
|
|
165
|
+
class MEDIUMTEXT extends AbstractDataType {
|
|
166
|
+
constructor() {
|
|
167
|
+
super(...arguments);
|
|
168
|
+
this.key = 'MEDIUMTEXT';
|
|
169
|
+
}
|
|
170
|
+
toSqlString(dialect) {
|
|
171
|
+
switch (dialect) {
|
|
172
|
+
case 'postgres':
|
|
173
|
+
case 'sqlite':
|
|
174
|
+
return 'TEXT';
|
|
175
|
+
case 'mysql':
|
|
176
|
+
case 'mariadb':
|
|
177
|
+
return 'MEDIUMTEXT';
|
|
178
|
+
case 'mssql':
|
|
179
|
+
case 'sqlserver':
|
|
180
|
+
return 'NVARCHAR(MAX)';
|
|
181
|
+
default:
|
|
182
|
+
return 'MEDIUMTEXT';
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
exports.MEDIUMTEXT = MEDIUMTEXT;
|
|
187
|
+
class LONGTEXT extends AbstractDataType {
|
|
188
|
+
constructor() {
|
|
189
|
+
super(...arguments);
|
|
190
|
+
this.key = 'LONGTEXT';
|
|
191
|
+
}
|
|
192
|
+
toSqlString(dialect) {
|
|
193
|
+
switch (dialect) {
|
|
194
|
+
case 'postgres':
|
|
195
|
+
case 'sqlite':
|
|
196
|
+
return 'TEXT';
|
|
197
|
+
case 'mysql':
|
|
198
|
+
case 'mariadb':
|
|
199
|
+
return 'LONGTEXT';
|
|
200
|
+
case 'mssql':
|
|
201
|
+
case 'sqlserver':
|
|
202
|
+
return 'NVARCHAR(MAX)';
|
|
203
|
+
default:
|
|
204
|
+
return 'LONGTEXT';
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
exports.LONGTEXT = LONGTEXT;
|
|
209
|
+
// Base class for integer types with unsigned and zerofill support
|
|
210
|
+
class AbstractIntegerType extends AbstractDataType {
|
|
211
|
+
/**
|
|
212
|
+
* Set as unsigned
|
|
213
|
+
* @example
|
|
214
|
+
* DataTypes.INTEGER.UNSIGNED()
|
|
215
|
+
* DataTypes.BIGINT.UNSIGNED()
|
|
216
|
+
*/
|
|
217
|
+
UNSIGNED() {
|
|
218
|
+
this.unsigned = true;
|
|
219
|
+
return this;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Set as zerofill
|
|
223
|
+
* @example
|
|
224
|
+
* DataTypes.INTEGER.ZEROFILL()
|
|
225
|
+
* DataTypes.INTEGER.UNSIGNED().ZEROFILL()
|
|
226
|
+
*/
|
|
227
|
+
ZEROFILL() {
|
|
228
|
+
this.zerofill = true;
|
|
229
|
+
return this;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Generate SQL string with unsigned and zerofill options
|
|
233
|
+
*/
|
|
234
|
+
toSqlStringHelper(baseType) {
|
|
235
|
+
let sql = baseType;
|
|
236
|
+
if (this.length) {
|
|
237
|
+
sql = `${baseType}(${this.length})`;
|
|
238
|
+
}
|
|
239
|
+
if (this.unsigned) {
|
|
240
|
+
sql += ' UNSIGNED';
|
|
241
|
+
}
|
|
242
|
+
if (this.zerofill) {
|
|
243
|
+
sql += ' ZEROFILL';
|
|
244
|
+
}
|
|
245
|
+
return sql;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// Number types
|
|
249
|
+
class INTEGER extends AbstractIntegerType {
|
|
250
|
+
constructor(options = {}) {
|
|
251
|
+
super();
|
|
252
|
+
this.key = 'INTEGER';
|
|
253
|
+
this.length = options.length;
|
|
254
|
+
this.unsigned = options.unsigned;
|
|
255
|
+
this.zerofill = options.zerofill;
|
|
256
|
+
}
|
|
257
|
+
toSqlString() {
|
|
258
|
+
return this.toSqlStringHelper('INTEGER');
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
exports.INTEGER = INTEGER;
|
|
262
|
+
// TINYINT - tiny integer (1 byte, -128 to 127 signed, 0 to 255 unsigned)
|
|
263
|
+
class TINYINT extends AbstractIntegerType {
|
|
264
|
+
/**
|
|
265
|
+
* Create a TINYINT data type
|
|
266
|
+
* @param options - Optional options object
|
|
267
|
+
* @example
|
|
268
|
+
* // Simple TINYINT
|
|
269
|
+
* DataTypes.TINYINT()
|
|
270
|
+
* // TINYINT with options
|
|
271
|
+
* DataTypes.TINYINT({ unsigned: true })
|
|
272
|
+
* // Using chainable methods
|
|
273
|
+
* DataTypes.TINYINT().UNSIGNED()
|
|
274
|
+
* DataTypes.TINYINT().ZEROFILL()
|
|
275
|
+
*/
|
|
276
|
+
constructor(options = {}) {
|
|
277
|
+
super();
|
|
278
|
+
this.key = 'TINYINT';
|
|
279
|
+
this.length = options.length;
|
|
280
|
+
this.unsigned = options.unsigned;
|
|
281
|
+
this.zerofill = options.zerofill;
|
|
282
|
+
}
|
|
283
|
+
toSqlString() {
|
|
284
|
+
return this.toSqlStringHelper('TINYINT');
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
exports.TINYINT = TINYINT;
|
|
288
|
+
// SMALLINT - small integer (2 bytes, -32768 to 32767 signed, 0 to 65535 unsigned)
|
|
289
|
+
class SMALLINT extends AbstractIntegerType {
|
|
290
|
+
/**
|
|
291
|
+
* Create a SMALLINT data type
|
|
292
|
+
* @param options - Optional options object
|
|
293
|
+
* @example
|
|
294
|
+
* // Simple SMALLINT
|
|
295
|
+
* DataTypes.SMALLINT()
|
|
296
|
+
* // SMALLINT with options
|
|
297
|
+
* DataTypes.SMALLINT({ unsigned: true })
|
|
298
|
+
* // Using chainable methods
|
|
299
|
+
* DataTypes.SMALLINT().UNSIGNED()
|
|
300
|
+
* DataTypes.SMALLINT().ZEROFILL()
|
|
301
|
+
*/
|
|
302
|
+
constructor(options = {}) {
|
|
303
|
+
super();
|
|
304
|
+
this.key = 'SMALLINT';
|
|
305
|
+
this.length = options.length;
|
|
306
|
+
this.unsigned = options.unsigned;
|
|
307
|
+
this.zerofill = options.zerofill;
|
|
308
|
+
}
|
|
309
|
+
toSqlString() {
|
|
310
|
+
return this.toSqlStringHelper('SMALLINT');
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
exports.SMALLINT = SMALLINT;
|
|
314
|
+
// MEDIUMINT - medium integer (3 bytes, -8388608 to 8388607 signed, 0 to 16777215 unsigned)
|
|
315
|
+
class MEDIUMINT extends AbstractIntegerType {
|
|
316
|
+
/**
|
|
317
|
+
* Create a MEDIUMINT data type
|
|
318
|
+
* @param options - Optional options object
|
|
319
|
+
* @example
|
|
320
|
+
* // Simple MEDIUMINT
|
|
321
|
+
* DataTypes.MEDIUMINT()
|
|
322
|
+
* // MEDIUMINT with options
|
|
323
|
+
* DataTypes.MEDIUMINT({ unsigned: true })
|
|
324
|
+
* // Using chainable methods
|
|
325
|
+
* DataTypes.MEDIUMINT().UNSIGNED()
|
|
326
|
+
* DataTypes.MEDIUMINT().ZEROFILL()
|
|
327
|
+
*/
|
|
328
|
+
constructor(options = {}) {
|
|
329
|
+
super();
|
|
330
|
+
this.key = 'MEDIUMINT';
|
|
331
|
+
this.length = options.length;
|
|
332
|
+
this.unsigned = options.unsigned;
|
|
333
|
+
this.zerofill = options.zerofill;
|
|
334
|
+
}
|
|
335
|
+
toSqlString() {
|
|
336
|
+
return this.toSqlStringHelper('MEDIUMINT');
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
exports.MEDIUMINT = MEDIUMINT;
|
|
340
|
+
class BIGINT extends AbstractIntegerType {
|
|
341
|
+
/**
|
|
342
|
+
* Create a BIGINT data type
|
|
343
|
+
* @param options - Optional options object
|
|
344
|
+
* @example
|
|
345
|
+
* // Simple BIGINT
|
|
346
|
+
* DataTypes.BIGINT()
|
|
347
|
+
* // BIGINT with options
|
|
348
|
+
* DataTypes.BIGINT({ unsigned: true })
|
|
349
|
+
* // Using chainable methods
|
|
350
|
+
* DataTypes.BIGINT().UNSIGNED()
|
|
351
|
+
* DataTypes.BIGINT().ZEROFILL()
|
|
352
|
+
*/
|
|
353
|
+
constructor(options = {}) {
|
|
354
|
+
super();
|
|
355
|
+
this.key = 'BIGINT';
|
|
356
|
+
this.length = options.length;
|
|
357
|
+
this.unsigned = options.unsigned;
|
|
358
|
+
this.zerofill = options.zerofill;
|
|
359
|
+
}
|
|
360
|
+
toSqlString() {
|
|
361
|
+
return this.toSqlStringHelper('BIGINT');
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
exports.BIGINT = BIGINT;
|
|
365
|
+
class FLOAT extends AbstractDataType {
|
|
366
|
+
/**
|
|
367
|
+
* Create a FLOAT data type
|
|
368
|
+
* @param precisionOrOptions - Either a precision number or an options object
|
|
369
|
+
* @example
|
|
370
|
+
* // Simple FLOAT
|
|
371
|
+
* DataTypes.FLOAT()
|
|
372
|
+
* // FLOAT with precision
|
|
373
|
+
* DataTypes.FLOAT(8)
|
|
374
|
+
* // FLOAT with options
|
|
375
|
+
* DataTypes.FLOAT({ precision: 8, decimals: 2, unsigned: true })
|
|
376
|
+
*/
|
|
377
|
+
constructor(precisionOrOptions) {
|
|
378
|
+
super();
|
|
379
|
+
this.key = 'FLOAT';
|
|
380
|
+
if (typeof precisionOrOptions === 'number') {
|
|
381
|
+
this.precision = precisionOrOptions;
|
|
382
|
+
}
|
|
383
|
+
else if (precisionOrOptions) {
|
|
384
|
+
this.precision = precisionOrOptions.precision;
|
|
385
|
+
this.decimals = precisionOrOptions.decimals;
|
|
386
|
+
this.unsigned = precisionOrOptions.unsigned;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
toSqlString(dialect) {
|
|
390
|
+
let sql = 'FLOAT';
|
|
391
|
+
if (this.precision) {
|
|
392
|
+
// MySQL/MariaDB support FLOAT(p) where p is precision
|
|
393
|
+
if (this.decimals) {
|
|
394
|
+
sql = `FLOAT(${this.precision},${this.decimals})`;
|
|
395
|
+
}
|
|
396
|
+
else if (dialect === 'mysql' || dialect === 'mariadb') {
|
|
397
|
+
sql = `FLOAT(${this.precision})`;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
if (this.unsigned) {
|
|
401
|
+
sql += ' UNSIGNED';
|
|
402
|
+
}
|
|
403
|
+
return sql;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
exports.FLOAT = FLOAT;
|
|
407
|
+
class DOUBLE extends AbstractDataType {
|
|
408
|
+
/**
|
|
409
|
+
* Create a DOUBLE data type
|
|
410
|
+
* @param precisionOrOptions - Either a precision number or an options object
|
|
411
|
+
* @example
|
|
412
|
+
* // Simple DOUBLE
|
|
413
|
+
* DataTypes.DOUBLE()
|
|
414
|
+
* // DOUBLE with precision (MySQL/MariaDB)
|
|
415
|
+
* DataTypes.DOUBLE(16)
|
|
416
|
+
* // DOUBLE with options (backward compatibility)
|
|
417
|
+
* DataTypes.DOUBLE({ precision: 16, decimals: 4, unsigned: true })
|
|
418
|
+
*/
|
|
419
|
+
constructor(precisionOrOptions) {
|
|
420
|
+
super();
|
|
421
|
+
this.key = 'DOUBLE';
|
|
422
|
+
if (typeof precisionOrOptions === 'number') {
|
|
423
|
+
this.precision = precisionOrOptions;
|
|
424
|
+
}
|
|
425
|
+
else if (precisionOrOptions) {
|
|
426
|
+
this.precision = precisionOrOptions.precision;
|
|
427
|
+
this.decimals = precisionOrOptions.decimals;
|
|
428
|
+
this.unsigned = precisionOrOptions.unsigned;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
toSqlString(dialect) {
|
|
432
|
+
let sql = 'DOUBLE';
|
|
433
|
+
if (this.precision) {
|
|
434
|
+
// MySQL/MariaDB support DOUBLE(p) where p is precision
|
|
435
|
+
if (this.decimals) {
|
|
436
|
+
sql = `DOUBLE(${this.precision},${this.decimals})`;
|
|
437
|
+
}
|
|
438
|
+
else if (dialect === 'mysql' || dialect === 'mariadb') {
|
|
439
|
+
sql = `DOUBLE(${this.precision})`;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
else if (this.decimals) {
|
|
443
|
+
// Backward compatibility: DOUBLE with only decimals
|
|
444
|
+
sql = `DOUBLE(10,${this.decimals})`;
|
|
445
|
+
}
|
|
446
|
+
if (this.unsigned) {
|
|
447
|
+
sql += ' UNSIGNED';
|
|
448
|
+
}
|
|
449
|
+
return sql;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
exports.DOUBLE = DOUBLE;
|
|
453
|
+
class DECIMAL extends AbstractDataType {
|
|
454
|
+
/**
|
|
455
|
+
* Create a DECIMAL data type
|
|
456
|
+
* @param precisionOrOptions - Either precision number or an options object
|
|
457
|
+
* @param scale - Number of decimal places (when precision is a number)
|
|
458
|
+
* @param unsigned - Whether the value is unsigned
|
|
459
|
+
* @example
|
|
460
|
+
* // DECIMAL with default precision (10, 0)
|
|
461
|
+
* DataTypes.DECIMAL()
|
|
462
|
+
* // DECIMAL with precision only (scale defaults to 0)
|
|
463
|
+
* DataTypes.DECIMAL(10)
|
|
464
|
+
* // DECIMAL with precision and scale
|
|
465
|
+
* DataTypes.DECIMAL(10, 2)
|
|
466
|
+
* // DECIMAL with options object
|
|
467
|
+
* DataTypes.DECIMAL({ precision: 10, scale: 2, unsigned: true })
|
|
468
|
+
*/
|
|
469
|
+
constructor(precisionOrOptions, scale = 0, unsigned = false) {
|
|
470
|
+
super();
|
|
471
|
+
this.key = 'DECIMAL';
|
|
472
|
+
if (typeof precisionOrOptions === 'number') {
|
|
473
|
+
this.precision = precisionOrOptions;
|
|
474
|
+
this.scale = scale;
|
|
475
|
+
this.unsigned = unsigned;
|
|
476
|
+
}
|
|
477
|
+
else if (precisionOrOptions) {
|
|
478
|
+
this.precision = precisionOrOptions.precision ?? 10;
|
|
479
|
+
this.scale = precisionOrOptions.scale ?? 0;
|
|
480
|
+
this.unsigned = precisionOrOptions.unsigned;
|
|
481
|
+
}
|
|
482
|
+
else {
|
|
483
|
+
// Default: DECIMAL(10, 0)
|
|
484
|
+
this.precision = 10;
|
|
485
|
+
this.scale = 0;
|
|
486
|
+
this.unsigned = false;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
toSqlString(dialect) {
|
|
490
|
+
let sql = `DECIMAL(${this.precision},${this.scale})`;
|
|
491
|
+
// UNSIGNED is not standard for DECIMAL in most dialects
|
|
492
|
+
// Only MySQL/MariaDB support it
|
|
493
|
+
if (this.unsigned && (dialect === 'mysql' || dialect === 'mariadb')) {
|
|
494
|
+
sql += ' UNSIGNED';
|
|
495
|
+
}
|
|
496
|
+
return sql;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
exports.DECIMAL = DECIMAL;
|
|
500
|
+
// Boolean
|
|
501
|
+
class BOOLEAN extends AbstractDataType {
|
|
502
|
+
constructor() {
|
|
503
|
+
super(...arguments);
|
|
504
|
+
this.key = 'BOOLEAN';
|
|
505
|
+
}
|
|
506
|
+
toSqlString() {
|
|
507
|
+
return 'INTEGER'; // SQLite uses INTEGER for booleans
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
exports.BOOLEAN = BOOLEAN;
|
|
511
|
+
// Date types
|
|
512
|
+
class DATE extends AbstractDataType {
|
|
513
|
+
constructor(precision, timezone = false) {
|
|
514
|
+
super();
|
|
515
|
+
this.key = 'DATE';
|
|
516
|
+
this.precision = precision;
|
|
517
|
+
this.timezone = timezone;
|
|
518
|
+
}
|
|
519
|
+
toSqlString(dialect) {
|
|
520
|
+
const precisionStr = this.precision !== undefined ? `(${this.precision})` : '';
|
|
521
|
+
switch (dialect) {
|
|
522
|
+
case 'postgres':
|
|
523
|
+
// PostgreSQL: TIMESTAMP WITH/WITHOUT TIME ZONE
|
|
524
|
+
return this.timezone
|
|
525
|
+
? `TIMESTAMP${precisionStr} WITH TIME ZONE`
|
|
526
|
+
: `TIMESTAMP${precisionStr}`;
|
|
527
|
+
case 'mysql':
|
|
528
|
+
case 'mariadb':
|
|
529
|
+
// MySQL/MariaDB: DATETIME or TIMESTAMP
|
|
530
|
+
return `DATETIME${precisionStr}`;
|
|
531
|
+
case 'sqlite':
|
|
532
|
+
// SQLite stores dates as TEXT in ISO8601 format
|
|
533
|
+
return `TEXT`;
|
|
534
|
+
case 'mssql':
|
|
535
|
+
case 'sqlserver':
|
|
536
|
+
// SQL Server: DATETIME2 for more precision
|
|
537
|
+
return `DATETIME2${precisionStr}`;
|
|
538
|
+
default:
|
|
539
|
+
return `DATETIME${precisionStr}`;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
exports.DATE = DATE;
|
|
544
|
+
class DATEONLY extends AbstractDataType {
|
|
545
|
+
constructor() {
|
|
546
|
+
super(...arguments);
|
|
547
|
+
this.key = 'DATEONLY';
|
|
548
|
+
}
|
|
549
|
+
toSqlString(dialect) {
|
|
550
|
+
switch (dialect) {
|
|
551
|
+
case 'postgres':
|
|
552
|
+
// PostgreSQL: DATE
|
|
553
|
+
return 'DATE';
|
|
554
|
+
case 'mysql':
|
|
555
|
+
case 'mariadb':
|
|
556
|
+
// MySQL/MariaDB: DATE
|
|
557
|
+
return 'DATE';
|
|
558
|
+
case 'sqlite':
|
|
559
|
+
// SQLite stores dates as TEXT in ISO8601 format (YYYY-MM-DD)
|
|
560
|
+
return 'TEXT';
|
|
561
|
+
case 'mssql':
|
|
562
|
+
case 'sqlserver':
|
|
563
|
+
// SQL Server: DATE
|
|
564
|
+
return 'DATE';
|
|
565
|
+
default:
|
|
566
|
+
return 'DATE';
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
exports.DATEONLY = DATEONLY;
|
|
571
|
+
class TIME extends AbstractDataType {
|
|
572
|
+
constructor(precision, timezone = false) {
|
|
573
|
+
super();
|
|
574
|
+
this.key = 'TIME';
|
|
575
|
+
this.precision = precision;
|
|
576
|
+
this.timezone = timezone;
|
|
577
|
+
}
|
|
578
|
+
toSqlString(dialect) {
|
|
579
|
+
const precisionStr = this.precision !== undefined ? `(${this.precision})` : '';
|
|
580
|
+
switch (dialect) {
|
|
581
|
+
case 'postgres':
|
|
582
|
+
// PostgreSQL: TIME WITH/WITHOUT TIME ZONE
|
|
583
|
+
return this.timezone ? `TIME${precisionStr} WITH TIME ZONE` : `TIME${precisionStr}`;
|
|
584
|
+
case 'mysql':
|
|
585
|
+
case 'mariadb':
|
|
586
|
+
// MySQL/MariaDB: TIME
|
|
587
|
+
return `TIME${precisionStr}`;
|
|
588
|
+
case 'sqlite':
|
|
589
|
+
// SQLite stores time as TEXT in ISO8601 format
|
|
590
|
+
return `TEXT`;
|
|
591
|
+
case 'mssql':
|
|
592
|
+
case 'sqlserver':
|
|
593
|
+
// SQL Server: TIME
|
|
594
|
+
return `TIME${precisionStr}`;
|
|
595
|
+
default:
|
|
596
|
+
return `TIME${precisionStr}`;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
exports.TIME = TIME;
|
|
601
|
+
// REAL - single-precision floating point (native SQLite storage class,
|
|
602
|
+
// PostgreSQL/MSSQL 4-byte float, alias for FLOAT/DOUBLE in MySQL/MariaDB)
|
|
603
|
+
class REAL extends AbstractDataType {
|
|
604
|
+
/**
|
|
605
|
+
* Create a REAL data type
|
|
606
|
+
* @param precisionOrOptions - Either a precision number or an options object
|
|
607
|
+
* @example
|
|
608
|
+
* // Simple REAL
|
|
609
|
+
* DataTypes.REAL()
|
|
610
|
+
* // REAL with precision (MySQL/MariaDB)
|
|
611
|
+
* DataTypes.REAL(10)
|
|
612
|
+
* // REAL with options
|
|
613
|
+
* DataTypes.REAL({ precision: 10, decimals: 2, unsigned: true })
|
|
614
|
+
*/
|
|
615
|
+
constructor(precisionOrOptions) {
|
|
616
|
+
super();
|
|
617
|
+
this.key = 'REAL';
|
|
618
|
+
if (typeof precisionOrOptions === 'number') {
|
|
619
|
+
this.precision = precisionOrOptions;
|
|
620
|
+
}
|
|
621
|
+
else if (precisionOrOptions) {
|
|
622
|
+
this.precision = precisionOrOptions.precision;
|
|
623
|
+
this.decimals = precisionOrOptions.decimals;
|
|
624
|
+
this.unsigned = precisionOrOptions.unsigned;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
toSqlString(dialect) {
|
|
628
|
+
let sql = 'REAL';
|
|
629
|
+
if (this.precision && this.decimals && (dialect === 'mysql' || dialect === 'mariadb')) {
|
|
630
|
+
// MySQL/MariaDB REAL is an alias for DOUBLE and supports (precision,decimals)
|
|
631
|
+
sql = `REAL(${this.precision},${this.decimals})`;
|
|
632
|
+
}
|
|
633
|
+
if (this.unsigned && (dialect === 'mysql' || dialect === 'mariadb')) {
|
|
634
|
+
sql += ' UNSIGNED';
|
|
635
|
+
}
|
|
636
|
+
return sql;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
exports.REAL = REAL;
|
|
640
|
+
// TIMESTAMP - dedicated timestamp type distinct from DATE/NOW
|
|
641
|
+
class TIMESTAMP extends AbstractDataType {
|
|
642
|
+
constructor(precision) {
|
|
643
|
+
super();
|
|
644
|
+
this.key = 'TIMESTAMP';
|
|
645
|
+
this.precision = precision;
|
|
646
|
+
}
|
|
647
|
+
toSqlString(dialect) {
|
|
648
|
+
const precisionStr = this.precision !== undefined ? `(${this.precision})` : '';
|
|
649
|
+
switch (dialect) {
|
|
650
|
+
case 'postgres':
|
|
651
|
+
return `TIMESTAMP${precisionStr}`;
|
|
652
|
+
case 'mysql':
|
|
653
|
+
case 'mariadb':
|
|
654
|
+
return `TIMESTAMP${precisionStr}`;
|
|
655
|
+
case 'sqlite':
|
|
656
|
+
// SQLite stores timestamps as TEXT in ISO8601 format
|
|
657
|
+
return 'TEXT';
|
|
658
|
+
case 'mssql':
|
|
659
|
+
case 'sqlserver':
|
|
660
|
+
return `DATETIME2${precisionStr}`;
|
|
661
|
+
default:
|
|
662
|
+
return `TIMESTAMP${precisionStr}`;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* Get the current timestamp SQL for use as a default value
|
|
667
|
+
*/
|
|
668
|
+
toDefaultValue(dialect) {
|
|
669
|
+
switch (dialect) {
|
|
670
|
+
case 'sqlite':
|
|
671
|
+
return "datetime('now')";
|
|
672
|
+
case 'mssql':
|
|
673
|
+
case 'sqlserver':
|
|
674
|
+
return 'GETDATE()';
|
|
675
|
+
default:
|
|
676
|
+
return 'CURRENT_TIMESTAMP';
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
exports.TIMESTAMP = TIMESTAMP;
|
|
681
|
+
// DATETIME - explicit datetime type (distinct from DATE, which supports timezone options)
|
|
682
|
+
class DATETIME extends AbstractDataType {
|
|
683
|
+
constructor(precision) {
|
|
684
|
+
super();
|
|
685
|
+
this.key = 'DATETIME';
|
|
686
|
+
this.precision = precision;
|
|
687
|
+
}
|
|
688
|
+
toSqlString(dialect) {
|
|
689
|
+
const precisionStr = this.precision !== undefined ? `(${this.precision})` : '';
|
|
690
|
+
switch (dialect) {
|
|
691
|
+
case 'postgres':
|
|
692
|
+
return `TIMESTAMP${precisionStr}`;
|
|
693
|
+
case 'mysql':
|
|
694
|
+
case 'mariadb':
|
|
695
|
+
return `DATETIME${precisionStr}`;
|
|
696
|
+
case 'sqlite':
|
|
697
|
+
// SQLite stores dates as TEXT in ISO8601 format
|
|
698
|
+
return 'TEXT';
|
|
699
|
+
case 'mssql':
|
|
700
|
+
case 'sqlserver':
|
|
701
|
+
return `DATETIME2${precisionStr}`;
|
|
702
|
+
default:
|
|
703
|
+
return `DATETIME${precisionStr}`;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
exports.DATETIME = DATETIME;
|
|
708
|
+
// UUID - stores UUID strings (works with all dialects)
|
|
709
|
+
class UUID extends AbstractDataType {
|
|
710
|
+
constructor() {
|
|
711
|
+
super(...arguments);
|
|
712
|
+
this.key = 'UUID';
|
|
713
|
+
}
|
|
714
|
+
toSqlString(dialect) {
|
|
715
|
+
switch (dialect) {
|
|
716
|
+
case 'postgres':
|
|
717
|
+
return 'UUID';
|
|
718
|
+
case 'mysql':
|
|
719
|
+
case 'mariadb':
|
|
720
|
+
return 'VARCHAR(36)';
|
|
721
|
+
case 'sqlite':
|
|
722
|
+
default:
|
|
723
|
+
return 'TEXT';
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
exports.UUID = UUID;
|
|
728
|
+
// UUIDV4 - auto-generates UUID v4 on insert (works with all dialects)
|
|
729
|
+
class UUIDV4 extends AbstractDataType {
|
|
730
|
+
constructor() {
|
|
731
|
+
super(...arguments);
|
|
732
|
+
this.key = 'UUIDV4';
|
|
733
|
+
}
|
|
734
|
+
toSqlString(dialect) {
|
|
735
|
+
switch (dialect) {
|
|
736
|
+
case 'postgres':
|
|
737
|
+
return 'UUID';
|
|
738
|
+
case 'mysql':
|
|
739
|
+
case 'mariadb':
|
|
740
|
+
return 'VARCHAR(36)';
|
|
741
|
+
case 'sqlite':
|
|
742
|
+
default:
|
|
743
|
+
return 'TEXT';
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* Get the default value for UUIDV4 - generates a new UUID v4 string
|
|
748
|
+
* This is called by the dialect when using UUIDV4 as a defaultValue
|
|
749
|
+
*/
|
|
750
|
+
toDefaultValue(_dialect) {
|
|
751
|
+
return UUIDV4.generate();
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Generate a UUID v4 string (instance method)
|
|
755
|
+
*/
|
|
756
|
+
generate() {
|
|
757
|
+
return UUIDV4.generate();
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* Generate a UUID v4 string (static method)
|
|
761
|
+
*/
|
|
762
|
+
static generate() {
|
|
763
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
764
|
+
const r = (Math.random() * 16) | 0;
|
|
765
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
766
|
+
return v.toString(16);
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
exports.UUIDV4 = UUIDV4;
|
|
771
|
+
// UUIDV1 - auto-generates a time-based UUID v1 on insert (works with all dialects)
|
|
772
|
+
class UUIDV1 extends AbstractDataType {
|
|
773
|
+
constructor() {
|
|
774
|
+
super(...arguments);
|
|
775
|
+
this.key = 'UUIDV1';
|
|
776
|
+
}
|
|
777
|
+
toSqlString(dialect) {
|
|
778
|
+
switch (dialect) {
|
|
779
|
+
case 'postgres':
|
|
780
|
+
return 'UUID';
|
|
781
|
+
case 'mysql':
|
|
782
|
+
case 'mariadb':
|
|
783
|
+
return 'VARCHAR(36)';
|
|
784
|
+
case 'sqlite':
|
|
785
|
+
default:
|
|
786
|
+
return 'TEXT';
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* Get the default value for UUIDV1 - generates a new UUID v1 string
|
|
791
|
+
* This is called by the dialect when using UUIDV1 as a defaultValue
|
|
792
|
+
*/
|
|
793
|
+
toDefaultValue(_dialect) {
|
|
794
|
+
return UUIDV1.generate();
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* Generate a UUID v1 string (instance method)
|
|
798
|
+
*/
|
|
799
|
+
generate() {
|
|
800
|
+
return UUIDV1.generate();
|
|
801
|
+
}
|
|
802
|
+
/**
|
|
803
|
+
* Generate a time-based UUID v1 string (static method)
|
|
804
|
+
* Note: This is a simplified, structurally-valid v1 UUID (RFC 4122 layout:
|
|
805
|
+
* time_low-time_mid-time_hi_and_version-clock_seq-node) derived from the
|
|
806
|
+
* current timestamp. It does not track a persistent MAC address or clock
|
|
807
|
+
* sequence across calls, which is acceptable for use as a unique row id.
|
|
808
|
+
*/
|
|
809
|
+
static generate() {
|
|
810
|
+
// 100-nanosecond intervals between the UUID epoch (1582-10-15) and the Unix epoch
|
|
811
|
+
const UUID_EPOCH_OFFSET = 122192928000000000n;
|
|
812
|
+
const timestamp = BigInt(Date.now()) * 10000n + UUID_EPOCH_OFFSET;
|
|
813
|
+
const timeLow = (timestamp & 0xffffffffn).toString(16).padStart(8, '0');
|
|
814
|
+
const timeMid = ((timestamp >> 32n) & 0xffffn).toString(16).padStart(4, '0');
|
|
815
|
+
const timeHiAndVersion = (((timestamp >> 48n) & 0x0fffn) | 0x1000n)
|
|
816
|
+
.toString(16)
|
|
817
|
+
.padStart(4, '0');
|
|
818
|
+
const clockSeq = ((Math.floor(Math.random() * 0x3fff) & 0x3fff) | 0x8000)
|
|
819
|
+
.toString(16)
|
|
820
|
+
.padStart(4, '0');
|
|
821
|
+
const node = Array.from({ length: 6 }, () => Math.floor(Math.random() * 256)
|
|
822
|
+
.toString(16)
|
|
823
|
+
.padStart(2, '0')).join('');
|
|
824
|
+
return `${timeLow}-${timeMid}-${timeHiAndVersion}-${clockSeq}-${node}`;
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
exports.UUIDV1 = UUIDV1;
|
|
828
|
+
// NOW - current timestamp
|
|
829
|
+
class NOW extends AbstractDataType {
|
|
830
|
+
constructor(precision) {
|
|
831
|
+
super();
|
|
832
|
+
this.key = 'NOW';
|
|
833
|
+
this.precision = precision;
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* Get the current timestamp SQL for use as default value
|
|
837
|
+
* This returns the raw SQL function name that gets passed through
|
|
838
|
+
* without quotes in the defaultValue handling
|
|
839
|
+
*/
|
|
840
|
+
toDefaultValue(dialect) {
|
|
841
|
+
switch (dialect) {
|
|
842
|
+
case 'postgres':
|
|
843
|
+
// PostgreSQL: CURRENT_TIMESTAMP or NOW()
|
|
844
|
+
return 'CURRENT_TIMESTAMP';
|
|
845
|
+
case 'mysql':
|
|
846
|
+
case 'mariadb':
|
|
847
|
+
// MySQL/MariaDB: CURRENT_TIMESTAMP or NOW()
|
|
848
|
+
return 'CURRENT_TIMESTAMP';
|
|
849
|
+
case 'sqlite':
|
|
850
|
+
// SQLite: datetime('now')
|
|
851
|
+
return "datetime('now')";
|
|
852
|
+
case 'mssql':
|
|
853
|
+
case 'sqlserver':
|
|
854
|
+
// SQL Server: GETDATE() or GETUTCDATE()
|
|
855
|
+
return 'GETDATE()';
|
|
856
|
+
default:
|
|
857
|
+
// Default to standard SQL
|
|
858
|
+
return 'CURRENT_TIMESTAMP';
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
toSqlString(dialect) {
|
|
862
|
+
// When used as a column type, generate proper DATETIME type
|
|
863
|
+
const precisionStr = this.precision !== undefined ? `(${this.precision})` : '';
|
|
864
|
+
switch (dialect) {
|
|
865
|
+
case 'postgres':
|
|
866
|
+
return `TIMESTAMP${precisionStr}`;
|
|
867
|
+
case 'mysql':
|
|
868
|
+
case 'mariadb':
|
|
869
|
+
return `DATETIME${precisionStr}`;
|
|
870
|
+
case 'sqlite':
|
|
871
|
+
// SQLite uses TEXT for timestamps but supports datetime() function
|
|
872
|
+
return 'TEXT';
|
|
873
|
+
case 'mssql':
|
|
874
|
+
case 'sqlserver':
|
|
875
|
+
return `DATETIME2${precisionStr}`;
|
|
876
|
+
default:
|
|
877
|
+
return 'DATETIME';
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
exports.NOW = NOW;
|
|
882
|
+
// JSON types with dialect-specific handling
|
|
883
|
+
/**
|
|
884
|
+
* JSON - standard JSON (text-based)
|
|
885
|
+
* - PostgreSQL: native JSON type
|
|
886
|
+
* - MySQL/MariaDB: native JSON type
|
|
887
|
+
* - SQLite: TEXT with JSON handling
|
|
888
|
+
*
|
|
889
|
+
* @example
|
|
890
|
+
* // Use native JSON where supported
|
|
891
|
+
* metadata: DataTypes.JSON(true)
|
|
892
|
+
* // Use TEXT fallback (useful for SQLite compatibility)
|
|
893
|
+
* settings: DataTypes.JSON(false) // or DataTypes.JSON()
|
|
894
|
+
*/
|
|
895
|
+
class JSON extends AbstractDataType {
|
|
896
|
+
constructor(useNative = false) {
|
|
897
|
+
super();
|
|
898
|
+
this.key = 'JSON';
|
|
899
|
+
this.useNative = useNative;
|
|
900
|
+
}
|
|
901
|
+
toSqlString(dialect) {
|
|
902
|
+
// If useNative is false, always use TEXT
|
|
903
|
+
if (!this.useNative) {
|
|
904
|
+
return 'TEXT';
|
|
905
|
+
}
|
|
906
|
+
switch (dialect) {
|
|
907
|
+
case 'postgres':
|
|
908
|
+
case 'mysql':
|
|
909
|
+
case 'mariadb':
|
|
910
|
+
return 'JSON';
|
|
911
|
+
case 'sqlite':
|
|
912
|
+
default:
|
|
913
|
+
return 'TEXT';
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
exports.JSON = JSON;
|
|
918
|
+
/**
|
|
919
|
+
* JSONB - binary JSON (PostgreSQL native)
|
|
920
|
+
* - PostgreSQL: native JSONB type (binary format, indexed)
|
|
921
|
+
* - MySQL/MariaDB: TEXT with JSON handling (no native JSONB)
|
|
922
|
+
* - SQLite: TEXT with JSON handling
|
|
923
|
+
*
|
|
924
|
+
* Benefits of JSONB in PostgreSQL:
|
|
925
|
+
* - Binary storage format (faster parsing)
|
|
926
|
+
* - Supports indexing with GIN
|
|
927
|
+
* - Key existence operators (? &?| etc.)
|
|
928
|
+
*
|
|
929
|
+
* @example
|
|
930
|
+
* // Use native JSONB for PostgreSQL, TEXT for others
|
|
931
|
+
* settings: DataTypes.JSONB()
|
|
932
|
+
* // or DataTypes.JSONB(true)
|
|
933
|
+
*
|
|
934
|
+
* // Always use TEXT (useful when JSONB features not needed)
|
|
935
|
+
* metadata: DataTypes.JSONB(false)
|
|
936
|
+
*/
|
|
937
|
+
class JSONB extends AbstractDataType {
|
|
938
|
+
constructor(useNative = false) {
|
|
939
|
+
super();
|
|
940
|
+
this.key = 'JSONB';
|
|
941
|
+
this.useNative = useNative;
|
|
942
|
+
}
|
|
943
|
+
toSqlString(dialect) {
|
|
944
|
+
// If useNative is false, always use TEXT
|
|
945
|
+
if (!this.useNative) {
|
|
946
|
+
return 'TEXT';
|
|
947
|
+
}
|
|
948
|
+
switch (dialect) {
|
|
949
|
+
case 'postgres':
|
|
950
|
+
// PostgreSQL has native JSONB support
|
|
951
|
+
return 'JSONB';
|
|
952
|
+
case 'mysql':
|
|
953
|
+
case 'mariadb':
|
|
954
|
+
// MySQL/MariaDB: No native JSONB, use JSON type (TEXT fallback)
|
|
955
|
+
return 'JSON';
|
|
956
|
+
case 'sqlite':
|
|
957
|
+
default:
|
|
958
|
+
// SQLite: No native JSON/JSONB support
|
|
959
|
+
return 'TEXT';
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
exports.JSONB = JSONB;
|
|
964
|
+
// HSTORE - PostgreSQL key-value type
|
|
965
|
+
// Requires: CREATE EXTENSION IF NOT EXISTS hstore
|
|
966
|
+
class HSTORE extends AbstractDataType {
|
|
967
|
+
constructor(useNative = true) {
|
|
968
|
+
super();
|
|
969
|
+
this.key = 'HSTORE';
|
|
970
|
+
this.useNative = useNative;
|
|
971
|
+
}
|
|
972
|
+
toSqlString(dialect) {
|
|
973
|
+
if (!this.useNative) {
|
|
974
|
+
// Fallback to JSONB for dialects without HStore support
|
|
975
|
+
return 'JSONB';
|
|
976
|
+
}
|
|
977
|
+
switch (dialect) {
|
|
978
|
+
case 'postgres':
|
|
979
|
+
return 'HSTORE';
|
|
980
|
+
case 'mysql':
|
|
981
|
+
case 'mariadb':
|
|
982
|
+
case 'sqlite':
|
|
983
|
+
default:
|
|
984
|
+
// No native HStore support, fallback to JSONB
|
|
985
|
+
return 'JSONB';
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
/**
|
|
989
|
+
* Get the SQL to create the HStore extension (PostgreSQL)
|
|
990
|
+
*/
|
|
991
|
+
static getExtensionSQL() {
|
|
992
|
+
return 'CREATE EXTENSION IF NOT EXISTS hstore';
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
exports.HSTORE = HSTORE;
|
|
996
|
+
// RANGE - PostgreSQL range types
|
|
997
|
+
// Range types: int4range, int8range, numrange, tsrange, tstzrange, daterange
|
|
998
|
+
class RANGE extends AbstractDataType {
|
|
999
|
+
constructor(subtype = 'int4range') {
|
|
1000
|
+
super();
|
|
1001
|
+
this.key = 'RANGE';
|
|
1002
|
+
this.subtype = subtype;
|
|
1003
|
+
}
|
|
1004
|
+
toSqlString(dialect) {
|
|
1005
|
+
switch (dialect) {
|
|
1006
|
+
case 'postgres':
|
|
1007
|
+
return this.subtype;
|
|
1008
|
+
case 'mysql':
|
|
1009
|
+
case 'mariadb':
|
|
1010
|
+
case 'sqlite':
|
|
1011
|
+
default:
|
|
1012
|
+
// Range types not supported, use VARCHAR as fallback
|
|
1013
|
+
return 'VARCHAR(255)';
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
exports.RANGE = RANGE;
|
|
1018
|
+
// INET - PostgreSQL IP address type
|
|
1019
|
+
//
|
|
1020
|
+
// PostgreSQL's own `INET` column stores either an IPv4 or IPv6 address (and
|
|
1021
|
+
// doesn't need to know which up front), so `version` only matters for
|
|
1022
|
+
// dialects - like ClickHouse - that have genuinely distinct fixed-width
|
|
1023
|
+
// IPv4/IPv6 column types (`IPv4` vs `IPv6`) rather than one type that holds
|
|
1024
|
+
// either. Defaults to `4` to preserve the previous unconditional `VARCHAR(45)`
|
|
1025
|
+
// /`IPv4`-shaped behavior for existing callers that don't pass a version.
|
|
1026
|
+
class INET extends AbstractDataType {
|
|
1027
|
+
constructor(options) {
|
|
1028
|
+
super();
|
|
1029
|
+
this.key = 'INET';
|
|
1030
|
+
const version = typeof options === 'number' ? options : options?.version;
|
|
1031
|
+
this.version = version === 6 ? 6 : 4;
|
|
1032
|
+
}
|
|
1033
|
+
toSqlString(dialect) {
|
|
1034
|
+
switch (dialect) {
|
|
1035
|
+
case 'postgres':
|
|
1036
|
+
return 'INET';
|
|
1037
|
+
case 'mysql':
|
|
1038
|
+
case 'mariadb':
|
|
1039
|
+
// MySQL/MariaDB: No INET type, use VARCHAR
|
|
1040
|
+
return 'VARCHAR(45)';
|
|
1041
|
+
case 'sqlite':
|
|
1042
|
+
// SQLite: No INET type, use TEXT
|
|
1043
|
+
return 'TEXT';
|
|
1044
|
+
default:
|
|
1045
|
+
return 'VARCHAR(45)';
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
exports.INET = INET;
|
|
1050
|
+
// CIDR - PostgreSQL network address type
|
|
1051
|
+
class CIDR extends AbstractDataType {
|
|
1052
|
+
constructor() {
|
|
1053
|
+
super(...arguments);
|
|
1054
|
+
this.key = 'CIDR';
|
|
1055
|
+
}
|
|
1056
|
+
toSqlString(dialect) {
|
|
1057
|
+
switch (dialect) {
|
|
1058
|
+
case 'postgres':
|
|
1059
|
+
return 'CIDR';
|
|
1060
|
+
case 'mysql':
|
|
1061
|
+
case 'mariadb':
|
|
1062
|
+
// MySQL/MariaDB: No CIDR type, use VARCHAR
|
|
1063
|
+
return 'VARCHAR(45)';
|
|
1064
|
+
case 'sqlite':
|
|
1065
|
+
// SQLite: No CIDR type, use TEXT
|
|
1066
|
+
return 'TEXT';
|
|
1067
|
+
default:
|
|
1068
|
+
return 'VARCHAR(45)';
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
exports.CIDR = CIDR;
|
|
1073
|
+
// MACADDR - PostgreSQL MAC address type
|
|
1074
|
+
class MACADDR extends AbstractDataType {
|
|
1075
|
+
constructor() {
|
|
1076
|
+
super(...arguments);
|
|
1077
|
+
this.key = 'MACADDR';
|
|
1078
|
+
}
|
|
1079
|
+
toSqlString(dialect) {
|
|
1080
|
+
switch (dialect) {
|
|
1081
|
+
case 'postgres':
|
|
1082
|
+
return 'MACADDR';
|
|
1083
|
+
case 'mysql':
|
|
1084
|
+
case 'mariadb':
|
|
1085
|
+
// MySQL/MariaDB: No MACADDR type, use VARCHAR
|
|
1086
|
+
return 'VARCHAR(17)';
|
|
1087
|
+
case 'sqlite':
|
|
1088
|
+
// SQLite: No MACADDR type, use TEXT
|
|
1089
|
+
return 'TEXT';
|
|
1090
|
+
default:
|
|
1091
|
+
return 'VARCHAR(17)';
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
exports.MACADDR = MACADDR;
|
|
1096
|
+
// BINARY - fixed-length binary data
|
|
1097
|
+
class BINARY extends AbstractDataType {
|
|
1098
|
+
constructor(length = 1) {
|
|
1099
|
+
super();
|
|
1100
|
+
this.key = 'BINARY';
|
|
1101
|
+
this.length = length;
|
|
1102
|
+
}
|
|
1103
|
+
toSqlString(dialect) {
|
|
1104
|
+
// MySQL/MariaDB use BINARY
|
|
1105
|
+
if (dialect === 'mysql' || dialect === 'mariadb') {
|
|
1106
|
+
return `BINARY(${this.length})`;
|
|
1107
|
+
}
|
|
1108
|
+
// SQLite uses BLOB for binary data
|
|
1109
|
+
return `BLOB`;
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
exports.BINARY = BINARY;
|
|
1113
|
+
// VARBINARY - variable-length binary data
|
|
1114
|
+
class VARBINARY extends AbstractDataType {
|
|
1115
|
+
constructor(length = 255) {
|
|
1116
|
+
super();
|
|
1117
|
+
this.key = 'VARBINARY';
|
|
1118
|
+
this.length = length;
|
|
1119
|
+
}
|
|
1120
|
+
toSqlString(dialect) {
|
|
1121
|
+
// MySQL/MariaDB use VARBINARY
|
|
1122
|
+
if (dialect === 'mysql' || dialect === 'mariadb') {
|
|
1123
|
+
return `VARBINARY(${this.length})`;
|
|
1124
|
+
}
|
|
1125
|
+
// SQLite uses BLOB for binary data
|
|
1126
|
+
return `BLOB`;
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
exports.VARBINARY = VARBINARY;
|
|
1130
|
+
// BLOB types - binary data storage with dialect-specific handling
|
|
1131
|
+
class BLOB extends AbstractDataType {
|
|
1132
|
+
constructor(length) {
|
|
1133
|
+
super();
|
|
1134
|
+
this.key = 'BLOB';
|
|
1135
|
+
this.length = length;
|
|
1136
|
+
}
|
|
1137
|
+
/**
|
|
1138
|
+
* Get the BLOB type string based on length variant
|
|
1139
|
+
* MySQL/MariaDB format: TINYBLOB, BLOB, MEDIUMBLOB, LONGBLOB
|
|
1140
|
+
*/
|
|
1141
|
+
getBlobType() {
|
|
1142
|
+
if (!this.length) {
|
|
1143
|
+
return 'BLOB';
|
|
1144
|
+
}
|
|
1145
|
+
// MySQL/MariaDB format: TINYBLOB, MEDIUMBLOB, LONGBLOB
|
|
1146
|
+
if (this.length === 'tiny')
|
|
1147
|
+
return 'TINYBLOB';
|
|
1148
|
+
if (this.length === 'medium')
|
|
1149
|
+
return 'MEDIUMBLOB';
|
|
1150
|
+
if (this.length === 'long')
|
|
1151
|
+
return 'LONGBLOB';
|
|
1152
|
+
return 'BLOB';
|
|
1153
|
+
}
|
|
1154
|
+
toSqlString(dialect) {
|
|
1155
|
+
switch (dialect) {
|
|
1156
|
+
case 'postgres':
|
|
1157
|
+
// PostgreSQL uses BYTEA for binary data
|
|
1158
|
+
return 'BYTEA';
|
|
1159
|
+
case 'mysql':
|
|
1160
|
+
case 'mariadb':
|
|
1161
|
+
// MySQL/MariaDB support TINYBLOB, BLOB, MEDIUMBLOB, LONGBLOB
|
|
1162
|
+
return this.getBlobType();
|
|
1163
|
+
case 'sqlite':
|
|
1164
|
+
// SQLite uses BLOB for all binary data
|
|
1165
|
+
return 'BLOB';
|
|
1166
|
+
case 'mssql':
|
|
1167
|
+
case 'sqlserver':
|
|
1168
|
+
// SQL Server uses VARBINARY(MAX) for binary data
|
|
1169
|
+
return 'VARBINARY(MAX)';
|
|
1170
|
+
default:
|
|
1171
|
+
// Default to standard BLOB
|
|
1172
|
+
return this.getBlobType();
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
exports.BLOB = BLOB;
|
|
1177
|
+
// Convenience classes for specific BLOB types
|
|
1178
|
+
class TINYBLOB extends AbstractDataType {
|
|
1179
|
+
constructor() {
|
|
1180
|
+
super(...arguments);
|
|
1181
|
+
this.key = 'TINYBLOB';
|
|
1182
|
+
}
|
|
1183
|
+
toSqlString(dialect) {
|
|
1184
|
+
switch (dialect) {
|
|
1185
|
+
case 'postgres':
|
|
1186
|
+
return 'BYTEA';
|
|
1187
|
+
case 'mysql':
|
|
1188
|
+
case 'mariadb':
|
|
1189
|
+
return 'TINYBLOB';
|
|
1190
|
+
case 'sqlite':
|
|
1191
|
+
case 'mssql':
|
|
1192
|
+
case 'sqlserver':
|
|
1193
|
+
return 'BLOB';
|
|
1194
|
+
default:
|
|
1195
|
+
return 'TINYBLOB';
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
exports.TINYBLOB = TINYBLOB;
|
|
1200
|
+
class MEDIUMBLOB extends AbstractDataType {
|
|
1201
|
+
constructor() {
|
|
1202
|
+
super(...arguments);
|
|
1203
|
+
this.key = 'MEDIUMBLOB';
|
|
1204
|
+
}
|
|
1205
|
+
toSqlString(dialect) {
|
|
1206
|
+
switch (dialect) {
|
|
1207
|
+
case 'postgres':
|
|
1208
|
+
return 'BYTEA';
|
|
1209
|
+
case 'mysql':
|
|
1210
|
+
case 'mariadb':
|
|
1211
|
+
return 'MEDIUMBLOB';
|
|
1212
|
+
case 'sqlite':
|
|
1213
|
+
case 'mssql':
|
|
1214
|
+
case 'sqlserver':
|
|
1215
|
+
return 'VARBINARY(MAX)';
|
|
1216
|
+
default:
|
|
1217
|
+
return 'MEDIUMBLOB';
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
exports.MEDIUMBLOB = MEDIUMBLOB;
|
|
1222
|
+
class LONGBLOB extends AbstractDataType {
|
|
1223
|
+
constructor() {
|
|
1224
|
+
super(...arguments);
|
|
1225
|
+
this.key = 'LONGBLOB';
|
|
1226
|
+
}
|
|
1227
|
+
toSqlString(dialect) {
|
|
1228
|
+
switch (dialect) {
|
|
1229
|
+
case 'postgres':
|
|
1230
|
+
return 'BYTEA';
|
|
1231
|
+
case 'mysql':
|
|
1232
|
+
case 'mariadb':
|
|
1233
|
+
return 'LONGBLOB';
|
|
1234
|
+
case 'sqlite':
|
|
1235
|
+
case 'mssql':
|
|
1236
|
+
case 'sqlserver':
|
|
1237
|
+
return 'VARBINARY(MAX)';
|
|
1238
|
+
default:
|
|
1239
|
+
return 'LONGBLOB';
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
exports.LONGBLOB = LONGBLOB;
|
|
1244
|
+
// ENUM
|
|
1245
|
+
class ENUM extends AbstractDataType {
|
|
1246
|
+
/**
|
|
1247
|
+
* Create an ENUM data type
|
|
1248
|
+
* @param values - Either an array of values or individual string values
|
|
1249
|
+
* @example
|
|
1250
|
+
* // Array of values
|
|
1251
|
+
* DataTypes.ENUM(['active', 'inactive', 'pending'])
|
|
1252
|
+
* // Individual values
|
|
1253
|
+
* DataTypes.ENUM('active', 'inactive', 'pending')
|
|
1254
|
+
*/
|
|
1255
|
+
constructor(...values) {
|
|
1256
|
+
super();
|
|
1257
|
+
this.key = 'ENUM';
|
|
1258
|
+
// Handle both array and spread arguments
|
|
1259
|
+
if (values.length === 1 && Array.isArray(values[0])) {
|
|
1260
|
+
this.values = values[0];
|
|
1261
|
+
}
|
|
1262
|
+
else {
|
|
1263
|
+
this.values = values;
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
/**
|
|
1267
|
+
* Set a name for the enum type (useful for PostgreSQL/MySQL)
|
|
1268
|
+
*/
|
|
1269
|
+
setName(name) {
|
|
1270
|
+
this.name = name;
|
|
1271
|
+
return this;
|
|
1272
|
+
}
|
|
1273
|
+
toSqlString(dialect) {
|
|
1274
|
+
const valuesStr = this.values.map((v) => `'${v}'`).join(', ');
|
|
1275
|
+
switch (dialect) {
|
|
1276
|
+
case 'postgres':
|
|
1277
|
+
// PostgreSQL supports native ENUM type
|
|
1278
|
+
if (this.name) {
|
|
1279
|
+
return `VARCHAR(255)`; // Will be created as ENUM type separately
|
|
1280
|
+
}
|
|
1281
|
+
return `VARCHAR(255)`;
|
|
1282
|
+
case 'mysql':
|
|
1283
|
+
case 'mariadb':
|
|
1284
|
+
// MySQL/MariaDB support native ENUM type
|
|
1285
|
+
return `ENUM(${valuesStr})`;
|
|
1286
|
+
case 'sqlite':
|
|
1287
|
+
default:
|
|
1288
|
+
// SQLite uses TEXT with validation
|
|
1289
|
+
return 'TEXT';
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
/**
|
|
1293
|
+
* Get the values for validation
|
|
1294
|
+
*/
|
|
1295
|
+
getValues() {
|
|
1296
|
+
return [...this.values];
|
|
1297
|
+
}
|
|
1298
|
+
/**
|
|
1299
|
+
* Validate if a value is valid for this ENUM
|
|
1300
|
+
*/
|
|
1301
|
+
validate(value) {
|
|
1302
|
+
return this.values.includes(value);
|
|
1303
|
+
}
|
|
1304
|
+
/**
|
|
1305
|
+
* Generate an ALTER TABLE statement to add/modify ENUM column
|
|
1306
|
+
* Note: MySQL uses MODIFY COLUMN, PostgreSQL needs type recreation
|
|
1307
|
+
*/
|
|
1308
|
+
toAlterTableSql(dialect, tableName, columnName, _columnDefinition) {
|
|
1309
|
+
const valuesStr = this.values.map((v) => `'${v}'`).join(', ');
|
|
1310
|
+
switch (dialect) {
|
|
1311
|
+
case 'mysql':
|
|
1312
|
+
case 'mariadb':
|
|
1313
|
+
return `ALTER TABLE \`${tableName}\` MODIFY COLUMN \`${columnName}\` ENUM(${valuesStr})`;
|
|
1314
|
+
case 'postgres': {
|
|
1315
|
+
// PostgreSQL requires creating the type first, then altering the column
|
|
1316
|
+
const typeName = this.name || `${tableName}_${columnName}_type`;
|
|
1317
|
+
return `-- PostgreSQL requires manual type creation:
|
|
1318
|
+
DROP TYPE IF EXISTS ${typeName};
|
|
1319
|
+
CREATE TYPE ${typeName} AS ENUM (${valuesStr});
|
|
1320
|
+
ALTER TABLE ${tableName} ALTER COLUMN ${columnName} TYPE ${typeName};
|
|
1321
|
+
ALTER TABLE ${tableName} ALTER COLUMN ${columnName} SET DEFAULT '${this.values[0]}';`;
|
|
1322
|
+
}
|
|
1323
|
+
default:
|
|
1324
|
+
return `-- ENUM not supported for ${dialect}, using TEXT`;
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
exports.ENUM = ENUM;
|
|
1329
|
+
// ARRAY - PostgreSQL native arrays with fallback to JSON/TEXT for other dialects
|
|
1330
|
+
class ARRAY extends AbstractDataType {
|
|
1331
|
+
/**
|
|
1332
|
+
* Create an ARRAY data type
|
|
1333
|
+
* @param type - The data type of array elements
|
|
1334
|
+
* @example
|
|
1335
|
+
* // Array of strings
|
|
1336
|
+
* tags: DataTypes.ARRAY(DataTypes.STRING)
|
|
1337
|
+
* // Array of integers
|
|
1338
|
+
* numbers: DataTypes.ARRAY(DataTypes.INTEGER)
|
|
1339
|
+
* // Array of floats
|
|
1340
|
+
* prices: DataTypes.ARRAY(DataTypes.FLOAT)
|
|
1341
|
+
*/
|
|
1342
|
+
constructor(type) {
|
|
1343
|
+
super();
|
|
1344
|
+
this.key = 'ARRAY';
|
|
1345
|
+
this.type = type;
|
|
1346
|
+
}
|
|
1347
|
+
/**
|
|
1348
|
+
* Get the SQL string representation based on the dialect
|
|
1349
|
+
* PostgreSQL: Uses native array syntax (e.g., TEXT[], INTEGER[])
|
|
1350
|
+
* Other dialects: Falls back to JSON or TEXT
|
|
1351
|
+
*/
|
|
1352
|
+
toSqlString(dialect) {
|
|
1353
|
+
// Get the base type for the element, passing the dialect through so nested
|
|
1354
|
+
// types (e.g. STRING(50), DECIMAL(10,2)) resolve correctly per-dialect
|
|
1355
|
+
const elementType = this.type.toSqlString(dialect);
|
|
1356
|
+
switch (dialect) {
|
|
1357
|
+
case 'postgres':
|
|
1358
|
+
// PostgreSQL supports native arrays with element type + []
|
|
1359
|
+
return `${elementType}[]`;
|
|
1360
|
+
case 'mysql':
|
|
1361
|
+
case 'mariadb':
|
|
1362
|
+
// MySQL/MariaDB: Use JSON type for arrays
|
|
1363
|
+
return 'JSON';
|
|
1364
|
+
case 'sqlite':
|
|
1365
|
+
case 'mssql':
|
|
1366
|
+
case 'sqlserver':
|
|
1367
|
+
default:
|
|
1368
|
+
// SQLite and SQL Server: Store as TEXT (JSON serialized)
|
|
1369
|
+
return 'TEXT';
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
/**
|
|
1373
|
+
* Get the element type
|
|
1374
|
+
*/
|
|
1375
|
+
getElementType() {
|
|
1376
|
+
return this.type;
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
exports.ARRAY = ARRAY;
|
|
1380
|
+
// LIST - DuckDB native variable-length list type, with fallback to JSON/TEXT
|
|
1381
|
+
// for dialects without a composite list type. Distinct from ARRAY: ARRAY is
|
|
1382
|
+
// modeled on PostgreSQL's fixed-element-type array (and mainly documents
|
|
1383
|
+
// PostgreSQL-native `[]` syntax with generic fallbacks), whereas LIST maps
|
|
1384
|
+
// onto DuckDB's `<type>[]` LIST columns specifically and is the type callers
|
|
1385
|
+
// should reach for when targeting DuckDB's composite type system.
|
|
1386
|
+
class LIST extends AbstractDataType {
|
|
1387
|
+
/**
|
|
1388
|
+
* Create a LIST data type
|
|
1389
|
+
* @param type - The data type of list elements
|
|
1390
|
+
* @example
|
|
1391
|
+
* // List of integers (DuckDB: INTEGER[])
|
|
1392
|
+
* tags: DataTypes.LIST(DataTypes.INTEGER)
|
|
1393
|
+
* // Nested list (DuckDB: VARCHAR[][])
|
|
1394
|
+
* matrix: DataTypes.LIST(DataTypes.LIST(DataTypes.VARCHAR))
|
|
1395
|
+
*/
|
|
1396
|
+
constructor(type) {
|
|
1397
|
+
super();
|
|
1398
|
+
this.key = 'LIST';
|
|
1399
|
+
this.type = type;
|
|
1400
|
+
}
|
|
1401
|
+
/**
|
|
1402
|
+
* Get the SQL string representation based on the dialect
|
|
1403
|
+
* DuckDB/PostgreSQL: native `elementType[]` syntax
|
|
1404
|
+
* Other dialects: falls back to JSON or TEXT
|
|
1405
|
+
*/
|
|
1406
|
+
toSqlString(dialect) {
|
|
1407
|
+
const elementType = this.type.toSqlString(dialect);
|
|
1408
|
+
switch (dialect) {
|
|
1409
|
+
case 'duckdb':
|
|
1410
|
+
case 'postgres':
|
|
1411
|
+
return `${elementType}[]`;
|
|
1412
|
+
case 'mysql':
|
|
1413
|
+
case 'mariadb':
|
|
1414
|
+
return 'JSON';
|
|
1415
|
+
case 'sqlite':
|
|
1416
|
+
case 'mssql':
|
|
1417
|
+
case 'sqlserver':
|
|
1418
|
+
default:
|
|
1419
|
+
return 'TEXT';
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
/**
|
|
1423
|
+
* Get the element type
|
|
1424
|
+
*/
|
|
1425
|
+
getElementType() {
|
|
1426
|
+
return this.type;
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
exports.LIST = LIST;
|
|
1430
|
+
// STRUCT - DuckDB native nested record type (named fields with heterogeneous
|
|
1431
|
+
// types), with fallback to JSON/TEXT for dialects without a composite struct type.
|
|
1432
|
+
class STRUCT extends AbstractDataType {
|
|
1433
|
+
/**
|
|
1434
|
+
* Create a STRUCT data type
|
|
1435
|
+
* @param fields - A map of field name -> field data type
|
|
1436
|
+
* @example
|
|
1437
|
+
* // DuckDB: STRUCT(x INTEGER, y INTEGER)
|
|
1438
|
+
* point: DataTypes.STRUCT({ x: DataTypes.INTEGER, y: DataTypes.INTEGER })
|
|
1439
|
+
*/
|
|
1440
|
+
constructor(fields) {
|
|
1441
|
+
super();
|
|
1442
|
+
this.key = 'STRUCT';
|
|
1443
|
+
this.fields = fields;
|
|
1444
|
+
}
|
|
1445
|
+
/**
|
|
1446
|
+
* Get the SQL string representation based on the dialect
|
|
1447
|
+
* DuckDB: native `STRUCT(field TYPE, ...)` syntax
|
|
1448
|
+
* Other dialects: falls back to JSON or TEXT
|
|
1449
|
+
*/
|
|
1450
|
+
toSqlString(dialect) {
|
|
1451
|
+
switch (dialect) {
|
|
1452
|
+
case 'duckdb': {
|
|
1453
|
+
const parts = Object.entries(this.fields).map(([name, type]) => `${name} ${type.toSqlString(dialect)}`);
|
|
1454
|
+
return `STRUCT(${parts.join(', ')})`;
|
|
1455
|
+
}
|
|
1456
|
+
case 'mysql':
|
|
1457
|
+
case 'mariadb':
|
|
1458
|
+
return 'JSON';
|
|
1459
|
+
case 'postgres':
|
|
1460
|
+
case 'sqlite':
|
|
1461
|
+
case 'mssql':
|
|
1462
|
+
case 'sqlserver':
|
|
1463
|
+
default:
|
|
1464
|
+
return 'TEXT';
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
/**
|
|
1468
|
+
* Get the struct's fields
|
|
1469
|
+
*/
|
|
1470
|
+
getFields() {
|
|
1471
|
+
return this.fields;
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
exports.STRUCT = STRUCT;
|
|
1475
|
+
// MAP - DuckDB native key/value map type (homogeneous key type, homogeneous
|
|
1476
|
+
// value type, unlike STRUCT), with fallback to JSON/TEXT for other dialects.
|
|
1477
|
+
class MAP extends AbstractDataType {
|
|
1478
|
+
/**
|
|
1479
|
+
* Create a MAP data type
|
|
1480
|
+
* @param keyType - The data type of map keys
|
|
1481
|
+
* @param valueType - The data type of map values
|
|
1482
|
+
* @example
|
|
1483
|
+
* // DuckDB: MAP(VARCHAR, INTEGER)
|
|
1484
|
+
* scores: DataTypes.MAP(DataTypes.STRING, DataTypes.INTEGER)
|
|
1485
|
+
*/
|
|
1486
|
+
constructor(keyType, valueType) {
|
|
1487
|
+
super();
|
|
1488
|
+
this.key = 'MAP';
|
|
1489
|
+
this.keyType = keyType;
|
|
1490
|
+
this.valueType = valueType;
|
|
1491
|
+
}
|
|
1492
|
+
/**
|
|
1493
|
+
* Get the SQL string representation based on the dialect
|
|
1494
|
+
* DuckDB: native `MAP(keyType, valueType)` syntax
|
|
1495
|
+
* Other dialects: falls back to JSON or TEXT
|
|
1496
|
+
*/
|
|
1497
|
+
toSqlString(dialect) {
|
|
1498
|
+
switch (dialect) {
|
|
1499
|
+
case 'duckdb':
|
|
1500
|
+
return `MAP(${this.keyType.toSqlString(dialect)}, ${this.valueType.toSqlString(dialect)})`;
|
|
1501
|
+
case 'mysql':
|
|
1502
|
+
case 'mariadb':
|
|
1503
|
+
return 'JSON';
|
|
1504
|
+
case 'postgres':
|
|
1505
|
+
case 'sqlite':
|
|
1506
|
+
case 'mssql':
|
|
1507
|
+
case 'sqlserver':
|
|
1508
|
+
default:
|
|
1509
|
+
return 'TEXT';
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
/**
|
|
1513
|
+
* Get the map's key type
|
|
1514
|
+
*/
|
|
1515
|
+
getKeyType() {
|
|
1516
|
+
return this.keyType;
|
|
1517
|
+
}
|
|
1518
|
+
/**
|
|
1519
|
+
* Get the map's value type
|
|
1520
|
+
*/
|
|
1521
|
+
getValueType() {
|
|
1522
|
+
return this.valueType;
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
exports.MAP = MAP;
|
|
1526
|
+
// UNION - DuckDB native tagged-union type (exactly one of several named
|
|
1527
|
+
// alternative types is active at a time), with fallback to JSON/TEXT for
|
|
1528
|
+
// other dialects. Not to be confused with the SQL `UNION` query operator.
|
|
1529
|
+
class DUCKDB_UNION extends AbstractDataType {
|
|
1530
|
+
/**
|
|
1531
|
+
* Create a UNION data type
|
|
1532
|
+
* @param fields - A map of tag name -> alternative data type
|
|
1533
|
+
* @example
|
|
1534
|
+
* // DuckDB: UNION(num INTEGER, str VARCHAR)
|
|
1535
|
+
* value: DataTypes.UNION({ num: DataTypes.INTEGER, str: DataTypes.STRING })
|
|
1536
|
+
*/
|
|
1537
|
+
constructor(fields) {
|
|
1538
|
+
super();
|
|
1539
|
+
this.key = 'UNION';
|
|
1540
|
+
this.fields = fields;
|
|
1541
|
+
}
|
|
1542
|
+
/**
|
|
1543
|
+
* Get the SQL string representation based on the dialect
|
|
1544
|
+
* DuckDB: native `UNION(tag TYPE, ...)` syntax
|
|
1545
|
+
* Other dialects: falls back to JSON or TEXT
|
|
1546
|
+
*/
|
|
1547
|
+
toSqlString(dialect) {
|
|
1548
|
+
switch (dialect) {
|
|
1549
|
+
case 'duckdb': {
|
|
1550
|
+
const parts = Object.entries(this.fields).map(([tag, type]) => `${tag} ${type.toSqlString(dialect)}`);
|
|
1551
|
+
return `UNION(${parts.join(', ')})`;
|
|
1552
|
+
}
|
|
1553
|
+
case 'mysql':
|
|
1554
|
+
case 'mariadb':
|
|
1555
|
+
return 'JSON';
|
|
1556
|
+
case 'postgres':
|
|
1557
|
+
case 'sqlite':
|
|
1558
|
+
case 'mssql':
|
|
1559
|
+
case 'sqlserver':
|
|
1560
|
+
default:
|
|
1561
|
+
return 'TEXT';
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
/**
|
|
1565
|
+
* Get the union's member fields
|
|
1566
|
+
*/
|
|
1567
|
+
getFields() {
|
|
1568
|
+
return this.fields;
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
exports.DUCKDB_UNION = DUCKDB_UNION;
|
|
1572
|
+
/**
|
|
1573
|
+
* Geometry - for spatial/geometric data
|
|
1574
|
+
* Supports optional geometry type and SRID (Spatial Reference System Identifier)
|
|
1575
|
+
*
|
|
1576
|
+
* @example
|
|
1577
|
+
* // Basic geometry (stored as JSON/text)
|
|
1578
|
+
* location: DataTypes.GEOMETRY
|
|
1579
|
+
*
|
|
1580
|
+
* // Geometry with specific type
|
|
1581
|
+
* point: DataTypes.GEOMETRY('POINT')
|
|
1582
|
+
* line: DataTypes.GEOMETRY('LINESTRING')
|
|
1583
|
+
* area: DataTypes.GEOMETRY('POLYGON')
|
|
1584
|
+
*
|
|
1585
|
+
* // Geometry with type and SRID (coordinate system)
|
|
1586
|
+
* geoPoint: DataTypes.GEOMETRY('POINT', 4326)
|
|
1587
|
+
*/
|
|
1588
|
+
class GEOMETRY extends AbstractDataType {
|
|
1589
|
+
constructor(typeOrOptions, srid) {
|
|
1590
|
+
super();
|
|
1591
|
+
this.key = 'GEOMETRY';
|
|
1592
|
+
if (typeof typeOrOptions === 'object' && typeOrOptions !== null) {
|
|
1593
|
+
// Called with options object: GEOMETRY({ type: 'POINT', srid: 4326 })
|
|
1594
|
+
this.type = typeOrOptions.type;
|
|
1595
|
+
this.srid = typeOrOptions.srid;
|
|
1596
|
+
}
|
|
1597
|
+
else {
|
|
1598
|
+
// Called with positional args: GEOMETRY('POINT', 4326)
|
|
1599
|
+
this.type = typeOrOptions;
|
|
1600
|
+
this.srid = srid;
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
/**
|
|
1604
|
+
* Get the geometry type in uppercase
|
|
1605
|
+
*/
|
|
1606
|
+
getGeometryType() {
|
|
1607
|
+
return this.type?.toUpperCase();
|
|
1608
|
+
}
|
|
1609
|
+
toSqlString(dialect) {
|
|
1610
|
+
const typeStr = this.type ? this.type.toUpperCase() : '';
|
|
1611
|
+
const sridStr = this.srid ? `, ${this.srid}` : '';
|
|
1612
|
+
switch (dialect) {
|
|
1613
|
+
case 'postgres':
|
|
1614
|
+
// PostgreSQL with PostGIS extension
|
|
1615
|
+
if (typeStr && sridStr) {
|
|
1616
|
+
return `GEOMETRY(${typeStr}${sridStr})`;
|
|
1617
|
+
}
|
|
1618
|
+
else if (typeStr) {
|
|
1619
|
+
return `GEOMETRY(${typeStr})`;
|
|
1620
|
+
}
|
|
1621
|
+
return 'GEOMETRY';
|
|
1622
|
+
case 'mysql':
|
|
1623
|
+
case 'mariadb':
|
|
1624
|
+
// MySQL/MariaDB spatial types
|
|
1625
|
+
if (typeStr && sridStr) {
|
|
1626
|
+
return `${typeStr}${sridStr}`;
|
|
1627
|
+
}
|
|
1628
|
+
else if (typeStr) {
|
|
1629
|
+
return typeStr;
|
|
1630
|
+
}
|
|
1631
|
+
return 'GEOMETRY';
|
|
1632
|
+
case 'mssql':
|
|
1633
|
+
case 'sqlserver':
|
|
1634
|
+
// SQL Server uses geography/geometry types
|
|
1635
|
+
if (typeStr) {
|
|
1636
|
+
return `geometry`;
|
|
1637
|
+
}
|
|
1638
|
+
return 'geometry';
|
|
1639
|
+
case 'sqlite':
|
|
1640
|
+
default:
|
|
1641
|
+
// SQLite stores spatial data as BLOB (GeoJSON or WKB)
|
|
1642
|
+
return 'BLOB';
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
exports.GEOMETRY = GEOMETRY;
|
|
1647
|
+
/**
|
|
1648
|
+
* Geography - for geographic/spatial data (uses WGS84 coordinate system)
|
|
1649
|
+
* Unlike GEOMETRY, GEOGRAPHY performs calculations using spherical geography
|
|
1650
|
+
*
|
|
1651
|
+
* @example
|
|
1652
|
+
* // Basic geography (defaults to WGS84 - SRID 4326)
|
|
1653
|
+
* location: DataTypes.GEOGRAPHY
|
|
1654
|
+
*
|
|
1655
|
+
* // Geography with specific type
|
|
1656
|
+
* point: DataTypes.GEOGRAPHY('POINT')
|
|
1657
|
+
* area: DataTypes.GEOGRAPHY('POLYGON', 4326)
|
|
1658
|
+
*
|
|
1659
|
+
* // Geography with type and custom SRID
|
|
1660
|
+
* // 4326 = WGS 84 (most common)
|
|
1661
|
+
* // 3857 = Web Mercator
|
|
1662
|
+
* region: DataTypes.GEOGRAPHY('MULTIPOLYGON', 4326)
|
|
1663
|
+
*/
|
|
1664
|
+
class GEOGRAPHY extends AbstractDataType {
|
|
1665
|
+
constructor(typeOrOptions, srid) {
|
|
1666
|
+
super();
|
|
1667
|
+
this.key = 'GEOGRAPHY';
|
|
1668
|
+
if (typeof typeOrOptions === 'object' && typeOrOptions !== null) {
|
|
1669
|
+
// Called with options object: GEOGRAPHY({ type: 'POLYGON', srid: 4326 })
|
|
1670
|
+
this.type = typeOrOptions.type;
|
|
1671
|
+
this.srid = typeOrOptions.srid;
|
|
1672
|
+
}
|
|
1673
|
+
else {
|
|
1674
|
+
// Called with positional args: GEOGRAPHY('POLYGON', 4326)
|
|
1675
|
+
this.type = typeOrOptions;
|
|
1676
|
+
this.srid = srid;
|
|
1677
|
+
}
|
|
1678
|
+
// Default to WGS84 (SRID 4326) if not specified
|
|
1679
|
+
if (this.srid === undefined) {
|
|
1680
|
+
this.srid = 4326;
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
/**
|
|
1684
|
+
* Get the geography type in uppercase
|
|
1685
|
+
*/
|
|
1686
|
+
getGeographyType() {
|
|
1687
|
+
return this.type?.toUpperCase();
|
|
1688
|
+
}
|
|
1689
|
+
/**
|
|
1690
|
+
* Get the SRID (defaults to 4326 for WGS84)
|
|
1691
|
+
*/
|
|
1692
|
+
getSRID() {
|
|
1693
|
+
return this.srid || 4326;
|
|
1694
|
+
}
|
|
1695
|
+
toSqlString(dialect) {
|
|
1696
|
+
const typeStr = this.type ? this.type.toUpperCase() : '';
|
|
1697
|
+
const sridStr = this.srid ? `, ${this.srid}` : '';
|
|
1698
|
+
switch (dialect) {
|
|
1699
|
+
case 'postgres':
|
|
1700
|
+
// PostgreSQL with PostGIS - GEOGRAPHY is preferred for geographic data
|
|
1701
|
+
if (typeStr && sridStr) {
|
|
1702
|
+
return `GEOGRAPHY(${typeStr}${sridStr})`;
|
|
1703
|
+
}
|
|
1704
|
+
else if (typeStr) {
|
|
1705
|
+
return `GEOGRAPHY(${typeStr})`;
|
|
1706
|
+
}
|
|
1707
|
+
// Default geography defaults to GEOGRAPHY(GEOMETRY, 4326)
|
|
1708
|
+
return 'GEOGRAPHY';
|
|
1709
|
+
case 'mysql':
|
|
1710
|
+
case 'mariadb':
|
|
1711
|
+
// MySQL 8.0+ supports GEOGRAPHY type
|
|
1712
|
+
if (typeStr) {
|
|
1713
|
+
return typeStr;
|
|
1714
|
+
}
|
|
1715
|
+
return 'GEOMETRY'; // MySQL treats geography as geometry
|
|
1716
|
+
case 'mssql':
|
|
1717
|
+
case 'sqlserver':
|
|
1718
|
+
// SQL Server geography type (uses WGS84 by default)
|
|
1719
|
+
if (typeStr) {
|
|
1720
|
+
return `geography`;
|
|
1721
|
+
}
|
|
1722
|
+
return 'geography';
|
|
1723
|
+
case 'sqlite':
|
|
1724
|
+
default:
|
|
1725
|
+
// SQLite stores spatial data as BLOB
|
|
1726
|
+
return 'BLOB';
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
exports.GEOGRAPHY = GEOGRAPHY;
|
|
1731
|
+
/**
|
|
1732
|
+
* POINT - specific geometry type for points
|
|
1733
|
+
* Shorthand for GEOMETRY('POINT', srid)
|
|
1734
|
+
*
|
|
1735
|
+
* @example
|
|
1736
|
+
* // Point with default SRID (4326)
|
|
1737
|
+
* location: DataTypes.POINT()
|
|
1738
|
+
*
|
|
1739
|
+
* // Point with custom SRID
|
|
1740
|
+
* location: DataTypes.POINT(4326)
|
|
1741
|
+
*/
|
|
1742
|
+
class POINT extends AbstractDataType {
|
|
1743
|
+
constructor(srid) {
|
|
1744
|
+
super();
|
|
1745
|
+
this.key = 'POINT';
|
|
1746
|
+
this.srid = srid;
|
|
1747
|
+
}
|
|
1748
|
+
toSqlString(dialect) {
|
|
1749
|
+
switch (dialect) {
|
|
1750
|
+
case 'postgres':
|
|
1751
|
+
if (this.srid) {
|
|
1752
|
+
return `GEOMETRY(POINT, ${this.srid})`;
|
|
1753
|
+
}
|
|
1754
|
+
return 'GEOMETRY(POINT)';
|
|
1755
|
+
case 'mysql':
|
|
1756
|
+
case 'mariadb':
|
|
1757
|
+
return 'POINT';
|
|
1758
|
+
case 'mssql':
|
|
1759
|
+
case 'sqlserver':
|
|
1760
|
+
return 'geometry';
|
|
1761
|
+
case 'sqlite':
|
|
1762
|
+
default:
|
|
1763
|
+
return 'BLOB';
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
exports.POINT = POINT;
|
|
1768
|
+
/**
|
|
1769
|
+
* LINESTRING - specific geometry type for lines
|
|
1770
|
+
* Shorthand for GEOMETRY('LINESTRING', srid)
|
|
1771
|
+
*
|
|
1772
|
+
* @example
|
|
1773
|
+
* // LineString with default SRID (4326)
|
|
1774
|
+
* route: DataTypes.LINESTRING()
|
|
1775
|
+
*
|
|
1776
|
+
* // LineString with custom SRID
|
|
1777
|
+
* route: DataTypes.LINESTRING(4326)
|
|
1778
|
+
*/
|
|
1779
|
+
class LINESTRING extends AbstractDataType {
|
|
1780
|
+
constructor(srid) {
|
|
1781
|
+
super();
|
|
1782
|
+
this.key = 'LINESTRING';
|
|
1783
|
+
this.srid = srid;
|
|
1784
|
+
}
|
|
1785
|
+
toSqlString(dialect) {
|
|
1786
|
+
switch (dialect) {
|
|
1787
|
+
case 'postgres':
|
|
1788
|
+
if (this.srid) {
|
|
1789
|
+
return `GEOMETRY(LINESTRING, ${this.srid})`;
|
|
1790
|
+
}
|
|
1791
|
+
return 'GEOMETRY(LINESTRING)';
|
|
1792
|
+
case 'mysql':
|
|
1793
|
+
case 'mariadb':
|
|
1794
|
+
return 'LINESTRING';
|
|
1795
|
+
case 'mssql':
|
|
1796
|
+
case 'sqlserver':
|
|
1797
|
+
return 'geometry';
|
|
1798
|
+
case 'sqlite':
|
|
1799
|
+
default:
|
|
1800
|
+
return 'BLOB';
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
exports.LINESTRING = LINESTRING;
|
|
1805
|
+
/**
|
|
1806
|
+
* POLYGON - specific geometry type for polygons
|
|
1807
|
+
* Shorthand for GEOMETRY('POLYGON', srid)
|
|
1808
|
+
*
|
|
1809
|
+
* @example
|
|
1810
|
+
* // Polygon with default SRID (4326)
|
|
1811
|
+
* boundary: DataTypes.POLYGON()
|
|
1812
|
+
*
|
|
1813
|
+
* // Polygon with custom SRID
|
|
1814
|
+
* boundary: DataTypes.POLYGON(4326)
|
|
1815
|
+
*/
|
|
1816
|
+
class POLYGON extends AbstractDataType {
|
|
1817
|
+
constructor(srid) {
|
|
1818
|
+
super();
|
|
1819
|
+
this.key = 'POLYGON';
|
|
1820
|
+
this.srid = srid;
|
|
1821
|
+
}
|
|
1822
|
+
toSqlString(dialect) {
|
|
1823
|
+
switch (dialect) {
|
|
1824
|
+
case 'postgres':
|
|
1825
|
+
if (this.srid) {
|
|
1826
|
+
return `GEOMETRY(POLYGON, ${this.srid})`;
|
|
1827
|
+
}
|
|
1828
|
+
return 'GEOMETRY(POLYGON)';
|
|
1829
|
+
case 'mysql':
|
|
1830
|
+
case 'mariadb':
|
|
1831
|
+
return 'POLYGON';
|
|
1832
|
+
case 'mssql':
|
|
1833
|
+
case 'sqlserver':
|
|
1834
|
+
return 'geometry';
|
|
1835
|
+
case 'sqlite':
|
|
1836
|
+
default:
|
|
1837
|
+
return 'BLOB';
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
exports.POLYGON = POLYGON;
|
|
1842
|
+
// MULTIPOINT - MySQL spatial type for collections of points
|
|
1843
|
+
class MULTIPOINT extends AbstractDataType {
|
|
1844
|
+
constructor(srid) {
|
|
1845
|
+
super();
|
|
1846
|
+
this.key = 'MULTIPOINT';
|
|
1847
|
+
this.srid = srid;
|
|
1848
|
+
}
|
|
1849
|
+
toSqlString(dialect) {
|
|
1850
|
+
switch (dialect) {
|
|
1851
|
+
case 'postgres':
|
|
1852
|
+
if (this.srid) {
|
|
1853
|
+
return `GEOMETRY(MULTIPOINT, ${this.srid})`;
|
|
1854
|
+
}
|
|
1855
|
+
return 'GEOMETRY(MULTIPOINT)';
|
|
1856
|
+
case 'mysql':
|
|
1857
|
+
case 'mariadb':
|
|
1858
|
+
return 'MULTIPOINT';
|
|
1859
|
+
case 'mssql':
|
|
1860
|
+
case 'sqlserver':
|
|
1861
|
+
return 'geometry';
|
|
1862
|
+
case 'sqlite':
|
|
1863
|
+
default:
|
|
1864
|
+
return 'BLOB';
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
exports.MULTIPOINT = MULTIPOINT;
|
|
1869
|
+
// MULTILINESTRING - MySQL spatial type for collections of lines
|
|
1870
|
+
class MULTILINESTRING extends AbstractDataType {
|
|
1871
|
+
constructor(srid) {
|
|
1872
|
+
super();
|
|
1873
|
+
this.key = 'MULTILINESTRING';
|
|
1874
|
+
this.srid = srid;
|
|
1875
|
+
}
|
|
1876
|
+
toSqlString(dialect) {
|
|
1877
|
+
switch (dialect) {
|
|
1878
|
+
case 'postgres':
|
|
1879
|
+
if (this.srid) {
|
|
1880
|
+
return `GEOMETRY(MULTILINESTRING, ${this.srid})`;
|
|
1881
|
+
}
|
|
1882
|
+
return 'GEOMETRY(MULTILINESTRING)';
|
|
1883
|
+
case 'mysql':
|
|
1884
|
+
case 'mariadb':
|
|
1885
|
+
return 'MULTILINESTRING';
|
|
1886
|
+
case 'mssql':
|
|
1887
|
+
case 'sqlserver':
|
|
1888
|
+
return 'geometry';
|
|
1889
|
+
case 'sqlite':
|
|
1890
|
+
default:
|
|
1891
|
+
return 'BLOB';
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
exports.MULTILINESTRING = MULTILINESTRING;
|
|
1896
|
+
// MULTIPOLYGON - MySQL spatial type for collections of polygons
|
|
1897
|
+
class MULTIPOLYGON extends AbstractDataType {
|
|
1898
|
+
constructor(srid) {
|
|
1899
|
+
super();
|
|
1900
|
+
this.key = 'MULTIPOLYGON';
|
|
1901
|
+
this.srid = srid;
|
|
1902
|
+
}
|
|
1903
|
+
toSqlString(dialect) {
|
|
1904
|
+
switch (dialect) {
|
|
1905
|
+
case 'postgres':
|
|
1906
|
+
if (this.srid) {
|
|
1907
|
+
return `GEOMETRY(MULTIPOLYGON, ${this.srid})`;
|
|
1908
|
+
}
|
|
1909
|
+
return 'GEOMETRY(MULTIPOLYGON)';
|
|
1910
|
+
case 'mysql':
|
|
1911
|
+
case 'mariadb':
|
|
1912
|
+
return 'MULTIPOLYGON';
|
|
1913
|
+
case 'mssql':
|
|
1914
|
+
case 'sqlserver':
|
|
1915
|
+
return 'geometry';
|
|
1916
|
+
case 'sqlite':
|
|
1917
|
+
default:
|
|
1918
|
+
return 'BLOB';
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
exports.MULTIPOLYGON = MULTIPOLYGON;
|
|
1923
|
+
// GEOMETRYCOLLECTION - MySQL spatial type for heterogeneous geometry collections
|
|
1924
|
+
class GEOMETRYCOLLECTION extends AbstractDataType {
|
|
1925
|
+
constructor(srid) {
|
|
1926
|
+
super();
|
|
1927
|
+
this.key = 'GEOMETRYCOLLECTION';
|
|
1928
|
+
this.srid = srid;
|
|
1929
|
+
}
|
|
1930
|
+
toSqlString(dialect) {
|
|
1931
|
+
switch (dialect) {
|
|
1932
|
+
case 'postgres':
|
|
1933
|
+
if (this.srid) {
|
|
1934
|
+
return `GEOMETRY(GEOMETRYCOLLECTION, ${this.srid})`;
|
|
1935
|
+
}
|
|
1936
|
+
return 'GEOMETRY(GEOMETRYCOLLECTION)';
|
|
1937
|
+
case 'mysql':
|
|
1938
|
+
case 'mariadb':
|
|
1939
|
+
return 'GEOMETRYCOLLECTION';
|
|
1940
|
+
case 'mssql':
|
|
1941
|
+
case 'sqlserver':
|
|
1942
|
+
return 'geometry';
|
|
1943
|
+
case 'sqlite':
|
|
1944
|
+
default:
|
|
1945
|
+
return 'BLOB';
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
exports.GEOMETRYCOLLECTION = GEOMETRYCOLLECTION;
|
|
1950
|
+
// SET - MySQL SET column type for storing multiple values from a set
|
|
1951
|
+
class SET extends AbstractDataType {
|
|
1952
|
+
/**
|
|
1953
|
+
* Create a SET data type
|
|
1954
|
+
* @param values - Either an array of values or individual string values
|
|
1955
|
+
* @example
|
|
1956
|
+
* // Array of values
|
|
1957
|
+
* DataTypes.SET(['red', 'green', 'blue'])
|
|
1958
|
+
* // Individual values
|
|
1959
|
+
* DataTypes.SET('red', 'green', 'blue')
|
|
1960
|
+
*/
|
|
1961
|
+
constructor(...values) {
|
|
1962
|
+
super();
|
|
1963
|
+
this.key = 'SET';
|
|
1964
|
+
// Handle both array and spread arguments
|
|
1965
|
+
if (values.length === 1 && Array.isArray(values[0])) {
|
|
1966
|
+
this.values = values[0];
|
|
1967
|
+
}
|
|
1968
|
+
else {
|
|
1969
|
+
this.values = values;
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
toSqlString(dialect) {
|
|
1973
|
+
const valuesStr = this.values.map((v) => `'${v}'`).join(', ');
|
|
1974
|
+
switch (dialect) {
|
|
1975
|
+
case 'mysql':
|
|
1976
|
+
case 'mariadb':
|
|
1977
|
+
// MySQL/MariaDB support native SET type
|
|
1978
|
+
return `SET(${valuesStr})`;
|
|
1979
|
+
case 'postgres':
|
|
1980
|
+
case 'sqlite':
|
|
1981
|
+
default:
|
|
1982
|
+
// Other dialects use TEXT with validation
|
|
1983
|
+
return 'TEXT';
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
/**
|
|
1987
|
+
* Get the values for validation
|
|
1988
|
+
*/
|
|
1989
|
+
getValues() {
|
|
1990
|
+
return [...this.values];
|
|
1991
|
+
}
|
|
1992
|
+
/**
|
|
1993
|
+
* Validate if a value is valid for this SET
|
|
1994
|
+
*/
|
|
1995
|
+
validate(value) {
|
|
1996
|
+
return this.values.includes(value);
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
exports.SET = SET;
|
|
2000
|
+
// JSONColumn - MySQL native JSON column type
|
|
2001
|
+
class JSONColumn extends AbstractDataType {
|
|
2002
|
+
/**
|
|
2003
|
+
* Create a JSON column type
|
|
2004
|
+
* @param options - Options for JSON column
|
|
2005
|
+
* @example
|
|
2006
|
+
* // Basic JSON column
|
|
2007
|
+
* DataTypes.JSONCOLUMN()
|
|
2008
|
+
* // JSON column with validation
|
|
2009
|
+
* DataTypes.JSONCOLUMN({ validate: true })
|
|
2010
|
+
*/
|
|
2011
|
+
constructor(options) {
|
|
2012
|
+
super();
|
|
2013
|
+
this.key = 'JSONCOLUMN';
|
|
2014
|
+
if (options) {
|
|
2015
|
+
this.validate = options.validate;
|
|
2016
|
+
this.unescapedUnicode = options.unescapedUnicode;
|
|
2017
|
+
this.compact = options.compact;
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
toSqlString(dialect) {
|
|
2021
|
+
switch (dialect) {
|
|
2022
|
+
case 'mysql':
|
|
2023
|
+
case 'mariadb':
|
|
2024
|
+
// MySQL/MariaDB native JSON type
|
|
2025
|
+
return 'JSON';
|
|
2026
|
+
case 'postgres':
|
|
2027
|
+
// PostgreSQL uses JSONB for better performance
|
|
2028
|
+
return 'JSONB';
|
|
2029
|
+
case 'sqlite':
|
|
2030
|
+
return 'TEXT';
|
|
2031
|
+
case 'mssql':
|
|
2032
|
+
case 'sqlserver':
|
|
2033
|
+
// SQL Server uses NVARCHAR(MAX) for JSON
|
|
2034
|
+
return 'NVARCHAR(MAX)';
|
|
2035
|
+
default:
|
|
2036
|
+
return 'TEXT';
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
exports.JSONColumn = JSONColumn;
|
|
2041
|
+
class VIRTUAL extends AbstractDataType {
|
|
2042
|
+
constructor(options) {
|
|
2043
|
+
super();
|
|
2044
|
+
this.key = 'VIRTUAL';
|
|
2045
|
+
if (options) {
|
|
2046
|
+
this.returnType = options.returnType;
|
|
2047
|
+
this.get = options.get;
|
|
2048
|
+
this.set = options.set;
|
|
2049
|
+
this.dependencies = options.dependencies;
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
toSqlString() {
|
|
2053
|
+
// Virtual fields don't create a database column
|
|
2054
|
+
return '';
|
|
2055
|
+
}
|
|
2056
|
+
/**
|
|
2057
|
+
* Check if this virtual field has a getter
|
|
2058
|
+
*/
|
|
2059
|
+
hasGetter() {
|
|
2060
|
+
return typeof this.get === 'function';
|
|
2061
|
+
}
|
|
2062
|
+
/**
|
|
2063
|
+
* Check if this virtual field has a setter
|
|
2064
|
+
*/
|
|
2065
|
+
hasSetter() {
|
|
2066
|
+
return typeof this.set === 'function';
|
|
2067
|
+
}
|
|
2068
|
+
/**
|
|
2069
|
+
* Get the dependencies for this virtual field
|
|
2070
|
+
*/
|
|
2071
|
+
getDependencies() {
|
|
2072
|
+
return this.dependencies || [];
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
exports.VIRTUAL = VIRTUAL;
|
|
2076
|
+
/**
|
|
2077
|
+
* VIRTUALSTRING - virtual string field with getter/setter support
|
|
2078
|
+
* Does not create a database column but provides computed string values
|
|
2079
|
+
*
|
|
2080
|
+
* @example
|
|
2081
|
+
* // Virtual string with getter (computed from other fields)
|
|
2082
|
+
* fullName: DataTypes.VIRTUALSTRING({
|
|
2083
|
+
* get() {
|
|
2084
|
+
* return `${this.firstName} ${this.lastName}`;
|
|
2085
|
+
* },
|
|
2086
|
+
* dependencies: ['firstName', 'lastName']
|
|
2087
|
+
* })
|
|
2088
|
+
*
|
|
2089
|
+
* // Virtual string with getter and setter
|
|
2090
|
+
* email: DataTypes.VIRTUALSTRING({
|
|
2091
|
+
* get() {
|
|
2092
|
+
* return this._email?.toLowerCase();
|
|
2093
|
+
* },
|
|
2094
|
+
* set(value: string) {
|
|
2095
|
+
* this._email = value.trim().toLowerCase();
|
|
2096
|
+
* },
|
|
2097
|
+
* length: 255
|
|
2098
|
+
* })
|
|
2099
|
+
*/
|
|
2100
|
+
class VIRTUALSTRING extends AbstractDataType {
|
|
2101
|
+
constructor(options) {
|
|
2102
|
+
super();
|
|
2103
|
+
this.key = 'VIRTUALSTRING';
|
|
2104
|
+
if (options) {
|
|
2105
|
+
this.get = options.get;
|
|
2106
|
+
this.set = options.set;
|
|
2107
|
+
this.length = options.length;
|
|
2108
|
+
this.dependencies = options.dependencies;
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
toSqlString() {
|
|
2112
|
+
// Virtual fields don't create a database column
|
|
2113
|
+
return '';
|
|
2114
|
+
}
|
|
2115
|
+
/**
|
|
2116
|
+
* Check if this virtual string field has a getter
|
|
2117
|
+
*/
|
|
2118
|
+
hasGetter() {
|
|
2119
|
+
return typeof this.get === 'function';
|
|
2120
|
+
}
|
|
2121
|
+
/**
|
|
2122
|
+
* Check if this virtual string field has a setter
|
|
2123
|
+
*/
|
|
2124
|
+
hasSetter() {
|
|
2125
|
+
return typeof this.set === 'function';
|
|
2126
|
+
}
|
|
2127
|
+
/**
|
|
2128
|
+
* Get the dependencies for this virtual field
|
|
2129
|
+
*/
|
|
2130
|
+
getDependencies() {
|
|
2131
|
+
return this.dependencies || [];
|
|
2132
|
+
}
|
|
2133
|
+
/**
|
|
2134
|
+
* Get the maximum length for validation
|
|
2135
|
+
*/
|
|
2136
|
+
getLength() {
|
|
2137
|
+
return this.length;
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
exports.VIRTUALSTRING = VIRTUALSTRING;
|
|
2141
|
+
/**
|
|
2142
|
+
* ALGORITHM - data type for hash algorithms
|
|
2143
|
+
* Used for storing hashed values (passwords, checksums, etc.)
|
|
2144
|
+
* Can be used with VIRTUAL type for computed/hashed fields
|
|
2145
|
+
*
|
|
2146
|
+
* Common output lengths:
|
|
2147
|
+
* - MD5: 32 hex chars (16 bytes)
|
|
2148
|
+
* - SHA1: 40 hex chars (20 bytes)
|
|
2149
|
+
* - SHA256: 64 hex chars (32 bytes)
|
|
2150
|
+
* - SHA384: 96 hex chars (48 bytes)
|
|
2151
|
+
* - SHA512: 128 hex chars (64 bytes)
|
|
2152
|
+
* - BCRYPT: 60 chars (with $2a$ or $2b$ prefix)
|
|
2153
|
+
* - ARGON2: Variable, typically ~100 chars (with $argon2$ prefix)
|
|
2154
|
+
* - PBKDF2: Variable based on hash length
|
|
2155
|
+
*
|
|
2156
|
+
* @example
|
|
2157
|
+
* // Store password hash using BCRYPT (recommended for passwords)
|
|
2158
|
+
* password: DataTypes.ALGORITHM({ algorithm: 'BCRYPT', cost: 12 })
|
|
2159
|
+
*
|
|
2160
|
+
* // Store checksum using SHA256
|
|
2161
|
+
* fileChecksum: DataTypes.ALGORITHM({ algorithm: 'SHA256' })
|
|
2162
|
+
*
|
|
2163
|
+
* // Store password hash using ARGON2
|
|
2164
|
+
* password: DataTypes.ALGORITHM({ algorithm: 'ARGON2', cost: 65536, parallelism: 2 })
|
|
2165
|
+
*
|
|
2166
|
+
* // Use with VIRTUAL for auto-hashing on set
|
|
2167
|
+
* passwordHash: DataTypes.VIRTUAL({
|
|
2168
|
+
* returnType: DataTypes.ALGORITHM({ algorithm: 'BCRYPT' }),
|
|
2169
|
+
* set(value: string) {
|
|
2170
|
+
* this.password = hashPassword(value);
|
|
2171
|
+
* }
|
|
2172
|
+
* })
|
|
2173
|
+
*/
|
|
2174
|
+
class ALGORITHM extends AbstractDataType {
|
|
2175
|
+
/**
|
|
2176
|
+
* Get the default cost/rounds for each algorithm
|
|
2177
|
+
*/
|
|
2178
|
+
getDefaultCost() {
|
|
2179
|
+
switch (this.algorithm) {
|
|
2180
|
+
case 'BCRYPT':
|
|
2181
|
+
return 10;
|
|
2182
|
+
case 'ARGON2':
|
|
2183
|
+
return 65536; // memory cost in KB
|
|
2184
|
+
case 'PBKDF2':
|
|
2185
|
+
return 100000;
|
|
2186
|
+
case 'SCRYPT':
|
|
2187
|
+
return 16384;
|
|
2188
|
+
default:
|
|
2189
|
+
return 0;
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
/**
|
|
2193
|
+
* Get the output length for each algorithm (in characters for VARCHAR)
|
|
2194
|
+
* This accounts for the full hash including prefixes, salts, etc.
|
|
2195
|
+
*/
|
|
2196
|
+
getOutputLength() {
|
|
2197
|
+
switch (this.algorithm) {
|
|
2198
|
+
case 'MD5':
|
|
2199
|
+
return 32; // 32 hex characters
|
|
2200
|
+
case 'SHA1':
|
|
2201
|
+
return 40; // 40 hex characters
|
|
2202
|
+
case 'SHA256':
|
|
2203
|
+
return 64; // 64 hex characters
|
|
2204
|
+
case 'SHA384':
|
|
2205
|
+
return 96; // 96 hex characters
|
|
2206
|
+
case 'SHA512':
|
|
2207
|
+
return 128; // 128 hex characters
|
|
2208
|
+
case 'SHA512_256':
|
|
2209
|
+
return 64; // 64 hex characters
|
|
2210
|
+
case 'BCRYPT':
|
|
2211
|
+
return 60; // $2a$10$ + 53 characters
|
|
2212
|
+
case 'ARGON2':
|
|
2213
|
+
return 128; // $argon2id$v=19$m=65536,t=3,p=2$ + salt + hash
|
|
2214
|
+
case 'PBKDF2':
|
|
2215
|
+
return this.hashLength ? this.hashLength * 2 : 128; // Hex encoded
|
|
2216
|
+
case 'SCRYPT':
|
|
2217
|
+
return 128; // Variable length
|
|
2218
|
+
case 'NTLM':
|
|
2219
|
+
return 32; // 32 hex characters
|
|
2220
|
+
case 'MYSQL':
|
|
2221
|
+
return 40; // 40 hex characters
|
|
2222
|
+
case 'POSTGRESQL_MD5':
|
|
2223
|
+
return 35; // md5( + 32 hex + )
|
|
2224
|
+
default:
|
|
2225
|
+
return 64;
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
constructor(options) {
|
|
2229
|
+
super();
|
|
2230
|
+
this.key = 'ALGORITHM';
|
|
2231
|
+
this.algorithm = options.algorithm;
|
|
2232
|
+
this.cost = options.cost ?? (options.algorithm ? this.getDefaultCost() : undefined);
|
|
2233
|
+
this.saltLength = options.saltLength;
|
|
2234
|
+
this.hashLength = options.hashLength;
|
|
2235
|
+
this.includeSalt = options.includeSalt ?? true;
|
|
2236
|
+
this.parallelism = options.parallelism ?? 1;
|
|
2237
|
+
this.blockSize = options.blockSize ?? 8;
|
|
2238
|
+
}
|
|
2239
|
+
/**
|
|
2240
|
+
* Get the algorithm name
|
|
2241
|
+
*/
|
|
2242
|
+
getAlgorithm() {
|
|
2243
|
+
return this.algorithm;
|
|
2244
|
+
}
|
|
2245
|
+
/**
|
|
2246
|
+
* Check if this is a password hashing algorithm (slow hash)
|
|
2247
|
+
* Password hashing algorithms are designed to be slow to prevent brute force
|
|
2248
|
+
*/
|
|
2249
|
+
isPasswordHash() {
|
|
2250
|
+
return ['BCRYPT', 'ARGON2', 'PBKDF2', 'SCRYPT'].includes(this.algorithm);
|
|
2251
|
+
}
|
|
2252
|
+
/**
|
|
2253
|
+
* Check if this is a fast hash algorithm (checksums)
|
|
2254
|
+
*/
|
|
2255
|
+
isFastHash() {
|
|
2256
|
+
return ['MD5', 'SHA1', 'SHA256', 'SHA384', 'SHA512', 'SHA512_256', 'NTLM'].includes(this.algorithm);
|
|
2257
|
+
}
|
|
2258
|
+
/**
|
|
2259
|
+
* Get the configuration object for hashing libraries
|
|
2260
|
+
*/
|
|
2261
|
+
getHashConfig() {
|
|
2262
|
+
const config = {
|
|
2263
|
+
algorithm: this.algorithm,
|
|
2264
|
+
};
|
|
2265
|
+
if (this.cost) {
|
|
2266
|
+
if (this.algorithm === 'BCRYPT') {
|
|
2267
|
+
config.rounds = this.cost;
|
|
2268
|
+
}
|
|
2269
|
+
else if (this.algorithm === 'ARGON2') {
|
|
2270
|
+
config.memoryCost = this.cost;
|
|
2271
|
+
}
|
|
2272
|
+
else if (this.algorithm === 'PBKDF2') {
|
|
2273
|
+
config.iterations = this.cost;
|
|
2274
|
+
}
|
|
2275
|
+
else if (this.algorithm === 'SCRYPT') {
|
|
2276
|
+
config.cost = this.cost;
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
if (this.saltLength) {
|
|
2280
|
+
config.saltLength = this.saltLength;
|
|
2281
|
+
}
|
|
2282
|
+
if (this.hashLength) {
|
|
2283
|
+
config.hashLength = this.hashLength;
|
|
2284
|
+
}
|
|
2285
|
+
if (this.parallelism && this.algorithm === 'ARGON2') {
|
|
2286
|
+
config.parallelism = this.parallelism;
|
|
2287
|
+
}
|
|
2288
|
+
if (this.blockSize && this.algorithm === 'ARGON2') {
|
|
2289
|
+
config.blockSize = this.blockSize;
|
|
2290
|
+
}
|
|
2291
|
+
return config;
|
|
2292
|
+
}
|
|
2293
|
+
toSqlString(dialect) {
|
|
2294
|
+
const length = this.getOutputLength();
|
|
2295
|
+
// For most databases, use VARCHAR with appropriate length
|
|
2296
|
+
// Some databases support native password hash types
|
|
2297
|
+
switch (dialect) {
|
|
2298
|
+
case 'postgres':
|
|
2299
|
+
// PostgreSQL doesn't have specific hash types, use VARCHAR
|
|
2300
|
+
return `VARCHAR(${length})`;
|
|
2301
|
+
case 'mysql':
|
|
2302
|
+
case 'mariadb':
|
|
2303
|
+
// MySQL/MariaDB - use VARCHAR for password hashes
|
|
2304
|
+
return `VARCHAR(${length})`;
|
|
2305
|
+
case 'sqlite':
|
|
2306
|
+
// SQLite uses TEXT for variable-length strings
|
|
2307
|
+
return `TEXT`;
|
|
2308
|
+
case 'mssql':
|
|
2309
|
+
case 'sqlserver':
|
|
2310
|
+
// SQL Server uses NVARCHAR
|
|
2311
|
+
return `NVARCHAR(${length})`;
|
|
2312
|
+
default:
|
|
2313
|
+
return `VARCHAR(${length})`;
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
exports.ALGORITHM = ALGORITHM;
|
|
2318
|
+
/**
|
|
2319
|
+
* VIRTUAL with ALGORITHM - computed hash field
|
|
2320
|
+
* Useful for automatic password hashing when setting values
|
|
2321
|
+
*
|
|
2322
|
+
* @example
|
|
2323
|
+
* // Auto-hash password on set using BCRYPT
|
|
2324
|
+
* passwordHash: DataTypes.VIRTUAL({
|
|
2325
|
+
* returnType: DataTypes.ALGORITHM({ algorithm: 'BCRYPT', cost: 12 }),
|
|
2326
|
+
* set(value: string) {
|
|
2327
|
+
* this._passwordHash = bcrypt.hashSync(value, 12);
|
|
2328
|
+
* },
|
|
2329
|
+
* get() {
|
|
2330
|
+
* return this._passwordHash;
|
|
2331
|
+
* }
|
|
2332
|
+
* })
|
|
2333
|
+
*
|
|
2334
|
+
* // Verify password (comparison virtual field)
|
|
2335
|
+
* password: DataTypes.STRING(255),
|
|
2336
|
+
* passwordConfirm: DataTypes.VIRTUAL({
|
|
2337
|
+
* returnType: DataTypes.BOOLEAN(),
|
|
2338
|
+
* set(value: string) {
|
|
2339
|
+
* // This will be handled by the model validation
|
|
2340
|
+
* }
|
|
2341
|
+
* })
|
|
2342
|
+
*/
|
|
2343
|
+
// Helper to add static toSql, equals, and serialize methods to factory functions while preserving call signature
|
|
2344
|
+
function createDataTypeFactory(factory, key) {
|
|
2345
|
+
const factoryFn = factory;
|
|
2346
|
+
// Attach the key to the factory function for comparison
|
|
2347
|
+
factoryFn.key = key;
|
|
2348
|
+
factoryFn.toSql = function () { return factory().toSql(); };
|
|
2349
|
+
// Static equals method for comparing DataType factories
|
|
2350
|
+
factoryFn.equals = function (other) {
|
|
2351
|
+
if (!other) {
|
|
2352
|
+
return false;
|
|
2353
|
+
}
|
|
2354
|
+
// If it's a factory function with a key property, compare by key
|
|
2355
|
+
if (typeof other === 'function' && other.key) {
|
|
2356
|
+
return other.key === key;
|
|
2357
|
+
}
|
|
2358
|
+
// If it's an object with key property (like a DataType instance)
|
|
2359
|
+
if (typeof other === 'object' && other.key) {
|
|
2360
|
+
return other.key === key;
|
|
2361
|
+
}
|
|
2362
|
+
// If it's a string, compare directly
|
|
2363
|
+
if (typeof other === 'string') {
|
|
2364
|
+
return other === key;
|
|
2365
|
+
}
|
|
2366
|
+
return false;
|
|
2367
|
+
};
|
|
2368
|
+
// Static serialize method for serializing values
|
|
2369
|
+
factoryFn.serialize = function (value) {
|
|
2370
|
+
return value;
|
|
2371
|
+
};
|
|
2372
|
+
return factoryFn;
|
|
2373
|
+
}
|
|
2374
|
+
// Export DataTypes object with all data types
|
|
2375
|
+
exports.DataTypes = {
|
|
2376
|
+
STRING: createDataTypeFactory((length, binary = false) => new STRING(length, binary), 'STRING'),
|
|
2377
|
+
VARCHAR: createDataTypeFactory((length = 255) => new VARCHAR(length), 'VARCHAR'),
|
|
2378
|
+
CHAR: createDataTypeFactory((length = 1) => new CHAR(length), 'CHAR'),
|
|
2379
|
+
TEXT: createDataTypeFactory((length) => new TEXT(length), 'TEXT'),
|
|
2380
|
+
TINYTEXT: createDataTypeFactory(() => new TINYTEXT(), 'TINYTEXT'),
|
|
2381
|
+
MEDIUMTEXT: createDataTypeFactory(() => new MEDIUMTEXT(), 'MEDIUMTEXT'),
|
|
2382
|
+
LONGTEXT: createDataTypeFactory(() => new LONGTEXT(), 'LONGTEXT'),
|
|
2383
|
+
INTEGER: createDataTypeFactory((options) => new INTEGER(options || {}), 'INTEGER'),
|
|
2384
|
+
TINYINT: createDataTypeFactory((options) => new TINYINT(options || {}), 'TINYINT'),
|
|
2385
|
+
SMALLINT: createDataTypeFactory((options) => new SMALLINT(options || {}), 'SMALLINT'),
|
|
2386
|
+
MEDIUMINT: createDataTypeFactory((options) => new MEDIUMINT(options || {}), 'MEDIUMINT'),
|
|
2387
|
+
BIGINT: createDataTypeFactory((options) => new BIGINT(options || {}), 'BIGINT'),
|
|
2388
|
+
FLOAT: createDataTypeFactory((precisionOrOptions) => new FLOAT(precisionOrOptions), 'FLOAT'),
|
|
2389
|
+
DOUBLE: createDataTypeFactory((precisionOrOptions) => new DOUBLE(precisionOrOptions), 'DOUBLE'),
|
|
2390
|
+
DECIMAL: createDataTypeFactory((precision = 10, scale = 0, unsigned = false) => new DECIMAL(precision, scale, unsigned), 'DECIMAL'),
|
|
2391
|
+
REAL: createDataTypeFactory((precisionOrOptions) => new REAL(precisionOrOptions), 'REAL'),
|
|
2392
|
+
BOOLEAN: createDataTypeFactory(() => new BOOLEAN(), 'BOOLEAN'),
|
|
2393
|
+
DATE: createDataTypeFactory((precision, timezone = false) => new DATE(precision, timezone), 'DATE'),
|
|
2394
|
+
DATEONLY: createDataTypeFactory(() => new DATEONLY(), 'DATEONLY'),
|
|
2395
|
+
DATETIME: createDataTypeFactory((precision) => new DATETIME(precision), 'DATETIME'),
|
|
2396
|
+
TIMESTAMP: createDataTypeFactory((precision) => new TIMESTAMP(precision), 'TIMESTAMP'),
|
|
2397
|
+
NOW: createDataTypeFactory(() => new NOW(), 'NOW'),
|
|
2398
|
+
TIME: createDataTypeFactory((precision, timezone = false) => new TIME(precision, timezone), 'TIME'),
|
|
2399
|
+
UUID: createDataTypeFactory(() => new UUID(), 'UUID'),
|
|
2400
|
+
UUIDV1: createDataTypeFactory(() => new UUIDV1(), 'UUIDV1'),
|
|
2401
|
+
UUIDV4: createDataTypeFactory(() => new UUIDV4(), 'UUIDV4'),
|
|
2402
|
+
JSON: createDataTypeFactory((useNative = false) => new JSON(useNative), 'JSON'),
|
|
2403
|
+
JSONB: createDataTypeFactory((useNative = false) => new JSONB(useNative), 'JSONB'),
|
|
2404
|
+
// PostgreSQL-specific types
|
|
2405
|
+
HSTORE: createDataTypeFactory((useNative = true) => new HSTORE(useNative), 'HSTORE'),
|
|
2406
|
+
RANGE: createDataTypeFactory((subtype) => new RANGE(subtype), 'RANGE'),
|
|
2407
|
+
INET: createDataTypeFactory((options) => new INET(options), 'INET'),
|
|
2408
|
+
// Convenience factory for an IPv6-specific INET column, e.g.
|
|
2409
|
+
// `DataTypes.INET6` instead of `DataTypes.INET({ version: 6 })`. Dialects
|
|
2410
|
+
// with a distinct IPv6 column type (e.g. ClickHouse's `IPv6`) key off
|
|
2411
|
+
// `INET.version`, which this sets to `6`; dialects that only have one
|
|
2412
|
+
// "INET" type (Postgres) render identically either way.
|
|
2413
|
+
INET6: createDataTypeFactory(() => new INET({ version: 6 }), 'INET'),
|
|
2414
|
+
CIDR: createDataTypeFactory(() => new CIDR(), 'CIDR'),
|
|
2415
|
+
MACADDR: createDataTypeFactory(() => new MACADDR(), 'MACADDR'),
|
|
2416
|
+
BLOB: createDataTypeFactory((length) => new BLOB(length), 'BLOB'),
|
|
2417
|
+
TINYBLOB: createDataTypeFactory(() => new TINYBLOB(), 'TINYBLOB'),
|
|
2418
|
+
MEDIUMBLOB: createDataTypeFactory(() => new MEDIUMBLOB(), 'MEDIUMBLOB'),
|
|
2419
|
+
LONGBLOB: createDataTypeFactory(() => new LONGBLOB(), 'LONGBLOB'),
|
|
2420
|
+
BINARY: createDataTypeFactory((length = 1) => new BINARY(length), 'BINARY'),
|
|
2421
|
+
VARBINARY: createDataTypeFactory((length = 255) => new VARBINARY(length), 'VARBINARY'),
|
|
2422
|
+
/**
|
|
2423
|
+
* ENUM data type
|
|
2424
|
+
* @param values - Either an array of values or individual string values
|
|
2425
|
+
* @example
|
|
2426
|
+
* // Array of values
|
|
2427
|
+
* status: { type: DataTypes.ENUM(['active', 'inactive', 'pending']) }
|
|
2428
|
+
* // Individual values
|
|
2429
|
+
* role: DataTypes.ENUM('admin', 'user', 'guest')
|
|
2430
|
+
*/
|
|
2431
|
+
ENUM: createDataTypeFactory((...values) => new ENUM(...values), 'ENUM'),
|
|
2432
|
+
ARRAY: createDataTypeFactory((type) => new ARRAY(type), 'ARRAY'),
|
|
2433
|
+
/**
|
|
2434
|
+
* LIST data type - DuckDB native variable-length list (`elementType[]`)
|
|
2435
|
+
* @param type - The data type of list elements
|
|
2436
|
+
* @example
|
|
2437
|
+
* tags: DataTypes.LIST(DataTypes.INTEGER)
|
|
2438
|
+
*/
|
|
2439
|
+
LIST: createDataTypeFactory((type) => new LIST(type), 'LIST'),
|
|
2440
|
+
/**
|
|
2441
|
+
* STRUCT data type - DuckDB native nested record (`STRUCT(field TYPE, ...)`)
|
|
2442
|
+
* @param fields - A map of field name -> field data type
|
|
2443
|
+
* @example
|
|
2444
|
+
* point: DataTypes.STRUCT({ x: DataTypes.INTEGER, y: DataTypes.INTEGER })
|
|
2445
|
+
*/
|
|
2446
|
+
STRUCT: createDataTypeFactory((fields) => new STRUCT(fields), 'STRUCT'),
|
|
2447
|
+
/**
|
|
2448
|
+
* MAP data type - DuckDB native key/value map (`MAP(keyType, valueType)`)
|
|
2449
|
+
* @param keyType - The data type of map keys
|
|
2450
|
+
* @param valueType - The data type of map values
|
|
2451
|
+
* @example
|
|
2452
|
+
* scores: DataTypes.MAP(DataTypes.STRING, DataTypes.INTEGER)
|
|
2453
|
+
*/
|
|
2454
|
+
MAP: createDataTypeFactory((keyType, valueType) => new MAP(keyType, valueType), 'MAP'),
|
|
2455
|
+
/**
|
|
2456
|
+
* UNION data type - DuckDB native tagged union (`UNION(tag TYPE, ...)`)
|
|
2457
|
+
* @param fields - A map of tag name -> alternative data type
|
|
2458
|
+
* @example
|
|
2459
|
+
* value: DataTypes.UNION({ num: DataTypes.INTEGER, str: DataTypes.STRING })
|
|
2460
|
+
*/
|
|
2461
|
+
UNION: createDataTypeFactory((fields) => new DUCKDB_UNION(fields), 'UNION'),
|
|
2462
|
+
GEOMETRY: createDataTypeFactory((type, srid) => new GEOMETRY(type, srid), 'GEOMETRY'),
|
|
2463
|
+
GEOGRAPHY: createDataTypeFactory((type, srid) => new GEOGRAPHY(type, srid), 'GEOGRAPHY'),
|
|
2464
|
+
POINT: createDataTypeFactory((srid) => new POINT(srid), 'POINT'),
|
|
2465
|
+
LINESTRING: createDataTypeFactory((srid) => new LINESTRING(srid), 'LINESTRING'),
|
|
2466
|
+
POLYGON: createDataTypeFactory((srid) => new POLYGON(srid), 'POLYGON'),
|
|
2467
|
+
MULTIPOINT: createDataTypeFactory((srid) => new MULTIPOINT(srid), 'MULTIPOINT'),
|
|
2468
|
+
MULTILINESTRING: createDataTypeFactory((srid) => new MULTILINESTRING(srid), 'MULTILINESTRING'),
|
|
2469
|
+
MULTIPOLYGON: createDataTypeFactory((srid) => new MULTIPOLYGON(srid), 'MULTIPOLYGON'),
|
|
2470
|
+
GEOMETRYCOLLECTION: createDataTypeFactory((srid) => new GEOMETRYCOLLECTION(srid), 'GEOMETRYCOLLECTION'),
|
|
2471
|
+
SET: createDataTypeFactory((...values) => new SET(...values), 'SET'),
|
|
2472
|
+
JSONCOLUMN: createDataTypeFactory((options) => new JSONColumn(options), 'JSONCOLUMN'),
|
|
2473
|
+
VIRTUAL: createDataTypeFactory((options) => new VIRTUAL(options), 'VIRTUAL'),
|
|
2474
|
+
VIRTUALSTRING: createDataTypeFactory((options) => new VIRTUALSTRING(options), 'VIRTUALSTRING'),
|
|
2475
|
+
/**
|
|
2476
|
+
* ALGORITHM data type for hash algorithms
|
|
2477
|
+
* Used for storing hashed values (passwords, checksums, etc.)
|
|
2478
|
+
* Supports BCRYPT, MD5, SHA1, SHA256, SHA384, SHA512, ARGON2, PBKDF2, SCRYPT, etc.
|
|
2479
|
+
*
|
|
2480
|
+
* @example
|
|
2481
|
+
* // Store password hash using BCRYPT (recommended for passwords)
|
|
2482
|
+
* password: DataTypes.ALGORITHM({ algorithm: 'BCRYPT', cost: 12 })
|
|
2483
|
+
*
|
|
2484
|
+
* // Store checksum using SHA256
|
|
2485
|
+
* fileChecksum: DataTypes.ALGORITHM({ algorithm: 'SHA256' })
|
|
2486
|
+
*
|
|
2487
|
+
* // Use with VIRTUAL for computed hash fields
|
|
2488
|
+
* passwordHash: DataTypes.VIRTUAL({
|
|
2489
|
+
* returnType: DataTypes.ALGORITHM({ algorithm: 'BCRYPT' }),
|
|
2490
|
+
* set(value: string) {
|
|
2491
|
+
* this.password = hashPassword(value);
|
|
2492
|
+
* }
|
|
2493
|
+
* })
|
|
2494
|
+
*/
|
|
2495
|
+
ALGORITHM: createDataTypeFactory((options) => new ALGORITHM(options), 'ALGORITHM'),
|
|
2496
|
+
};
|
|
2497
|
+
/**
|
|
2498
|
+
* Static convenience modifiers, mirroring the chainable instance modifiers
|
|
2499
|
+
* (e.g. `DataTypes.INTEGER().UNSIGNED()`) as pre-built instances so they can
|
|
2500
|
+
* also be accessed directly off the type factory (e.g. `DataTypes.INTEGER.UNSIGNED`).
|
|
2501
|
+
*/
|
|
2502
|
+
exports.DataTypes.INTEGER.UNSIGNED = new INTEGER({
|
|
2503
|
+
unsigned: true,
|
|
2504
|
+
});
|
|
2505
|
+
exports.DataTypes.INTEGER.ZEROFILL = new INTEGER({
|
|
2506
|
+
zerofill: true,
|
|
2507
|
+
});
|
|
2508
|
+
// STRING has no UNSIGNED/ZEROFILL semantics in SQL (those only apply to numeric types),
|
|
2509
|
+
// but the property is exposed as a harmless pass-through for API parity.
|
|
2510
|
+
exports.DataTypes.STRING.UNSIGNED = new STRING();
|
|
2511
|
+
exports.DataTypes.STRING.ZEROFILL = new STRING();
|
|
2512
|
+
// BOOLEAN is commonly stored as TINYINT(1) (this is what MySQL/MariaDB already do
|
|
2513
|
+
// under the hood for BOOLEAN columns), exposed here for explicit opt-in.
|
|
2514
|
+
exports.DataTypes.BOOLEAN.TINYINT = new TINYINT({ length: 1 });
|
|
2515
|
+
// DATE-family convenience aliases
|
|
2516
|
+
exports.DataTypes.DATE.TIMESTAMP = new TIMESTAMP();
|
|
2517
|
+
exports.DataTypes.DATE.DATEONLY = new DATEONLY();
|
|
2518
|
+
exports.DataTypes.DATE.TIME = new TIME();
|