pqb 0.52.0 → 0.52.2

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/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { ExpressionTypeMethod, Expression, RawSQLBase, emptyObject, isTemplateLiteralArgs, ColumnTypeBase, setColumnData, pushColumnData, templateLiteralSQLToCode, quoteObjectKey, toArray, emptyArray, singleQuote, addCode, singleQuoteArray, objectHasValues, toSnakeCase, columnDefaultArgumentToCode, columnErrorMessagesToCode, setObjectValueImmutable, getValueKey, addValue, isExpression, joinTruthy, stringDataToCode, getDefaultLanguage, dateDataToCode, pushOrNewArrayToObjectImmutable, noop, arrayDataToCode, numberDataToCode, logColors, applyTransforms, callWithThis, setParserToQuery, pushOrNewArray, isRawSQL, returnArg as returnArg$1, setDefaultNowFn, setDefaultLanguage, setCurrentColumnName, makeTimestampsHelpers, setAdapterConnectRetry, isObjectEmpty, ValExpression, applyMixins, snakeCaseKey } from 'orchid-core';
1
+ import { ExpressionTypeMethod, Expression, RawSQLBase, emptyObject, isTemplateLiteralArgs, ColumnTypeBase, setColumnData, pushColumnData, templateLiteralSQLToCode, quoteObjectKey, toArray, emptyArray, singleQuote, addCode, singleQuoteArray, objectHasValues, toSnakeCase, columnDefaultArgumentToCode, columnErrorMessagesToCode, setObjectValueImmutable, getValueKey, addValue, isExpression, dateDataToCode, joinTruthy, arrayDataToCode, numberDataToCode, noop, stringDataToCode, getDefaultLanguage, pushOrNewArrayToObjectImmutable, logColors, applyTransforms, callWithThis, setParserToQuery, pushOrNewArray, isRawSQL, returnArg as returnArg$1, setDefaultNowFn, setDefaultLanguage, setCurrentColumnName, makeTimestampsHelpers, setAdapterConnectRetry, isObjectEmpty, ValExpression, applyMixins, snakeCaseKey } from 'orchid-core';
2
2
  import pg from 'pg';
3
3
  import { inspect } from 'node:util';
4
4
  import { AsyncLocalStorage } from 'node:async_hooks';
@@ -925,20 +925,33 @@ const getSqlText = (sql) => {
925
925
  };
926
926
 
927
927
  class CustomTypeColumn extends ColumnType {
928
- constructor(schema, dataType, extension) {
928
+ constructor(schema, typeName, typeSchema, extension) {
929
929
  super(
930
930
  schema,
931
931
  schema.unknown(),
932
932
  schema.unknown(),
933
933
  schema.unknown()
934
934
  );
935
- this.dataType = dataType;
935
+ this.typeName = typeName;
936
+ this.typeSchema = typeSchema;
936
937
  this.operators = Operators.any;
938
+ this.dataType = typeSchema ? typeSchema + "." + typeName : typeName;
937
939
  this.data.isOfCustomType = true;
938
940
  this.data.extension = extension;
939
941
  }
940
942
  toCode(ctx, key) {
941
- return columnCode(this, ctx, key, `type(${singleQuote(this.dataType)})`);
943
+ const {
944
+ dataType,
945
+ data: { typmod }
946
+ } = this;
947
+ return columnCode(
948
+ this,
949
+ ctx,
950
+ key,
951
+ `type(${singleQuote(
952
+ (dataType.startsWith(ctx.currentSchema) ? dataType.slice(ctx.currentSchema.length + 1) : dataType) + (typmod !== void 0 && typmod !== -1 && !dataType.includes("(") ? `(${typmod})` : "")
953
+ )})`
954
+ );
942
955
  }
943
956
  as(column) {
944
957
  const c = setColumnData(
@@ -1272,1507 +1285,1522 @@ const Operators = {
1272
1285
  array
1273
1286
  };
1274
1287
 
1275
- class TextBaseColumn extends ColumnType {
1276
- constructor(schema, schemaType = schema.stringSchema()) {
1277
- super(schema, schemaType);
1278
- this.operators = Operators.text;
1279
- }
1280
- }
1281
- class LimitedTextBaseColumn extends TextBaseColumn {
1282
- constructor(schema, limit) {
1288
+ const dateTimeEncode = (input) => {
1289
+ return typeof input === "number" ? new Date(input) : input;
1290
+ };
1291
+ class DateBaseColumn extends ColumnType {
1292
+ constructor(schema) {
1283
1293
  super(
1284
1294
  schema,
1285
- limit !== void 0 ? schema.stringMax(limit) : schema.stringSchema()
1286
- );
1287
- this.data.maxChars = limit;
1288
- }
1289
- toSQL() {
1290
- return joinTruthy(
1291
- this.dataType,
1292
- this.data.maxChars !== void 0 && `(${this.data.maxChars})`
1295
+ schema.stringNumberDate(),
1296
+ schema.stringSchema(),
1297
+ schema.stringNumberDate()
1293
1298
  );
1299
+ this.operators = Operators.date;
1300
+ this.asNumber = schema.dateAsNumber;
1301
+ this.asDate = schema.dateAsDate;
1302
+ this.data.encode = dateTimeEncode;
1294
1303
  }
1295
1304
  }
1296
- class VarCharColumn extends LimitedTextBaseColumn {
1305
+ class DateColumn extends DateBaseColumn {
1297
1306
  constructor() {
1298
1307
  super(...arguments);
1299
- this.dataType = "varchar";
1308
+ this.dataType = "date";
1300
1309
  }
1301
1310
  toCode(ctx, key) {
1302
- const { maxChars } = this.data;
1303
1311
  return columnCode(
1304
1312
  this,
1305
1313
  ctx,
1306
1314
  key,
1307
- `varchar(${maxChars ?? ""})${stringDataToCode(this.data, ctx.migration)}`
1315
+ `date()${dateDataToCode(this.data, ctx.migration)}`
1308
1316
  );
1309
1317
  }
1310
1318
  }
1311
- class StringColumn extends VarCharColumn {
1312
- constructor(schema, limit = 255) {
1313
- super(schema, limit);
1319
+ class DateTimeBaseClass extends DateBaseColumn {
1320
+ constructor(schema, dateTimePrecision) {
1321
+ super(schema);
1322
+ this.data.dateTimePrecision = dateTimePrecision;
1314
1323
  }
1315
- toCode(ctx, key) {
1316
- let max = this.data.maxChars;
1317
- if (max === 255) max = void 0;
1324
+ toSQL() {
1325
+ return joinTruthy(
1326
+ this.dataType,
1327
+ this.data.dateTimePrecision !== void 0 && `(${this.data.dateTimePrecision})`
1328
+ );
1329
+ }
1330
+ }
1331
+ class DateTimeTzBaseClass extends DateTimeBaseClass {
1332
+ toSQL() {
1333
+ return joinTruthy(
1334
+ this.baseDataType,
1335
+ this.data.dateTimePrecision !== void 0 && `(${this.data.dateTimePrecision})`,
1336
+ " with time zone"
1337
+ );
1338
+ }
1339
+ }
1340
+ const timestampToCode = (self, ctx, key) => {
1341
+ const { dateTimePrecision: p } = self.data;
1342
+ const { defaultTimestamp } = self.data;
1343
+ if (defaultTimestamp) {
1344
+ const noTz = self instanceof TimestampColumn ? "NoTZ" : "";
1345
+ const def = self.data.default;
1346
+ const modifyQuery = self.data.modifyQuery;
1347
+ self.data.default = void 0;
1348
+ self.data.modifyQuery = void 0;
1349
+ const code = columnCode(
1350
+ self,
1351
+ ctx,
1352
+ key,
1353
+ `timestamps${noTz}(${p && p !== 6 ? p : ""}).${defaultTimestamp}${dateDataToCode(self.data, ctx.migration)}`
1354
+ );
1355
+ self.data.default = def;
1356
+ self.data.modifyQuery = modifyQuery;
1357
+ return code;
1358
+ } else {
1318
1359
  return columnCode(
1319
- this,
1360
+ self,
1320
1361
  ctx,
1321
1362
  key,
1322
- `string(${max ?? ""})${stringDataToCode(this.data, ctx.migration)}`
1363
+ `${self instanceof TimestampColumn ? "timestampNoTZ" : "timestamp"}(${p && p !== 6 ? p : ""})${dateDataToCode(self.data, ctx.migration)}`
1323
1364
  );
1324
1365
  }
1325
- }
1326
- const textColumnToCode = (column, ctx, key) => {
1327
- const data = { ...column.data };
1328
- let args = "";
1329
- const hasMax = data.maxArg !== void 0 && data.max === data.maxArg;
1330
- if (data.minArg !== void 0 && data.min === data.minArg || hasMax) {
1331
- if (data.minArg !== 0 || hasMax && data.max !== Infinity) {
1332
- args += data.minArg;
1333
- }
1334
- delete data.min;
1335
- if (hasMax) {
1336
- if (data.maxArg !== Infinity) {
1337
- args += `, ${data.maxArg}`;
1338
- }
1339
- delete data.max;
1340
- }
1341
- }
1342
- return columnCode(
1343
- column,
1344
- ctx,
1345
- key,
1346
- `${column.dataType}(${args})${stringDataToCode(data, ctx.migration)}`
1347
- );
1348
1366
  };
1349
- class TextColumn extends TextBaseColumn {
1350
- constructor(schema) {
1351
- super(schema, schema.stringSchema());
1352
- this.dataType = "text";
1367
+ class TimestampColumn extends DateTimeBaseClass {
1368
+ constructor() {
1369
+ super(...arguments);
1370
+ this.dataType = "timestamp";
1353
1371
  }
1354
1372
  toCode(ctx, key) {
1355
- return textColumnToCode(this, ctx, key);
1373
+ return timestampToCode(this, ctx, key);
1356
1374
  }
1357
1375
  }
1358
- const byteaParse = (val) => typeof val === "string" ? Buffer.from(val.slice(2), "hex") : val;
1359
- class ByteaColumn extends ColumnType {
1360
- constructor(schema) {
1361
- super(schema, schema.buffer());
1362
- this.dataType = "bytea";
1363
- this.operators = Operators.text;
1364
- setColumnDefaultParse(this, byteaParse);
1376
+ class TimestampTZColumn extends DateTimeTzBaseClass {
1377
+ constructor() {
1378
+ super(...arguments);
1379
+ this.dataType = "timestamptz";
1380
+ this.baseDataType = "timestamp";
1365
1381
  }
1366
1382
  toCode(ctx, key) {
1367
- return columnCode(this, ctx, key, `bytea()`);
1383
+ return timestampToCode(this, ctx, key);
1368
1384
  }
1369
1385
  }
1370
- class PointColumn extends ColumnType {
1371
- constructor(schema) {
1386
+ class TimeColumn extends ColumnType {
1387
+ constructor(schema, dateTimePrecision) {
1372
1388
  super(schema, schema.stringSchema());
1373
- this.dataType = "point";
1374
- this.operators = Operators.text;
1389
+ this.dataType = "time";
1390
+ this.operators = Operators.time;
1391
+ this.data.dateTimePrecision = dateTimePrecision;
1375
1392
  }
1376
1393
  toCode(ctx, key) {
1377
- return columnCode(this, ctx, key, `point()`);
1394
+ const { dateTimePrecision } = this.data;
1395
+ return columnCode(
1396
+ this,
1397
+ ctx,
1398
+ key,
1399
+ `time(${dateTimePrecision || ""})${dateDataToCode(
1400
+ this.data,
1401
+ ctx.migration
1402
+ )}`
1403
+ );
1378
1404
  }
1379
1405
  }
1380
- class LineColumn extends ColumnType {
1381
- constructor(schema) {
1382
- super(schema, schema.stringSchema());
1383
- this.dataType = "line";
1384
- this.operators = Operators.text;
1406
+ class IntervalColumn extends ColumnType {
1407
+ constructor(schema, fields, precision) {
1408
+ super(schema, schema.timeInterval());
1409
+ this.dataType = "interval";
1410
+ this.operators = Operators.date;
1411
+ this.data.fields = fields;
1412
+ this.data.precision = precision;
1385
1413
  }
1386
1414
  toCode(ctx, key) {
1387
- return columnCode(this, ctx, key, `line()`);
1388
- }
1389
- }
1390
- class LsegColumn extends ColumnType {
1391
- constructor(schema) {
1392
- super(schema, schema.stringSchema());
1393
- this.dataType = "lseg";
1394
- this.operators = Operators.text;
1415
+ const { fields, precision } = this.data;
1416
+ return columnCode(
1417
+ this,
1418
+ ctx,
1419
+ key,
1420
+ `interval(${[fields && `'${fields}'`, precision && String(precision)].filter((part) => part).join(", ")})`
1421
+ );
1395
1422
  }
1396
- toCode(ctx, key) {
1397
- return columnCode(this, ctx, key, `lseg()`);
1423
+ toSQL() {
1424
+ return joinTruthy(
1425
+ this.dataType,
1426
+ this.data.fields && ` ${this.data.fields}`,
1427
+ this.data.precision !== void 0 && ` (${this.data.precision})`
1428
+ );
1398
1429
  }
1399
1430
  }
1400
- class BoxColumn extends ColumnType {
1401
- constructor(schema) {
1402
- super(schema, schema.stringSchema());
1403
- this.dataType = "box";
1404
- this.operators = Operators.text;
1405
- }
1406
- toCode(ctx, key) {
1407
- return columnCode(this, ctx, key, `box()`);
1431
+
1432
+ class ArrayColumn extends ColumnType {
1433
+ constructor(schema, item, inputType, outputType, queryType) {
1434
+ super(schema, inputType, outputType, queryType);
1435
+ this.dataType = "array";
1436
+ this.operators = Operators.array;
1437
+ item.data.isNullable = true;
1438
+ setColumnDefaultParse(this, (input) => parse$1.call(this, input));
1439
+ this.data.item = item instanceof ArrayColumn ? item.data.item : item;
1440
+ this.data.name = item.data.name;
1441
+ this.data.arrayDims = item instanceof ArrayColumn ? item.data.arrayDims + 1 : 1;
1408
1442
  }
1409
- }
1410
- class PathColumn extends ColumnType {
1411
- constructor(schema) {
1412
- super(schema, schema.stringSchema());
1413
- this.dataType = "path";
1414
- this.operators = Operators.text;
1443
+ toSQL() {
1444
+ return this.data.item.toSQL() + "[]".repeat(this.data.arrayDims);
1415
1445
  }
1416
1446
  toCode(ctx, key) {
1417
- return columnCode(this, ctx, key, `path()`);
1447
+ let open = "array(";
1448
+ let close = ")";
1449
+ for (let i = 1; i < this.data.arrayDims; i++) {
1450
+ open += `${ctx.t}.array(`;
1451
+ close += ")";
1452
+ }
1453
+ const code = [open];
1454
+ const { item } = this.data;
1455
+ const { isNullable } = item.data;
1456
+ delete item.data.isNullable;
1457
+ addCode(code, item.toCode(ctx, key));
1458
+ item.data.isNullable = isNullable;
1459
+ addCode(code, `${close}${arrayDataToCode(this.data, ctx.migration)}`);
1460
+ return columnCode(this, ctx, key, code);
1418
1461
  }
1419
1462
  }
1420
- class PolygonColumn extends ColumnType {
1421
- constructor(schema) {
1422
- super(schema, schema.stringSchema());
1423
- this.dataType = "polygon";
1424
- this.operators = Operators.text;
1425
- }
1426
- toCode(ctx, key) {
1427
- return columnCode(this, ctx, key, `polygon()`);
1463
+ const parse$1 = function(source) {
1464
+ if (typeof source !== "string") return source;
1465
+ const entries = [];
1466
+ parsePostgresArray(source, entries, this.data.item.data.parseItem);
1467
+ return entries;
1468
+ };
1469
+ const parsePostgresArray = (source, entries, transform) => {
1470
+ let pos = 0;
1471
+ if (source[0] === "[") {
1472
+ pos = source.indexOf("=") + 1;
1473
+ if (!pos) pos = source.length;
1428
1474
  }
1429
- }
1430
- class CircleColumn extends ColumnType {
1431
- constructor(schema) {
1432
- super(schema, schema.stringSchema());
1433
- this.dataType = "circle";
1434
- this.operators = Operators.text;
1475
+ if (source[pos] === "{") pos++;
1476
+ let recorded = "";
1477
+ while (pos < source.length) {
1478
+ const character = source[pos++];
1479
+ if (character === "{") {
1480
+ const innerEntries = [];
1481
+ entries.push(innerEntries);
1482
+ pos += parsePostgresArray(source.slice(pos - 1), innerEntries, transform) - 1;
1483
+ } else if (character === "}") {
1484
+ if (recorded) {
1485
+ entries.push(
1486
+ recorded === "NULL" ? null : transform ? transform(recorded) : recorded
1487
+ );
1488
+ }
1489
+ return pos;
1490
+ } else if (character === '"') {
1491
+ let esc = false;
1492
+ let rec = "";
1493
+ while (pos < source.length) {
1494
+ let char;
1495
+ while ((char = source[pos++]) === "\\") {
1496
+ if (!(esc = !esc)) rec += "\\";
1497
+ }
1498
+ if (esc) {
1499
+ esc = false;
1500
+ } else if (char === '"') {
1501
+ break;
1502
+ }
1503
+ rec += char;
1504
+ }
1505
+ entries.push(transform ? transform(rec) : rec);
1506
+ recorded = "";
1507
+ } else if (character === ",") {
1508
+ if (recorded) {
1509
+ entries.push(
1510
+ recorded === "NULL" ? null : transform ? transform(recorded) : recorded
1511
+ );
1512
+ recorded = "";
1513
+ }
1514
+ } else {
1515
+ recorded += character;
1516
+ }
1517
+ }
1518
+ return pos;
1519
+ };
1520
+
1521
+ const encode$1 = (x) => x === null ? x : JSON.stringify(x);
1522
+ class JSONColumn extends ColumnType {
1523
+ constructor(schema, inputType) {
1524
+ super(schema, inputType);
1525
+ this.dataType = "jsonb";
1526
+ this.operators = Operators.json;
1527
+ this.data.encode = encode$1;
1528
+ this.data.parseItem = JSON.parse;
1435
1529
  }
1436
1530
  toCode(ctx, key) {
1437
- return columnCode(this, ctx, key, `circle()`);
1531
+ return columnCode(this, ctx, key, `json()`);
1438
1532
  }
1439
1533
  }
1440
- class MoneyColumn extends ColumnType {
1534
+ class JSONTextColumn extends ColumnType {
1441
1535
  constructor(schema) {
1442
- super(schema, schema.number());
1443
- this.dataType = "money";
1444
- this.operators = Operators.number;
1445
- setColumnDefaultParse(this, moneyParse);
1536
+ super(schema, schema.stringSchema());
1537
+ this.dataType = "json";
1538
+ this.operators = Operators.text;
1539
+ }
1540
+ static get instance() {
1541
+ return this._instance ?? (this._instance = new JSONTextColumn(defaultSchemaConfig));
1446
1542
  }
1447
1543
  toCode(ctx, key) {
1448
- return columnCode(this, ctx, key, `money()`);
1544
+ return columnCode(this, ctx, key, `jsonText()`);
1449
1545
  }
1450
1546
  }
1451
- const moneyParse = Object.assign(
1452
- function(input) {
1453
- return input === null ? input : parseFloat(input.replace(/,/g, "").replace(/\$/g, ""));
1454
- },
1455
- {
1456
- hideFromCode: true
1547
+
1548
+ class NumberBaseColumn extends ColumnType {
1549
+ constructor() {
1550
+ super(...arguments);
1551
+ this.operators = Operators.number;
1457
1552
  }
1458
- );
1459
- class CidrColumn extends ColumnType {
1553
+ }
1554
+ class IntegerBaseColumn extends NumberBaseColumn {
1555
+ constructor(schema) {
1556
+ super(schema, schema.int());
1557
+ this.data.int = true;
1558
+ }
1559
+ }
1560
+ class NumberAsStringBaseColumn extends ColumnType {
1460
1561
  constructor(schema) {
1461
1562
  super(schema, schema.stringSchema());
1462
- this.dataType = "cidr";
1463
- this.operators = Operators.text;
1563
+ this.operators = Operators.number;
1564
+ this.data.jsonCast = "text";
1565
+ }
1566
+ }
1567
+ class DecimalColumn extends NumberAsStringBaseColumn {
1568
+ constructor(schema, numericPrecision, numericScale) {
1569
+ super(schema);
1570
+ this.operators = Operators.number;
1571
+ this.dataType = "numeric";
1572
+ this.data.numericPrecision = numericPrecision;
1573
+ this.data.numericScale = numericScale;
1574
+ this.data.alias = "decimal";
1464
1575
  }
1465
1576
  toCode(ctx, key) {
1466
- return columnCode(this, ctx, key, `cidr()`);
1577
+ const { numericPrecision, numericScale } = this.data;
1578
+ return columnCode(
1579
+ this,
1580
+ ctx,
1581
+ key,
1582
+ `decimal(${numericPrecision || ""}${numericScale ? `, ${numericScale}` : ""})`
1583
+ );
1584
+ }
1585
+ toSQL() {
1586
+ const { numericPrecision, numericScale } = this.data;
1587
+ return joinTruthy(
1588
+ this.dataType,
1589
+ numericPrecision ? numericScale ? `(${numericPrecision}, ${numericScale})` : `(${numericPrecision})` : void 0
1590
+ );
1467
1591
  }
1468
1592
  }
1469
- class InetColumn extends ColumnType {
1593
+ const skipNumberMethods = { int: true };
1594
+ const intToCode = (column, ctx, key, alias) => {
1595
+ let code;
1596
+ if (column.data.identity) {
1597
+ code = identityToCode(column.data.identity, alias);
1598
+ } else {
1599
+ code = [`${alias}()`];
1600
+ }
1601
+ addCode(
1602
+ code,
1603
+ numberDataToCode(column.data, ctx.migration, skipNumberMethods)
1604
+ );
1605
+ return columnCode(column, ctx, key, code);
1606
+ };
1607
+ class SmallIntColumn extends IntegerBaseColumn {
1470
1608
  constructor(schema) {
1471
- super(schema, schema.stringSchema());
1472
- this.dataType = "inet";
1473
- this.operators = Operators.text;
1609
+ super(schema);
1610
+ this.dataType = "int2";
1611
+ this.data.alias = "smallint";
1612
+ this.data.parseItem = parseInt;
1474
1613
  }
1475
1614
  toCode(ctx, key) {
1476
- return columnCode(this, ctx, key, `inet()`);
1615
+ return intToCode(this, ctx, key, "smallint");
1616
+ }
1617
+ identity(options = {}) {
1618
+ return setColumnData(this, "identity", options);
1477
1619
  }
1478
1620
  }
1479
- class MacAddrColumn extends ColumnType {
1621
+ class IntegerColumn extends IntegerBaseColumn {
1480
1622
  constructor(schema) {
1481
- super(schema, schema.stringSchema());
1482
- this.dataType = "macaddr";
1483
- this.operators = Operators.text;
1623
+ super(schema);
1624
+ this.dataType = "int4";
1625
+ this.data.alias = "integer";
1626
+ this.data.parseItem = parseInt;
1484
1627
  }
1485
1628
  toCode(ctx, key) {
1486
- return columnCode(this, ctx, key, `macaddr()`);
1629
+ return intToCode(this, ctx, key, "integer");
1630
+ }
1631
+ identity(options = {}) {
1632
+ return setColumnData(this, "identity", options);
1487
1633
  }
1488
1634
  }
1489
- class MacAddr8Column extends ColumnType {
1635
+ class BigIntColumn extends NumberAsStringBaseColumn {
1490
1636
  constructor(schema) {
1491
- super(schema, schema.stringSchema());
1492
- this.dataType = "macaddr8";
1493
- this.operators = Operators.text;
1637
+ super(schema);
1638
+ this.dataType = "int8";
1639
+ this.data.alias = "bigint";
1494
1640
  }
1495
1641
  toCode(ctx, key) {
1496
- return columnCode(this, ctx, key, `macaddr8()`);
1642
+ return intToCode(this, ctx, key, "bigint");
1643
+ }
1644
+ identity(options = {}) {
1645
+ return setColumnData(this, "identity", options);
1497
1646
  }
1498
1647
  }
1499
- class BitColumn extends ColumnType {
1500
- constructor(schema, length) {
1501
- super(schema, schema.bit(length));
1502
- this.dataType = "bit";
1503
- this.operators = Operators.text;
1504
- this.data.length = length;
1648
+ class RealColumn extends NumberBaseColumn {
1649
+ constructor(schema) {
1650
+ super(schema, schema.number());
1651
+ this.dataType = "float4";
1652
+ this.data.alias = "real";
1653
+ this.data.parseItem = parseFloat;
1505
1654
  }
1506
1655
  toCode(ctx, key) {
1507
- const { length } = this.data;
1508
- return columnCode(this, ctx, key, `bit(${length})`);
1509
- }
1510
- toSQL() {
1511
- return joinTruthy(
1512
- this.dataType,
1513
- this.data.length !== void 0 && `(${this.data.length})`
1656
+ return columnCode(
1657
+ this,
1658
+ ctx,
1659
+ key,
1660
+ `real()${numberDataToCode(this.data, ctx.migration)}`
1514
1661
  );
1515
1662
  }
1516
1663
  }
1517
- class BitVaryingColumn extends ColumnType {
1518
- constructor(schema, length) {
1519
- super(schema, schema.bit(length));
1520
- this.dataType = "varbit";
1521
- this.operators = Operators.text;
1522
- this.data.length = length;
1523
- this.data.alias = "bitVarying";
1664
+ class DoublePrecisionColumn extends NumberAsStringBaseColumn {
1665
+ constructor(schema) {
1666
+ super(schema);
1667
+ this.dataType = "float8";
1668
+ this.data.alias = "doublePrecision";
1524
1669
  }
1525
1670
  toCode(ctx, key) {
1526
- const { length } = this.data;
1527
- return columnCode(this, ctx, key, `bitVarying(${length ?? ""})`);
1671
+ return columnCode(this, ctx, key, `doublePrecision()`);
1672
+ }
1673
+ }
1674
+ class SmallSerialColumn extends IntegerBaseColumn {
1675
+ constructor(schema) {
1676
+ super(schema);
1677
+ this.dataType = "int2";
1678
+ this.data.int = true;
1679
+ this.data.alias = "smallSerial";
1680
+ this.data.parseItem = parseInt;
1528
1681
  }
1529
1682
  toSQL() {
1530
- return joinTruthy(
1531
- this.dataType,
1532
- this.data.length !== void 0 && `(${this.data.length})`
1683
+ return "smallserial";
1684
+ }
1685
+ toCode(ctx, key) {
1686
+ return columnCode(
1687
+ this,
1688
+ ctx,
1689
+ key,
1690
+ `smallSerial()${numberDataToCode(
1691
+ this.data,
1692
+ ctx.migration,
1693
+ skipNumberMethods
1694
+ )}`
1533
1695
  );
1534
1696
  }
1535
1697
  }
1536
- class TsVectorColumn extends ColumnType {
1537
- constructor(schema, defaultLanguage = getDefaultLanguage()) {
1538
- super(schema, schema.stringSchema());
1539
- this.defaultLanguage = defaultLanguage;
1540
- this.dataType = "tsvector";
1541
- this.operators = Operators.text;
1698
+ class SerialColumn extends IntegerBaseColumn {
1699
+ constructor(schema) {
1700
+ super(schema);
1701
+ this.dataType = "int4";
1702
+ this.data.int = true;
1703
+ this.data.alias = "serial";
1704
+ this.data.parseItem = parseInt;
1542
1705
  }
1543
- toCode(ctx, key) {
1544
- return columnCode(this, ctx, key, `tsvector()`);
1545
- }
1546
- /**
1547
- * For `tsvector` column type, it can also accept language (optional) and columns:
1548
- *
1549
- * ```ts
1550
- * import { change } from '../dbScript';
1551
- *
1552
- * change(async (db) => {
1553
- * await db.createTable('post', (t) => ({
1554
- * id: t.id(),
1555
- * title: t.text(),
1556
- * body: t.text(),
1557
- * // join title and body into a single ts_vector
1558
- * generatedTsVector: t.tsvector().generated(['title', 'body']).searchIndex(),
1559
- * // with language:
1560
- * spanishTsVector: t
1561
- * .tsvector()
1562
- * .generated('spanish', ['title', 'body'])
1563
- * .searchIndex(),
1564
- * }));
1565
- * });
1566
- * ```
1567
- *
1568
- * @param args
1569
- */
1570
- generated(...args) {
1571
- const arg = args[0];
1572
- if (typeof arg === "object" && "raw" in arg) {
1573
- return super.generated(...args);
1574
- }
1575
- const toSQL = (ctx) => {
1576
- const first = args[0];
1577
- const target = typeof first === "string" ? args[1] : first;
1578
- const language = typeof first === "string" ? first : this.defaultLanguage;
1579
- const { snakeCase } = ctx;
1580
- let sql;
1581
- if (Array.isArray(target)) {
1582
- const columns = target.length === 1 ? `"${snakeCase ? toSnakeCase(target[0]) : target[0]}"` : target.map(
1583
- (column2) => `coalesce("${snakeCase ? toSnakeCase(column2) : column2}", '')`
1584
- ).join(` || ' ' || `);
1585
- sql = `to_tsvector('${language}', ${columns})`;
1586
- } else {
1587
- for (const key in target) {
1588
- sql = (sql ? sql + " || " : "(") + `setweight(to_tsvector('${language}', coalesce("${snakeCase ? toSnakeCase(key) : key}", '')), '${target[key]}')`;
1589
- }
1590
- if (sql) {
1591
- sql += ")";
1592
- } else {
1593
- throw new Error("Empty target in the text search generated column");
1594
- }
1595
- }
1596
- return sql;
1597
- };
1598
- const toCode = () => {
1599
- let code = ".generated(";
1600
- const first = args[0];
1601
- let target;
1602
- if (typeof first === "string") {
1603
- code += `'${first}', `;
1604
- target = args[1];
1605
- } else {
1606
- target = args[0];
1607
- }
1608
- if (Array.isArray(target)) {
1609
- code += `[${target.map((x) => `'${x}'`).join(", ")}]`;
1610
- } else {
1611
- const pairs = [];
1612
- for (const key in target) {
1613
- pairs.push(
1614
- `${quoteObjectKey(key)}: '${target[key]}'`
1615
- );
1616
- }
1617
- code += `{ ${pairs.join(", ")} }`;
1618
- }
1619
- return code + ")";
1620
- };
1621
- const column = setColumnData(this, "generated", {
1622
- toSQL,
1623
- toCode
1624
- });
1625
- column.data.readonly = true;
1626
- return column;
1627
- }
1628
- }
1629
- class TsQueryColumn extends ColumnType {
1630
- constructor(schema) {
1631
- super(schema, schema.stringSchema());
1632
- this.dataType = "tsquery";
1633
- this.operators = Operators.text;
1706
+ toSQL() {
1707
+ return "serial";
1634
1708
  }
1635
1709
  toCode(ctx, key) {
1636
- return columnCode(this, ctx, key, `tsquery()`);
1710
+ return columnCode(
1711
+ this,
1712
+ ctx,
1713
+ key,
1714
+ `serial()${numberDataToCode(
1715
+ this.data,
1716
+ ctx.migration,
1717
+ skipNumberMethods
1718
+ )}`
1719
+ );
1637
1720
  }
1638
1721
  }
1639
- const uuidDefaultSQL = "gen_random_uuid()";
1640
- const uuidDefault = new RawSQL(uuidDefaultSQL);
1641
- class UUIDColumn extends ColumnType {
1722
+ class BigSerialColumn extends NumberAsStringBaseColumn {
1642
1723
  constructor(schema) {
1643
- super(schema, schema.uuid());
1644
- this.dataType = "uuid";
1645
- this.operators = Operators.text;
1646
- this.data.defaultDefault = uuidDefault;
1724
+ super(schema);
1725
+ this.dataType = "int8";
1726
+ this.data.alias = "bigint";
1647
1727
  }
1648
- /**
1649
- * see {@link ColumnType.primaryKey}
1650
- */
1651
- primaryKey(name) {
1652
- const column = super.primaryKey(name);
1653
- if (!column.data.default) column.data.default = uuidDefault;
1654
- return column;
1728
+ toSQL() {
1729
+ return "bigserial";
1655
1730
  }
1656
1731
  toCode(ctx, key) {
1657
- return columnCode(this, ctx, key, `uuid()`);
1732
+ return columnCode(this, ctx, key, `bigSerial()`);
1658
1733
  }
1659
1734
  }
1660
- class XMLColumn extends ColumnType {
1661
- constructor(schema) {
1662
- super(schema, schema.stringSchema());
1663
- this.dataType = "xml";
1735
+
1736
+ const parseDateToDate = (value) => new Date(value);
1737
+ const defaultSchemaConfig = {
1738
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1739
+ parse(fn) {
1740
+ return setColumnParse(this, fn);
1741
+ },
1742
+ parseNull(fn) {
1743
+ return setColumnParseNull(this, fn);
1744
+ },
1745
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1746
+ encode(fn) {
1747
+ return setColumnData(this, "encode", fn);
1748
+ },
1749
+ asType() {
1750
+ return this;
1751
+ },
1752
+ dateAsNumber() {
1753
+ return this.parse(Date.parse);
1754
+ },
1755
+ dateAsDate() {
1756
+ return this.parse(parseDateToDate);
1757
+ },
1758
+ enum(dataType, type) {
1759
+ return new EnumColumn(defaultSchemaConfig, dataType, type, void 0);
1760
+ },
1761
+ array(item) {
1762
+ return new ArrayColumn(defaultSchemaConfig, item, void 0);
1763
+ },
1764
+ boolean: noop,
1765
+ buffer: noop,
1766
+ unknown: noop,
1767
+ never: noop,
1768
+ stringSchema: noop,
1769
+ stringMin: noop,
1770
+ stringMax: noop,
1771
+ stringMinMax: noop,
1772
+ number: noop,
1773
+ int: noop,
1774
+ stringNumberDate: noop,
1775
+ timeInterval: noop,
1776
+ bit: noop,
1777
+ uuid: noop,
1778
+ nullable() {
1779
+ return setColumnData(this, "isNullable", true);
1780
+ },
1781
+ json() {
1782
+ return new JSONColumn(defaultSchemaConfig, void 0);
1783
+ },
1784
+ setErrors: noop,
1785
+ smallint: () => new SmallIntColumn(defaultSchemaConfig),
1786
+ integer: () => new IntegerColumn(defaultSchemaConfig),
1787
+ real: () => new RealColumn(defaultSchemaConfig),
1788
+ smallSerial: () => new SmallSerialColumn(defaultSchemaConfig),
1789
+ serial: () => new SerialColumn(defaultSchemaConfig),
1790
+ bigint: () => new BigIntColumn(defaultSchemaConfig),
1791
+ decimal: (precision, scale) => new DecimalColumn(defaultSchemaConfig, precision, scale),
1792
+ doublePrecision: () => new DoublePrecisionColumn(defaultSchemaConfig),
1793
+ bigSerial: () => new BigSerialColumn(defaultSchemaConfig),
1794
+ money: () => new MoneyColumn(defaultSchemaConfig),
1795
+ varchar: (limit) => new VarCharColumn(defaultSchemaConfig, limit),
1796
+ text: () => new TextColumn(defaultSchemaConfig),
1797
+ string: (limit) => new StringColumn(defaultSchemaConfig, limit),
1798
+ citext: () => new CitextColumn(defaultSchemaConfig),
1799
+ date: () => new DateColumn(defaultSchemaConfig),
1800
+ timestampNoTZ: (precision) => new TimestampColumn(defaultSchemaConfig, precision),
1801
+ timestamp: (precision) => new TimestampTZColumn(defaultSchemaConfig, precision),
1802
+ geographyPointSchema: noop
1803
+ };
1804
+
1805
+ class TextBaseColumn extends ColumnType {
1806
+ constructor(schema, schemaType = schema.stringSchema()) {
1807
+ super(schema, schemaType);
1664
1808
  this.operators = Operators.text;
1665
1809
  }
1666
- toCode(ctx, key) {
1667
- return columnCode(this, ctx, key, `xml()`);
1668
- }
1669
- }
1670
- class CitextColumn extends TextBaseColumn {
1671
- constructor(schema) {
1672
- super(schema, schema.stringSchema());
1673
- this.dataType = "citext";
1674
- this.data.extension = "citext";
1675
- }
1676
- toCode(ctx, key) {
1677
- return textColumnToCode(this, ctx, key);
1678
- }
1679
1810
  }
1680
-
1681
- const dateTimeEncode = (input) => {
1682
- return typeof input === "number" ? new Date(input) : input;
1683
- };
1684
- class DateBaseColumn extends ColumnType {
1685
- constructor(schema) {
1811
+ class LimitedTextBaseColumn extends TextBaseColumn {
1812
+ constructor(schema, limit) {
1686
1813
  super(
1687
1814
  schema,
1688
- schema.stringNumberDate(),
1689
- schema.stringSchema(),
1690
- schema.stringNumberDate()
1815
+ limit !== void 0 ? schema.stringMax(limit) : schema.stringSchema()
1816
+ );
1817
+ this.data.maxChars = limit;
1818
+ }
1819
+ toSQL() {
1820
+ return joinTruthy(
1821
+ this.dataType,
1822
+ this.data.maxChars !== void 0 && `(${this.data.maxChars})`
1691
1823
  );
1692
- this.operators = Operators.date;
1693
- this.asNumber = schema.dateAsNumber;
1694
- this.asDate = schema.dateAsDate;
1695
- this.data.encode = dateTimeEncode;
1696
1824
  }
1697
1825
  }
1698
- class DateColumn extends DateBaseColumn {
1826
+ class VarCharColumn extends LimitedTextBaseColumn {
1699
1827
  constructor() {
1700
1828
  super(...arguments);
1701
- this.dataType = "date";
1829
+ this.dataType = "varchar";
1702
1830
  }
1703
1831
  toCode(ctx, key) {
1832
+ const { maxChars } = this.data;
1704
1833
  return columnCode(
1705
1834
  this,
1706
1835
  ctx,
1707
1836
  key,
1708
- `date()${dateDataToCode(this.data, ctx.migration)}`
1837
+ `varchar(${maxChars ?? ""})${stringDataToCode(this.data, ctx.migration)}`
1709
1838
  );
1710
1839
  }
1711
1840
  }
1712
- class DateTimeBaseClass extends DateBaseColumn {
1713
- constructor(schema, dateTimePrecision) {
1714
- super(schema);
1715
- this.data.dateTimePrecision = dateTimePrecision;
1716
- }
1717
- toSQL() {
1718
- return joinTruthy(
1719
- this.dataType,
1720
- this.data.dateTimePrecision !== void 0 && `(${this.data.dateTimePrecision})`
1721
- );
1841
+ class StringColumn extends VarCharColumn {
1842
+ constructor(schema, limit = 255) {
1843
+ super(schema, limit);
1722
1844
  }
1723
- }
1724
- class DateTimeTzBaseClass extends DateTimeBaseClass {
1725
- toSQL() {
1726
- return joinTruthy(
1727
- this.baseDataType,
1728
- this.data.dateTimePrecision !== void 0 && `(${this.data.dateTimePrecision})`,
1729
- " with time zone"
1730
- );
1731
- }
1732
- }
1733
- const timestampToCode = (self, ctx, key) => {
1734
- const { dateTimePrecision: p } = self.data;
1735
- const { defaultTimestamp } = self.data;
1736
- if (defaultTimestamp) {
1737
- const noTz = self instanceof TimestampColumn ? "NoTZ" : "";
1738
- const def = self.data.default;
1739
- const modifyQuery = self.data.modifyQuery;
1740
- self.data.default = void 0;
1741
- self.data.modifyQuery = void 0;
1742
- const code = columnCode(
1743
- self,
1744
- ctx,
1745
- key,
1746
- `timestamps${noTz}(${p && p !== 6 ? p : ""}).${defaultTimestamp}${dateDataToCode(self.data, ctx.migration)}`
1747
- );
1748
- self.data.default = def;
1749
- self.data.modifyQuery = modifyQuery;
1750
- return code;
1751
- } else {
1845
+ toCode(ctx, key) {
1846
+ let max = this.data.maxChars;
1847
+ if (max === 255) max = void 0;
1752
1848
  return columnCode(
1753
- self,
1849
+ this,
1754
1850
  ctx,
1755
1851
  key,
1756
- `${self instanceof TimestampColumn ? "timestampNoTZ" : "timestamp"}(${p && p !== 6 ? p : ""})${dateDataToCode(self.data, ctx.migration)}`
1852
+ `string(${max ?? ""})${stringDataToCode(this.data, ctx.migration)}`
1757
1853
  );
1758
1854
  }
1855
+ }
1856
+ const textColumnToCode = (column, ctx, key) => {
1857
+ const data = { ...column.data };
1858
+ let args = "";
1859
+ const hasMax = data.maxArg !== void 0 && data.max === data.maxArg;
1860
+ if (data.minArg !== void 0 && data.min === data.minArg || hasMax) {
1861
+ if (data.minArg !== 0 || hasMax && data.max !== Infinity) {
1862
+ args += data.minArg;
1863
+ }
1864
+ delete data.min;
1865
+ if (hasMax) {
1866
+ if (data.maxArg !== Infinity) {
1867
+ args += `, ${data.maxArg}`;
1868
+ }
1869
+ delete data.max;
1870
+ }
1871
+ }
1872
+ return columnCode(
1873
+ column,
1874
+ ctx,
1875
+ key,
1876
+ `${column.dataType}(${args})${stringDataToCode(data, ctx.migration)}`
1877
+ );
1759
1878
  };
1760
- class TimestampColumn extends DateTimeBaseClass {
1761
- constructor() {
1762
- super(...arguments);
1763
- this.dataType = "timestamp";
1879
+ class TextColumn extends TextBaseColumn {
1880
+ constructor(schema) {
1881
+ super(schema, schema.stringSchema());
1882
+ this.dataType = "text";
1883
+ }
1884
+ static get instance() {
1885
+ return this._instance ?? (this._instance = new TextColumn(defaultSchemaConfig));
1764
1886
  }
1765
1887
  toCode(ctx, key) {
1766
- return timestampToCode(this, ctx, key);
1888
+ return textColumnToCode(this, ctx, key);
1767
1889
  }
1768
1890
  }
1769
- class TimestampTZColumn extends DateTimeTzBaseClass {
1770
- constructor() {
1771
- super(...arguments);
1772
- this.dataType = "timestamptz";
1773
- this.baseDataType = "timestamp";
1891
+ const byteaParse = (val) => typeof val === "string" ? Buffer.from(val.slice(2), "hex") : val;
1892
+ class ByteaColumn extends ColumnType {
1893
+ constructor(schema) {
1894
+ super(schema, schema.buffer());
1895
+ this.dataType = "bytea";
1896
+ this.operators = Operators.text;
1897
+ setColumnDefaultParse(this, byteaParse);
1774
1898
  }
1775
1899
  toCode(ctx, key) {
1776
- return timestampToCode(this, ctx, key);
1900
+ return columnCode(this, ctx, key, `bytea()`);
1777
1901
  }
1778
1902
  }
1779
- class TimeColumn extends ColumnType {
1780
- constructor(schema, dateTimePrecision) {
1903
+ class PointColumn extends ColumnType {
1904
+ constructor(schema) {
1781
1905
  super(schema, schema.stringSchema());
1782
- this.dataType = "time";
1783
- this.operators = Operators.time;
1784
- this.data.dateTimePrecision = dateTimePrecision;
1906
+ this.dataType = "point";
1907
+ this.operators = Operators.text;
1785
1908
  }
1786
1909
  toCode(ctx, key) {
1787
- const { dateTimePrecision } = this.data;
1788
- return columnCode(
1789
- this,
1790
- ctx,
1791
- key,
1792
- `time(${dateTimePrecision || ""})${dateDataToCode(
1793
- this.data,
1794
- ctx.migration
1795
- )}`
1796
- );
1910
+ return columnCode(this, ctx, key, `point()`);
1797
1911
  }
1798
1912
  }
1799
- class IntervalColumn extends ColumnType {
1800
- constructor(schema, fields, precision) {
1801
- super(schema, schema.timeInterval());
1802
- this.dataType = "interval";
1803
- this.operators = Operators.date;
1804
- this.data.fields = fields;
1805
- this.data.precision = precision;
1913
+ class LineColumn extends ColumnType {
1914
+ constructor(schema) {
1915
+ super(schema, schema.stringSchema());
1916
+ this.dataType = "line";
1917
+ this.operators = Operators.text;
1806
1918
  }
1807
1919
  toCode(ctx, key) {
1808
- const { fields, precision } = this.data;
1809
- return columnCode(
1810
- this,
1811
- ctx,
1812
- key,
1813
- `interval(${[fields && `'${fields}'`, precision && String(precision)].filter((part) => part).join(", ")})`
1814
- );
1815
- }
1816
- toSQL() {
1817
- return joinTruthy(
1818
- this.dataType,
1819
- this.data.fields && ` ${this.data.fields}`,
1820
- this.data.precision !== void 0 && ` (${this.data.precision})`
1821
- );
1920
+ return columnCode(this, ctx, key, `line()`);
1822
1921
  }
1823
1922
  }
1824
-
1825
- class BooleanColumn extends ColumnType {
1923
+ class LsegColumn extends ColumnType {
1826
1924
  constructor(schema) {
1827
- super(schema, schema.boolean());
1828
- this.dataType = "bool";
1829
- this.operators = Operators.boolean;
1830
- this.data.alias = "boolean";
1831
- this.data.parseItem = parseItem;
1925
+ super(schema, schema.stringSchema());
1926
+ this.dataType = "lseg";
1927
+ this.operators = Operators.text;
1832
1928
  }
1833
1929
  toCode(ctx, key) {
1834
- return columnCode(this, ctx, key, "boolean()");
1930
+ return columnCode(this, ctx, key, `lseg()`);
1835
1931
  }
1836
1932
  }
1837
- const parseItem = (input) => input[0] === "t";
1838
-
1839
- const encode$1 = (x) => x === null ? x : JSON.stringify(x);
1840
- class JSONColumn extends ColumnType {
1841
- constructor(schema, inputType) {
1842
- super(schema, inputType);
1843
- this.dataType = "jsonb";
1844
- this.operators = Operators.json;
1845
- this.data.encode = encode$1;
1846
- this.data.parseItem = JSON.parse;
1933
+ class BoxColumn extends ColumnType {
1934
+ constructor(schema) {
1935
+ super(schema, schema.stringSchema());
1936
+ this.dataType = "box";
1937
+ this.operators = Operators.text;
1847
1938
  }
1848
1939
  toCode(ctx, key) {
1849
- return columnCode(this, ctx, key, `json()`);
1940
+ return columnCode(this, ctx, key, `box()`);
1850
1941
  }
1851
1942
  }
1852
- class JSONTextColumn extends ColumnType {
1943
+ class PathColumn extends ColumnType {
1853
1944
  constructor(schema) {
1854
1945
  super(schema, schema.stringSchema());
1855
- this.dataType = "json";
1946
+ this.dataType = "path";
1856
1947
  this.operators = Operators.text;
1857
1948
  }
1858
1949
  toCode(ctx, key) {
1859
- return columnCode(this, ctx, key, `jsonText()`);
1950
+ return columnCode(this, ctx, key, `path()`);
1860
1951
  }
1861
1952
  }
1862
-
1863
- var __typeError = (msg) => {
1864
- throw TypeError(msg);
1865
- };
1866
- var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
1867
- var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
1868
- var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
1869
- var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
1870
- var _query, _query2;
1871
- class OrchidOrmError extends Error {
1872
- }
1873
- class NotFoundError extends OrchidOrmError {
1874
- constructor(query, message = "Record is not found") {
1875
- super(message);
1876
- // `#query` is private to prevent it from serializing to not cause problems to test runner reports
1877
- __privateAdd(this, _query);
1878
- __privateSet(this, _query, query);
1953
+ class PolygonColumn extends ColumnType {
1954
+ constructor(schema) {
1955
+ super(schema, schema.stringSchema());
1956
+ this.dataType = "polygon";
1957
+ this.operators = Operators.text;
1879
1958
  }
1880
- get query() {
1881
- return __privateGet(this, _query);
1959
+ toCode(ctx, key) {
1960
+ return columnCode(this, ctx, key, `polygon()`);
1882
1961
  }
1883
1962
  }
1884
- _query = new WeakMap();
1885
- class OrchidOrmInternalError extends Error {
1886
- constructor(query, message) {
1887
- super(message);
1888
- // `#query` is private to prevent it from serializing to not cause problems to test runner reports
1889
- __privateAdd(this, _query2);
1890
- __privateSet(this, _query2, query);
1963
+ class CircleColumn extends ColumnType {
1964
+ constructor(schema) {
1965
+ super(schema, schema.stringSchema());
1966
+ this.dataType = "circle";
1967
+ this.operators = Operators.text;
1891
1968
  }
1892
- get query() {
1893
- return __privateGet(this, _query2);
1969
+ toCode(ctx, key) {
1970
+ return columnCode(this, ctx, key, `circle()`);
1894
1971
  }
1895
1972
  }
1896
- _query2 = new WeakMap();
1897
- class QueryError extends OrchidOrmInternalError {
1898
- get isUnique() {
1899
- return this.code === "23505";
1973
+ class MoneyColumn extends ColumnType {
1974
+ constructor(schema) {
1975
+ super(schema, schema.number());
1976
+ this.dataType = "money";
1977
+ this.operators = Operators.number;
1978
+ setColumnDefaultParse(this, moneyParse);
1900
1979
  }
1901
- get columns() {
1902
- if (this.columnsCache) return this.columnsCache;
1903
- const columns = {};
1904
- if (this.detail) {
1905
- const list = this.detail.match(/\((.*)\)=/)?.[1];
1906
- if (list) {
1907
- list.split(", ").forEach((item) => {
1908
- const column = item.startsWith('"') ? item.slice(1, -1) : item;
1909
- const key = this.query.columnNameToKey(column) ?? column;
1910
- columns[key] = true;
1911
- });
1912
- }
1913
- }
1914
- return this.columnsCache = columns;
1980
+ toCode(ctx, key) {
1981
+ return columnCode(this, ctx, key, `money()`);
1915
1982
  }
1916
1983
  }
1917
- class MoreThanOneRowError extends OrchidOrmInternalError {
1918
- constructor(query, message) {
1919
- super(query, message);
1984
+ const moneyParse = Object.assign(
1985
+ function(input) {
1986
+ return input === null ? input : parseFloat(input.replace(/,/g, "").replace(/\$/g, ""));
1987
+ },
1988
+ {
1989
+ hideFromCode: true
1920
1990
  }
1921
- }
1922
- class UnhandledTypeError extends OrchidOrmInternalError {
1923
- constructor(query, value) {
1924
- super(query, `Unhandled type: ${JSON.stringify(value)} received`);
1991
+ );
1992
+ class CidrColumn extends ColumnType {
1993
+ constructor(schema) {
1994
+ super(schema, schema.stringSchema());
1995
+ this.dataType = "cidr";
1996
+ this.operators = Operators.text;
1997
+ }
1998
+ toCode(ctx, key) {
1999
+ return columnCode(this, ctx, key, `cidr()`);
1925
2000
  }
1926
2001
  }
1927
-
1928
- const _clone = (q) => q.clone();
1929
- const pushQueryArrayImmutable = (q, key, value) => {
1930
- const arr = q.q[key];
1931
- q.q[key] = arr ? [...arr, ...value] : value;
1932
- return q;
1933
- };
1934
- const pushQueryValueImmutable = (q, key, value) => {
1935
- pushOrNewArrayToObjectImmutable(q.q, key, value);
1936
- return q;
1937
- };
1938
- const setQueryObjectValueImmutable = (q, object, key, value) => {
1939
- q.q[object] = {
1940
- ...q.q[object],
1941
- [key]: value
1942
- };
1943
- return q;
1944
- };
1945
- const throwIfNoWhere = (q, method) => {
1946
- if (!q.q.or && !q.q.and && !q.q.scopes && !q.q.all) {
1947
- throw new OrchidOrmInternalError(
1948
- q,
1949
- `Dangerous ${method} without conditions`
1950
- );
1951
- }
1952
- };
1953
- const throwIfJoinLateral = (q, method) => {
1954
- if (q.q.join?.some(
1955
- (x) => Array.isArray(x) || "s" in x.args && x.args.s
1956
- )) {
1957
- throw new OrchidOrmInternalError(
1958
- q,
1959
- `Cannot join a complex query in ${method}`
1960
- );
2002
+ class InetColumn extends ColumnType {
2003
+ constructor(schema) {
2004
+ super(schema, schema.stringSchema());
2005
+ this.dataType = "inet";
2006
+ this.operators = Operators.text;
1961
2007
  }
1962
- };
1963
- const saveSearchAlias = (q, as, key) => {
1964
- const shapes = q.q[key];
1965
- if (shapes?.[as]) {
1966
- let suffix = 2;
1967
- while (shapes[as = `${as}${suffix}`]) {
1968
- suffix++;
1969
- }
2008
+ toCode(ctx, key) {
2009
+ return columnCode(this, ctx, key, `inet()`);
1970
2010
  }
1971
- setQueryObjectValueImmutable(q, key, as, emptyObject);
1972
- return as;
1973
- };
1974
- const extendQuery = (q, methods) => {
1975
- const base = Object.create(q.baseQuery);
1976
- base.baseQuery = base;
1977
- Object.assign(base, methods);
1978
- const cloned = Object.create(base);
1979
- cloned.q = getClonedQueryData(q.q);
1980
- return cloned;
1981
- };
1982
- const getPrimaryKeys = (q) => {
1983
- var _a;
1984
- return (_a = q.internal).primaryKeys ?? (_a.primaryKeys = collectPrimaryKeys(q));
1985
- };
1986
- const collectPrimaryKeys = (q) => {
1987
- const primaryKeys = [];
1988
- const { shape } = q.q;
1989
- for (const key in shape) {
1990
- if (shape[key].data.primaryKey) {
1991
- primaryKeys.push(key);
1992
- }
2011
+ }
2012
+ class MacAddrColumn extends ColumnType {
2013
+ constructor(schema) {
2014
+ super(schema, schema.stringSchema());
2015
+ this.dataType = "macaddr";
2016
+ this.operators = Operators.text;
1993
2017
  }
1994
- const pkey = q.internal.tableData.primaryKey;
1995
- if (pkey) {
1996
- primaryKeys.push(...pkey.columns);
2018
+ toCode(ctx, key) {
2019
+ return columnCode(this, ctx, key, `macaddr()`);
1997
2020
  }
1998
- return primaryKeys;
1999
- };
2000
- const _queryAll = (q) => {
2001
- q.q.returnType = "all";
2002
- q.q.all = true;
2003
- return q;
2004
- };
2005
- const _queryTake = (query) => {
2006
- const q = query.q;
2007
- switch (q.returnType) {
2008
- case "valueOrThrow":
2009
- case "pluck":
2010
- case "void":
2011
- break;
2012
- case "value": {
2013
- q.returnType = "valueOrThrow";
2014
- break;
2015
- }
2016
- default: {
2017
- q.returnType = "oneOrThrow";
2018
- }
2021
+ }
2022
+ class MacAddr8Column extends ColumnType {
2023
+ constructor(schema) {
2024
+ super(schema, schema.stringSchema());
2025
+ this.dataType = "macaddr8";
2026
+ this.operators = Operators.text;
2019
2027
  }
2020
- return query;
2021
- };
2022
- const _queryTakeOptional = (query) => {
2023
- const q = query.q;
2024
- switch (q.returnType) {
2025
- case "value":
2026
- case "pluck":
2027
- case "void":
2028
- break;
2029
- case "valueOrThrow": {
2030
- q.returnType = "value";
2031
- break;
2032
- }
2033
- default: {
2034
- q.returnType = "one";
2035
- }
2028
+ toCode(ctx, key) {
2029
+ return columnCode(this, ctx, key, `macaddr8()`);
2036
2030
  }
2037
- return query;
2038
- };
2039
- const _queryExec = (q) => {
2040
- q.q.returnType = "void";
2041
- return q;
2042
- };
2043
- const _queryRows = (q) => {
2044
- q.q.returnType = "rows";
2045
- return q;
2046
- };
2047
- const getFullColumnTable = (q, column, index, as) => {
2048
- const table = column.slice(0, index);
2049
- return as && table !== as && q.q.aliases?.[table] === as ? as : table;
2050
- };
2051
-
2052
- function simpleColumnToSQL(ctx, key, column, quotedAs) {
2053
- if (!column) return `"${key}"`;
2054
- const { data } = column;
2055
- return data.computed ? data.computed.toSQL(ctx, quotedAs) : `${quotedAs ? `${quotedAs}.` : ""}"${data.name || key}"`;
2056
- }
2057
- function simpleExistingColumnToSQL(ctx, key, column, quotedAs) {
2058
- const { data } = column;
2059
- return data.computed ? data.computed.toSQL(ctx, quotedAs) : `${quotedAs ? `${quotedAs}.` : ""}"${data.name || key}"`;
2060
2031
  }
2061
- const columnToSql = (ctx, data, shape, column, quotedAs, select) => {
2062
- const index = column.indexOf(".");
2063
- if (index !== -1) {
2064
- return columnWithDotToSql(
2065
- ctx,
2066
- data,
2067
- shape,
2068
- column,
2069
- index,
2070
- quotedAs,
2071
- select
2032
+ class BitColumn extends ColumnType {
2033
+ constructor(schema, length) {
2034
+ super(schema, schema.bit(length));
2035
+ this.dataType = "bit";
2036
+ this.operators = Operators.text;
2037
+ this.data.length = length;
2038
+ }
2039
+ toCode(ctx, key) {
2040
+ const { length } = this.data;
2041
+ return columnCode(this, ctx, key, `bit(${length})`);
2042
+ }
2043
+ toSQL() {
2044
+ return joinTruthy(
2045
+ this.dataType,
2046
+ this.data.length !== void 0 && `(${this.data.length})`
2072
2047
  );
2073
2048
  }
2074
- if (!select && data.joinedShapes?.[column]) {
2075
- return `"${column}".r`;
2049
+ }
2050
+ class BitVaryingColumn extends ColumnType {
2051
+ constructor(schema, length) {
2052
+ super(schema, schema.bit(length));
2053
+ this.dataType = "varbit";
2054
+ this.operators = Operators.text;
2055
+ this.data.length = length;
2056
+ this.data.alias = "bitVarying";
2076
2057
  }
2077
- return simpleColumnToSQL(ctx, column, shape[column], quotedAs);
2078
- };
2079
- const maybeSelectedColumnToSql = (ctx, data, column, quotedAs) => {
2080
- const index = column.indexOf(".");
2081
- if (index !== -1) {
2082
- return columnWithDotToSql(ctx, data, data.shape, column, index, quotedAs);
2083
- } else {
2084
- if (data.joinedShapes?.[column]) {
2085
- return `"${column}".r`;
2086
- }
2087
- if (data.select) {
2088
- for (const s of data.select) {
2089
- if (typeof s === "object" && "selectAs" in s) {
2090
- if (column in s.selectAs) {
2091
- return simpleColumnToSQL(ctx, column, data.shape[column]);
2092
- }
2093
- }
2094
- }
2095
- }
2096
- return simpleColumnToSQL(ctx, column, data.shape[column], quotedAs);
2058
+ toCode(ctx, key) {
2059
+ const { length } = this.data;
2060
+ return columnCode(this, ctx, key, `bitVarying(${length ?? ""})`);
2097
2061
  }
2098
- };
2099
- const columnWithDotToSql = (ctx, data, shape, column, index, quotedAs, select) => {
2100
- const table = column.slice(0, index);
2101
- const key = column.slice(index + 1);
2102
- if (key === "*") {
2103
- const shape2 = data.joinedShapes?.[table];
2104
- return shape2 ? select ? makeRowToJson(table, shape2, true) : `"${table}".*` : column;
2062
+ toSQL() {
2063
+ return joinTruthy(
2064
+ this.dataType,
2065
+ this.data.length !== void 0 && `(${this.data.length})`
2066
+ );
2105
2067
  }
2106
- const tableName = data.aliases?.[table] || table;
2107
- const quoted = `"${table}"`;
2108
- const col = quoted === quotedAs ? shape[key] : data.joinedShapes?.[tableName]?.[key];
2109
- if (col) {
2110
- if (col.data.name) {
2111
- return `"${tableName}"."${col.data.name}"`;
2112
- }
2113
- if (col.data.computed) {
2114
- return col.data.computed.toSQL(ctx, quoted);
2115
- }
2116
- return `"${tableName}"."${key}"`;
2068
+ }
2069
+ class TsVectorColumn extends ColumnType {
2070
+ constructor(schema, defaultLanguage = getDefaultLanguage()) {
2071
+ super(schema, schema.stringSchema());
2072
+ this.defaultLanguage = defaultLanguage;
2073
+ this.dataType = "tsvector";
2074
+ this.operators = Operators.text;
2117
2075
  }
2118
- return `"${tableName}"."${key}"`;
2119
- };
2120
- const columnToSqlWithAs = (ctx, data, column, as, quotedAs, select, jsonList) => {
2121
- const index = column.indexOf(".");
2122
- return index !== -1 ? tableColumnToSqlWithAs(
2123
- ctx,
2124
- data,
2125
- column,
2126
- column.slice(0, index),
2127
- column.slice(index + 1),
2128
- as,
2129
- quotedAs,
2130
- select,
2131
- jsonList
2132
- ) : ownColumnToSqlWithAs(ctx, data, column, as, quotedAs, select, jsonList);
2133
- };
2134
- const tableColumnToSqlWithAs = (ctx, data, column, table, key, as, quotedAs, select, jsonList) => {
2135
- if (key === "*") {
2136
- if (jsonList) jsonList[as] = void 0;
2137
- const shape = data.joinedShapes?.[table];
2138
- if (shape) {
2139
- {
2140
- return makeRowToJson(table, shape, true) + ` "${as}"`;
2141
- }
2076
+ toCode(ctx, key) {
2077
+ return columnCode(this, ctx, key, `tsvector()`);
2078
+ }
2079
+ /**
2080
+ * For `tsvector` column type, it can also accept language (optional) and columns:
2081
+ *
2082
+ * ```ts
2083
+ * import { change } from '../dbScript';
2084
+ *
2085
+ * change(async (db) => {
2086
+ * await db.createTable('post', (t) => ({
2087
+ * id: t.id(),
2088
+ * title: t.text(),
2089
+ * body: t.text(),
2090
+ * // join title and body into a single ts_vector
2091
+ * generatedTsVector: t.tsvector().generated(['title', 'body']).searchIndex(),
2092
+ * // with language:
2093
+ * spanishTsVector: t
2094
+ * .tsvector()
2095
+ * .generated('spanish', ['title', 'body'])
2096
+ * .searchIndex(),
2097
+ * }));
2098
+ * });
2099
+ * ```
2100
+ *
2101
+ * @param args
2102
+ */
2103
+ generated(...args) {
2104
+ const arg = args[0];
2105
+ if (typeof arg === "object" && "raw" in arg) {
2106
+ return super.generated(...args);
2142
2107
  }
2108
+ const toSQL = (ctx) => {
2109
+ const first = args[0];
2110
+ const target = typeof first === "string" ? args[1] : first;
2111
+ const language = typeof first === "string" ? first : this.defaultLanguage;
2112
+ const { snakeCase } = ctx;
2113
+ let sql;
2114
+ if (Array.isArray(target)) {
2115
+ const columns = target.length === 1 ? `"${snakeCase ? toSnakeCase(target[0]) : target[0]}"` : target.map(
2116
+ (column2) => `coalesce("${snakeCase ? toSnakeCase(column2) : column2}", '')`
2117
+ ).join(` || ' ' || `);
2118
+ sql = `to_tsvector('${language}', ${columns})`;
2119
+ } else {
2120
+ for (const key in target) {
2121
+ sql = (sql ? sql + " || " : "(") + `setweight(to_tsvector('${language}', coalesce("${snakeCase ? toSnakeCase(key) : key}", '')), '${target[key]}')`;
2122
+ }
2123
+ if (sql) {
2124
+ sql += ")";
2125
+ } else {
2126
+ throw new Error("Empty target in the text search generated column");
2127
+ }
2128
+ }
2129
+ return sql;
2130
+ };
2131
+ const toCode = () => {
2132
+ let code = ".generated(";
2133
+ const first = args[0];
2134
+ let target;
2135
+ if (typeof first === "string") {
2136
+ code += `'${first}', `;
2137
+ target = args[1];
2138
+ } else {
2139
+ target = args[0];
2140
+ }
2141
+ if (Array.isArray(target)) {
2142
+ code += `[${target.map((x) => `'${x}'`).join(", ")}]`;
2143
+ } else {
2144
+ const pairs = [];
2145
+ for (const key in target) {
2146
+ pairs.push(
2147
+ `${quoteObjectKey(key)}: '${target[key]}'`
2148
+ );
2149
+ }
2150
+ code += `{ ${pairs.join(", ")} }`;
2151
+ }
2152
+ return code + ")";
2153
+ };
2154
+ const column = setColumnData(this, "generated", {
2155
+ toSQL,
2156
+ toCode
2157
+ });
2158
+ column.data.readonly = true;
2143
2159
  return column;
2144
2160
  }
2145
- const tableName = data.aliases?.[table] || table;
2146
- const quoted = `"${table}"`;
2147
- const col = quoted === quotedAs ? data.shape[key] : data.joinedShapes?.[tableName][key];
2148
- if (jsonList) jsonList[as] = col;
2149
- if (col) {
2150
- if (col.data.name && col.data.name !== key) {
2151
- return `"${tableName}"."${col.data.name}" "${as}"`;
2152
- }
2153
- if (col.data.computed) {
2154
- return `${col.data.computed.toSQL(ctx, quoted)} "${as}"`;
2155
- }
2161
+ }
2162
+ class TsQueryColumn extends ColumnType {
2163
+ constructor(schema) {
2164
+ super(schema, schema.stringSchema());
2165
+ this.dataType = "tsquery";
2166
+ this.operators = Operators.text;
2156
2167
  }
2157
- return `"${tableName}"."${key}"${key === as ? "" : ` "${as}"`}`;
2158
- };
2159
- const ownColumnToSqlWithAs = (ctx, data, column, as, quotedAs, select, jsonList) => {
2160
- const col = data.shape[column];
2161
- if (jsonList) jsonList[as] = col;
2162
- if (col) {
2163
- if (col.data.name && col.data.name !== column) {
2164
- return `${quotedAs ? `${quotedAs}.` : ""}"${col.data.name}"${col.data.name === as ? "" : ` "${as}"`}`;
2165
- }
2166
- if (col.data.computed) {
2167
- return `${col.data.computed.toSQL(ctx, quotedAs)} "${as}"`;
2168
- }
2168
+ toCode(ctx, key) {
2169
+ return columnCode(this, ctx, key, `tsquery()`);
2169
2170
  }
2170
- return `${quotedAs ? `${quotedAs}.` : ""}"${column}"${column === as ? "" : ` "${as}"`}`;
2171
- };
2172
- const rawOrColumnToSql = (ctx, data, expr, quotedAs, shape = data.shape, select) => {
2173
- return typeof expr === "string" ? columnToSql(ctx, data, shape, expr, quotedAs, select) : expr.toSQL(ctx, quotedAs);
2174
- };
2175
- const quoteSchemaAndTable = (schema, table) => {
2176
- return schema ? `"${schema}"."${table}"` : `"${table}"`;
2177
- };
2178
- const makeRowToJson = (table, shape, aliasName) => {
2179
- let isSimple = true;
2180
- const list = [];
2181
- for (const key in shape) {
2182
- const column = shape[key];
2183
- if (column.data.explicitSelect) {
2184
- continue;
2185
- }
2186
- if (aliasName && column.data.name || column.data.jsonCast) {
2187
- isSimple = false;
2188
- }
2189
- list.push(
2190
- `'${key}', "${table}"."${aliasName && column.data.name || key}"${column.data.jsonCast ? `::${column.data.jsonCast}` : ""}`
2191
- );
2171
+ }
2172
+ const uuidDefaultSQL = "gen_random_uuid()";
2173
+ const uuidDefault = new RawSQL(uuidDefaultSQL);
2174
+ class UUIDColumn extends ColumnType {
2175
+ constructor(schema) {
2176
+ super(schema, schema.uuid());
2177
+ this.dataType = "uuid";
2178
+ this.operators = Operators.text;
2179
+ this.data.defaultDefault = uuidDefault;
2192
2180
  }
2193
- return isSimple ? `row_to_json("${table}".*)` : `CASE WHEN "${table}".* IS NULL THEN NULL ELSE json_build_object(` + list.join(", ") + ") END";
2194
- };
2195
-
2196
- const queryTypeWithLimitOne = {
2197
- one: true,
2198
- oneOrThrow: true,
2199
- value: true,
2200
- valueOrThrow: true
2201
- };
2202
- const isQueryReturnsAll = (q) => !q.q.returnType || q.q.returnType === "all";
2203
-
2204
- const pushDistinctSql = (ctx, table, distinct, quotedAs) => {
2205
- ctx.sql.push("DISTINCT");
2206
- if (distinct.length) {
2207
- const columns = distinct?.map(
2208
- (item) => rawOrColumnToSql(ctx, table.q, item, quotedAs)
2209
- );
2210
- ctx.sql.push(`ON (${columns?.join(", ") || ""})`);
2181
+ /**
2182
+ * see {@link ColumnType.primaryKey}
2183
+ */
2184
+ primaryKey(name) {
2185
+ const column = super.primaryKey(name);
2186
+ if (!column.data.default) column.data.default = uuidDefault;
2187
+ return column;
2211
2188
  }
2212
- };
2189
+ toCode(ctx, key) {
2190
+ return columnCode(this, ctx, key, `uuid()`);
2191
+ }
2192
+ }
2193
+ class XMLColumn extends ColumnType {
2194
+ constructor(schema) {
2195
+ super(schema, schema.stringSchema());
2196
+ this.dataType = "xml";
2197
+ this.operators = Operators.text;
2198
+ }
2199
+ static get instance() {
2200
+ return this._instance ?? (this._instance = new XMLColumn(defaultSchemaConfig));
2201
+ }
2202
+ toCode(ctx, key) {
2203
+ return columnCode(this, ctx, key, `xml()`);
2204
+ }
2205
+ }
2206
+ class CitextColumn extends TextBaseColumn {
2207
+ constructor(schema) {
2208
+ super(schema, schema.stringSchema());
2209
+ this.dataType = "citext";
2210
+ this.data.extension = "citext";
2211
+ }
2212
+ toCode(ctx, key) {
2213
+ return textColumnToCode(this, ctx, key);
2214
+ }
2215
+ }
2213
2216
 
2214
- const noneResult = (q, queryData, type) => {
2215
- if (!type || type === "all" || type === "rows" || type === "pluck") {
2216
- return [];
2217
- } else if (type === "one" || type === "value" || type === "void") {
2218
- return queryData.notFoundDefault;
2219
- } else if (type === "valueOrThrow" && queryData.returning) {
2220
- return 0;
2221
- } else {
2222
- throw new NotFoundError(q);
2217
+ class BooleanColumn extends ColumnType {
2218
+ constructor(schema) {
2219
+ super(schema, schema.boolean());
2220
+ this.dataType = "bool";
2221
+ this.operators = Operators.boolean;
2222
+ this.data.alias = "boolean";
2223
+ this.data.parseItem = parseItem;
2224
+ }
2225
+ static get instance() {
2226
+ return this._instance ?? (this._instance = new BooleanColumn(defaultSchemaConfig));
2227
+ }
2228
+ toCode(ctx, key) {
2229
+ return columnCode(this, ctx, key, "boolean()");
2223
2230
  }
2231
+ }
2232
+ const parseItem = (input) => input[0] === "t";
2233
+
2234
+ var __typeError = (msg) => {
2235
+ throw TypeError(msg);
2224
2236
  };
2225
- const noneMethods = {
2226
- // `then` resolves or rejects based on a return type of the query.
2227
- // It is `async` so it returns a chainable Promise.
2228
- async then(resolve, reject) {
2229
- try {
2230
- const result = noneResult(this, this.q, this.q.returnType);
2231
- resolve?.(result);
2232
- } catch (err) {
2233
- reject?.(err);
2237
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
2238
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
2239
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
2240
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
2241
+ var _query, _query2;
2242
+ class OrchidOrmError extends Error {
2243
+ }
2244
+ class NotFoundError extends OrchidOrmError {
2245
+ constructor(query, message = "Record is not found") {
2246
+ super(message);
2247
+ // `#query` is private to prevent it from serializing to not cause problems to test runner reports
2248
+ __privateAdd(this, _query);
2249
+ __privateSet(this, _query, query);
2250
+ }
2251
+ get query() {
2252
+ return __privateGet(this, _query);
2253
+ }
2254
+ }
2255
+ _query = new WeakMap();
2256
+ class OrchidOrmInternalError extends Error {
2257
+ constructor(query, message) {
2258
+ super(message);
2259
+ // `#query` is private to prevent it from serializing to not cause problems to test runner reports
2260
+ __privateAdd(this, _query2);
2261
+ __privateSet(this, _query2, query);
2262
+ }
2263
+ get query() {
2264
+ return __privateGet(this, _query2);
2265
+ }
2266
+ }
2267
+ _query2 = new WeakMap();
2268
+ class QueryError extends OrchidOrmInternalError {
2269
+ get isUnique() {
2270
+ return this.code === "23505";
2271
+ }
2272
+ get columns() {
2273
+ if (this.columnsCache) return this.columnsCache;
2274
+ const columns = {};
2275
+ if (this.detail) {
2276
+ const list = this.detail.match(/\((.*)\)=/)?.[1];
2277
+ if (list) {
2278
+ list.split(", ").forEach((item) => {
2279
+ const column = item.startsWith('"') ? item.slice(1, -1) : item;
2280
+ const key = this.query.columnNameToKey(column) ?? column;
2281
+ columns[key] = true;
2282
+ });
2283
+ }
2234
2284
  }
2235
- },
2236
- // `catch` returns a Promise, so it is chainable with then/catch.
2237
- catch: () => new Promise(noop)
2285
+ return this.columnsCache = columns;
2286
+ }
2287
+ }
2288
+ class MoreThanOneRowError extends OrchidOrmInternalError {
2289
+ constructor(query, message) {
2290
+ super(query, message);
2291
+ }
2292
+ }
2293
+ class UnhandledTypeError extends OrchidOrmInternalError {
2294
+ constructor(query, value) {
2295
+ super(query, `Unhandled type: ${JSON.stringify(value)} received`);
2296
+ }
2297
+ }
2298
+
2299
+ const _clone = (q) => q.clone();
2300
+ const pushQueryArrayImmutable = (q, key, value) => {
2301
+ const arr = q.q[key];
2302
+ q.q[key] = arr ? [...arr, ...value] : value;
2303
+ return q;
2238
2304
  };
2239
- const _queryNone = (q) => {
2240
- if (isQueryNone(q)) return q;
2241
- q = extendQuery(q, noneMethods);
2242
- pushQueryValueImmutable(q, "and", new RawSQL("false"));
2243
- pushQueryValueImmutable(
2244
- q,
2245
- "transform",
2246
- (_, queryData) => noneResult(q, queryData, queryData.returnType)
2247
- );
2305
+ const pushQueryValueImmutable = (q, key, value) => {
2306
+ pushOrNewArrayToObjectImmutable(q.q, key, value);
2248
2307
  return q;
2249
2308
  };
2250
- const isQueryNone = (q) => q.then === noneMethods.then;
2251
-
2252
- const _join = (query, require, type, first, args) => {
2253
- let joinKey;
2254
- let shape;
2255
- let parsers;
2256
- let batchParsers;
2257
- let computeds;
2258
- let joinSubQuery = false;
2259
- first = preprocessJoinArg(query, first);
2260
- if (typeof first === "object") {
2261
- let isInternalJoin;
2262
- if ("_internalJoin" in first) {
2263
- isInternalJoin = true;
2264
- first = first._internalJoin;
2265
- }
2266
- if (require && isQueryNone(first)) {
2267
- return _queryNone(query);
2268
- }
2269
- const q = first;
2270
- if (!isInternalJoin) {
2271
- joinSubQuery = getIsJoinSubQuery(q);
2272
- }
2273
- joinKey = q.q.as || q.table;
2274
- if (joinKey) {
2275
- shape = getShapeFromSelect(q, joinSubQuery && !!q.q.select);
2276
- parsers = q.q.parsers;
2277
- batchParsers = q.q.batchParsers;
2278
- computeds = q.q.computeds;
2279
- if (joinSubQuery) {
2280
- first = q.clone();
2281
- first.shape = shape;
2282
- }
2283
- }
2284
- } else {
2285
- joinKey = first;
2286
- const relation = query.relations[joinKey];
2287
- if (relation) {
2288
- shape = getShapeFromSelect(relation.relationConfig.query);
2289
- const r = relation.relationConfig.query;
2290
- parsers = r.q.parsers;
2291
- batchParsers = r.q.batchParsers;
2292
- computeds = r.q.computeds;
2293
- } else {
2294
- const w = query.q.withShapes?.[joinKey];
2295
- shape = w?.shape;
2296
- computeds = w?.computeds;
2297
- if (shape) {
2298
- if (!require) shape = { ...shape };
2299
- const arg = { parsers: {} };
2300
- for (const key in shape) {
2301
- addColumnParserToQuery(arg, key, shape[key]);
2302
- }
2303
- }
2304
- }
2305
- }
2306
- const joinArgs = processJoinArgs(
2307
- query,
2308
- first,
2309
- args,
2310
- joinSubQuery
2311
- );
2312
- if (require && "r" in joinArgs && isQueryNone(joinArgs.r)) {
2313
- return _queryNone(query);
2314
- } else if (joinKey && "s" in joinArgs && joinArgs.s) {
2315
- const j = "j" in joinArgs ? joinArgs.r ?? joinArgs.j : "r" in joinArgs ? joinArgs.r : joinArgs.q;
2316
- const jq = j.q;
2317
- if (jq.select || !jq.selectAllColumns) {
2318
- const { q } = query;
2319
- const shape2 = getShapeFromSelect(j, true);
2320
- setObjectValueImmutable(q, "joinedShapes", joinKey, shape2);
2321
- setObjectValueImmutable(q, "joinedParsers", joinKey, jq.parsers);
2322
- if (jq.batchParsers) {
2323
- setObjectValueImmutable(
2324
- jq,
2325
- "joinedBatchParsers",
2326
- joinKey,
2327
- jq.batchParsers
2328
- );
2329
- }
2330
- setObjectValueImmutable(q, "joinedComputeds", joinKey, jq.computeds);
2331
- } else {
2332
- addAllShapesAndParsers(
2333
- query,
2334
- joinKey,
2335
- shape,
2336
- parsers,
2337
- batchParsers,
2338
- computeds
2339
- );
2340
- }
2341
- } else {
2342
- addAllShapesAndParsers(
2343
- query,
2344
- joinKey,
2345
- shape,
2346
- parsers,
2347
- batchParsers,
2348
- computeds
2309
+ const setQueryObjectValueImmutable = (q, object, key, value) => {
2310
+ q.q[object] = {
2311
+ ...q.q[object],
2312
+ [key]: value
2313
+ };
2314
+ return q;
2315
+ };
2316
+ const throwIfNoWhere = (q, method) => {
2317
+ if (!q.q.or && !q.q.and && !q.q.scopes && !q.q.all) {
2318
+ throw new OrchidOrmInternalError(
2319
+ q,
2320
+ `Dangerous ${method} without conditions`
2349
2321
  );
2350
2322
  }
2351
- pushQueryValueImmutable(query, "join", {
2352
- type,
2353
- args: joinArgs
2354
- });
2355
- if (query.q.type === "delete") {
2356
- throwIfJoinLateral(
2357
- query,
2358
- query.q.type
2323
+ };
2324
+ const throwIfJoinLateral = (q, method) => {
2325
+ if (q.q.join?.some(
2326
+ (x) => Array.isArray(x) || "s" in x.args && x.args.s
2327
+ )) {
2328
+ throw new OrchidOrmInternalError(
2329
+ q,
2330
+ `Cannot join a complex query in ${method}`
2359
2331
  );
2360
2332
  }
2361
- return query;
2362
2333
  };
2363
- const addAllShapesAndParsers = (query, joinKey, shape, parsers, batchParsers, computeds) => {
2364
- if (!joinKey) return;
2365
- const { q } = query;
2366
- setObjectValueImmutable(q, "joinedShapes", joinKey, shape);
2367
- setObjectValueImmutable(q, "joinedParsers", joinKey, parsers);
2368
- if (batchParsers) {
2369
- setObjectValueImmutable(q, "joinedBatchParsers", joinKey, batchParsers);
2334
+ const saveSearchAlias = (q, as, key) => {
2335
+ const shapes = q.q[key];
2336
+ if (shapes?.[as]) {
2337
+ let suffix = 2;
2338
+ while (shapes[as = `${as}${suffix}`]) {
2339
+ suffix++;
2340
+ }
2370
2341
  }
2371
- setObjectValueImmutable(q, "joinedComputeds", joinKey, computeds);
2342
+ setQueryObjectValueImmutable(q, key, as, emptyObject);
2343
+ return as;
2372
2344
  };
2373
- const _joinLateralProcessArg = (q, arg, cb) => {
2374
- let relation;
2375
- if (typeof arg === "string") {
2376
- relation = q.relations[arg];
2377
- if (relation) {
2378
- arg = _clone(relation.relationConfig.query);
2379
- } else {
2380
- const w = q.q.withShapes?.[arg];
2381
- if (w) {
2382
- const t = Object.create(q.queryBuilder);
2383
- t.table = arg;
2384
- t.shape = w.shape;
2385
- t.computeds = w.computeds;
2386
- t.q = {
2387
- ...t.q,
2388
- shape: w.shape
2389
- };
2390
- t.baseQuery = t;
2391
- arg = t;
2392
- }
2345
+ const extendQuery = (q, methods) => {
2346
+ const base = Object.create(q.baseQuery);
2347
+ base.baseQuery = base;
2348
+ Object.assign(base, methods);
2349
+ const cloned = Object.create(base);
2350
+ cloned.q = getClonedQueryData(q.q);
2351
+ return cloned;
2352
+ };
2353
+ const getPrimaryKeys = (q) => {
2354
+ var _a;
2355
+ return (_a = q.internal).primaryKeys ?? (_a.primaryKeys = collectPrimaryKeys(q));
2356
+ };
2357
+ const collectPrimaryKeys = (q) => {
2358
+ const primaryKeys = [];
2359
+ const { shape } = q.q;
2360
+ for (const key in shape) {
2361
+ if (shape[key].data.primaryKey) {
2362
+ primaryKeys.push(key);
2393
2363
  }
2394
2364
  }
2395
- let result = resolveSubQueryCallbackV2(
2396
- arg,
2397
- cb
2398
- );
2399
- if (relation) {
2400
- result = relation.relationConfig.joinQuery(
2401
- result,
2402
- q
2403
- );
2365
+ const pkey = q.internal.tableData.primaryKey;
2366
+ if (pkey) {
2367
+ primaryKeys.push(...pkey.columns);
2404
2368
  }
2405
- return result;
2369
+ return primaryKeys;
2406
2370
  };
2407
- const _joinLateral = (self, type, arg, as) => {
2408
- const q = self;
2409
- arg.q.joinTo = q;
2410
- const joinedAs = getQueryAs(q);
2411
- setObjectValueImmutable(arg.q, "joinedShapes", joinedAs, q.q.shape);
2412
- const joinKey = as || arg.q.as || arg.table;
2413
- if (joinKey) {
2414
- const shape = getShapeFromSelect(arg, true);
2415
- setObjectValueImmutable(q.q, "joinedShapes", joinKey, shape);
2416
- setObjectValueImmutable(q.q, "joinedParsers", joinKey, arg.q.parsers);
2417
- if (arg.q.batchParsers) {
2418
- setObjectValueImmutable(
2419
- q.q,
2420
- "joinedBatchParsers",
2421
- joinKey,
2422
- arg.q.batchParsers
2423
- );
2371
+ const _queryAll = (q) => {
2372
+ q.q.returnType = "all";
2373
+ q.q.all = true;
2374
+ return q;
2375
+ };
2376
+ const _queryTake = (query) => {
2377
+ const q = query.q;
2378
+ switch (q.returnType) {
2379
+ case "valueOrThrow":
2380
+ case "pluck":
2381
+ case "void":
2382
+ break;
2383
+ case "value": {
2384
+ q.returnType = "valueOrThrow";
2385
+ break;
2386
+ }
2387
+ default: {
2388
+ q.returnType = "oneOrThrow";
2424
2389
  }
2425
2390
  }
2426
- as || (as = getQueryAs(arg));
2427
- setObjectValueImmutable(q.q, "joinedComputeds", as, arg.q.computeds);
2428
- pushQueryValueImmutable(q, "join", [type, arg, as]);
2391
+ return query;
2392
+ };
2393
+ const _queryTakeOptional = (query) => {
2394
+ const q = query.q;
2395
+ switch (q.returnType) {
2396
+ case "value":
2397
+ case "pluck":
2398
+ case "void":
2399
+ break;
2400
+ case "valueOrThrow": {
2401
+ q.returnType = "value";
2402
+ break;
2403
+ }
2404
+ default: {
2405
+ q.returnType = "one";
2406
+ }
2407
+ }
2408
+ return query;
2409
+ };
2410
+ const _queryExec = (q) => {
2411
+ q.q.returnType = "void";
2412
+ return q;
2413
+ };
2414
+ const _queryRows = (q) => {
2415
+ q.q.returnType = "rows";
2429
2416
  return q;
2430
2417
  };
2418
+ const getFullColumnTable = (q, column, index, as) => {
2419
+ const table = column.slice(0, index);
2420
+ return as && table !== as && q.q.aliases?.[table] === as ? as : table;
2421
+ };
2431
2422
 
2432
- class ArrayColumn extends ColumnType {
2433
- constructor(schema, item, inputType, outputType, queryType) {
2434
- super(schema, inputType, outputType, queryType);
2435
- this.dataType = "array";
2436
- this.operators = Operators.array;
2437
- item.data.isNullable = true;
2438
- setColumnDefaultParse(this, (input) => parse$1.call(this, input));
2439
- this.data.item = item instanceof ArrayColumn ? item.data.item : item;
2440
- this.data.name = item.data.name;
2441
- this.data.arrayDims = item instanceof ArrayColumn ? item.data.arrayDims + 1 : 1;
2423
+ function simpleColumnToSQL(ctx, key, column, quotedAs) {
2424
+ if (!column) return `"${key}"`;
2425
+ const { data } = column;
2426
+ return data.computed ? data.computed.toSQL(ctx, quotedAs) : `${quotedAs ? `${quotedAs}.` : ""}"${data.name || key}"`;
2427
+ }
2428
+ function simpleExistingColumnToSQL(ctx, key, column, quotedAs) {
2429
+ const { data } = column;
2430
+ return data.computed ? data.computed.toSQL(ctx, quotedAs) : `${quotedAs ? `${quotedAs}.` : ""}"${data.name || key}"`;
2431
+ }
2432
+ const columnToSql = (ctx, data, shape, column, quotedAs, select) => {
2433
+ const index = column.indexOf(".");
2434
+ if (index !== -1) {
2435
+ return columnWithDotToSql(
2436
+ ctx,
2437
+ data,
2438
+ shape,
2439
+ column,
2440
+ index,
2441
+ quotedAs,
2442
+ select
2443
+ );
2442
2444
  }
2443
- toSQL() {
2444
- return this.data.item.toSQL() + "[]".repeat(this.data.arrayDims);
2445
+ if (!select && data.joinedShapes?.[column]) {
2446
+ return `"${column}".r`;
2445
2447
  }
2446
- toCode(ctx, key) {
2447
- let open = "array(";
2448
- let close = ")";
2449
- for (let i = 1; i < this.data.arrayDims; i++) {
2450
- open += `${ctx.t}.array(`;
2451
- close += ")";
2448
+ return simpleColumnToSQL(ctx, column, shape[column], quotedAs);
2449
+ };
2450
+ const maybeSelectedColumnToSql = (ctx, data, column, quotedAs) => {
2451
+ const index = column.indexOf(".");
2452
+ if (index !== -1) {
2453
+ return columnWithDotToSql(ctx, data, data.shape, column, index, quotedAs);
2454
+ } else {
2455
+ if (data.joinedShapes?.[column]) {
2456
+ return `"${column}".r`;
2452
2457
  }
2453
- const code = [open];
2454
- const { item } = this.data;
2455
- const { isNullable } = item.data;
2456
- delete item.data.isNullable;
2457
- addCode(code, item.toCode(ctx, key));
2458
- item.data.isNullable = isNullable;
2459
- addCode(code, `${close}${arrayDataToCode(this.data, ctx.migration)}`);
2460
- return columnCode(this, ctx, key, code);
2458
+ if (data.select) {
2459
+ for (const s of data.select) {
2460
+ if (typeof s === "object" && "selectAs" in s) {
2461
+ if (column in s.selectAs) {
2462
+ return simpleColumnToSQL(ctx, column, data.shape[column]);
2463
+ }
2464
+ }
2465
+ }
2466
+ }
2467
+ return simpleColumnToSQL(ctx, column, data.shape[column], quotedAs);
2461
2468
  }
2462
- }
2463
- const parse$1 = function(source) {
2464
- if (typeof source !== "string") return source;
2465
- const entries = [];
2466
- parsePostgresArray(source, entries, this.data.item.data.parseItem);
2467
- return entries;
2468
2469
  };
2469
- const parsePostgresArray = (source, entries, transform) => {
2470
- let pos = 0;
2471
- if (source[0] === "[") {
2472
- pos = source.indexOf("=") + 1;
2473
- if (!pos) pos = source.length;
2470
+ const columnWithDotToSql = (ctx, data, shape, column, index, quotedAs, select) => {
2471
+ const table = column.slice(0, index);
2472
+ const key = column.slice(index + 1);
2473
+ if (key === "*") {
2474
+ const shape2 = data.joinedShapes?.[table];
2475
+ return shape2 ? select ? makeRowToJson(table, shape2, true) : `"${table}".*` : column;
2474
2476
  }
2475
- if (source[pos] === "{") pos++;
2476
- let recorded = "";
2477
- while (pos < source.length) {
2478
- const character = source[pos++];
2479
- if (character === "{") {
2480
- const innerEntries = [];
2481
- entries.push(innerEntries);
2482
- pos += parsePostgresArray(source.slice(pos - 1), innerEntries, transform) - 1;
2483
- } else if (character === "}") {
2484
- if (recorded) {
2485
- entries.push(
2486
- recorded === "NULL" ? null : transform ? transform(recorded) : recorded
2487
- );
2488
- }
2489
- return pos;
2490
- } else if (character === '"') {
2491
- let esc = false;
2492
- let rec = "";
2493
- while (pos < source.length) {
2494
- let char;
2495
- while ((char = source[pos++]) === "\\") {
2496
- if (!(esc = !esc)) rec += "\\";
2497
- }
2498
- if (esc) {
2499
- esc = false;
2500
- } else if (char === '"') {
2501
- break;
2502
- }
2503
- rec += char;
2504
- }
2505
- entries.push(transform ? transform(rec) : rec);
2506
- recorded = "";
2507
- } else if (character === ",") {
2508
- if (recorded) {
2509
- entries.push(
2510
- recorded === "NULL" ? null : transform ? transform(recorded) : recorded
2511
- );
2512
- recorded = "";
2477
+ const tableName = data.aliases?.[table] || table;
2478
+ const quoted = `"${table}"`;
2479
+ const col = quoted === quotedAs ? shape[key] : data.joinedShapes?.[tableName]?.[key];
2480
+ if (col) {
2481
+ if (col.data.name) {
2482
+ return `"${tableName}"."${col.data.name}"`;
2483
+ }
2484
+ if (col.data.computed) {
2485
+ return col.data.computed.toSQL(ctx, quoted);
2486
+ }
2487
+ return `"${tableName}"."${key}"`;
2488
+ }
2489
+ return `"${tableName}"."${key}"`;
2490
+ };
2491
+ const columnToSqlWithAs = (ctx, data, column, as, quotedAs, select, jsonList) => {
2492
+ const index = column.indexOf(".");
2493
+ return index !== -1 ? tableColumnToSqlWithAs(
2494
+ ctx,
2495
+ data,
2496
+ column,
2497
+ column.slice(0, index),
2498
+ column.slice(index + 1),
2499
+ as,
2500
+ quotedAs,
2501
+ select,
2502
+ jsonList
2503
+ ) : ownColumnToSqlWithAs(ctx, data, column, as, quotedAs, select, jsonList);
2504
+ };
2505
+ const tableColumnToSqlWithAs = (ctx, data, column, table, key, as, quotedAs, select, jsonList) => {
2506
+ if (key === "*") {
2507
+ if (jsonList) jsonList[as] = void 0;
2508
+ const shape = data.joinedShapes?.[table];
2509
+ if (shape) {
2510
+ {
2511
+ return makeRowToJson(table, shape, true) + ` "${as}"`;
2513
2512
  }
2514
- } else {
2515
- recorded += character;
2513
+ }
2514
+ return column;
2515
+ }
2516
+ const tableName = data.aliases?.[table] || table;
2517
+ const quoted = `"${table}"`;
2518
+ const col = quoted === quotedAs ? data.shape[key] : data.joinedShapes?.[tableName][key];
2519
+ if (jsonList) jsonList[as] = col;
2520
+ if (col) {
2521
+ if (col.data.name && col.data.name !== key) {
2522
+ return `"${tableName}"."${col.data.name}" "${as}"`;
2523
+ }
2524
+ if (col.data.computed) {
2525
+ return `${col.data.computed.toSQL(ctx, quoted)} "${as}"`;
2516
2526
  }
2517
2527
  }
2518
- return pos;
2528
+ return `"${tableName}"."${key}"${key === as ? "" : ` "${as}"`}`;
2519
2529
  };
2520
-
2521
- class NumberBaseColumn extends ColumnType {
2522
- constructor() {
2523
- super(...arguments);
2524
- this.operators = Operators.number;
2525
- }
2526
- }
2527
- class IntegerBaseColumn extends NumberBaseColumn {
2528
- constructor(schema) {
2529
- super(schema, schema.int());
2530
- this.data.int = true;
2531
- }
2532
- }
2533
- class NumberAsStringBaseColumn extends ColumnType {
2534
- constructor(schema) {
2535
- super(schema, schema.stringSchema());
2536
- this.operators = Operators.number;
2537
- this.data.jsonCast = "text";
2538
- }
2539
- }
2540
- class DecimalColumn extends NumberAsStringBaseColumn {
2541
- constructor(schema, numericPrecision, numericScale) {
2542
- super(schema);
2543
- this.operators = Operators.number;
2544
- this.dataType = "numeric";
2545
- this.data.numericPrecision = numericPrecision;
2546
- this.data.numericScale = numericScale;
2547
- this.data.alias = "decimal";
2530
+ const ownColumnToSqlWithAs = (ctx, data, column, as, quotedAs, select, jsonList) => {
2531
+ const col = data.shape[column];
2532
+ if (jsonList) jsonList[as] = col;
2533
+ if (col) {
2534
+ if (col.data.name && col.data.name !== column) {
2535
+ return `${quotedAs ? `${quotedAs}.` : ""}"${col.data.name}"${col.data.name === as ? "" : ` "${as}"`}`;
2536
+ }
2537
+ if (col.data.computed) {
2538
+ return `${col.data.computed.toSQL(ctx, quotedAs)} "${as}"`;
2539
+ }
2548
2540
  }
2549
- toCode(ctx, key) {
2550
- const { numericPrecision, numericScale } = this.data;
2551
- return columnCode(
2552
- this,
2553
- ctx,
2554
- key,
2555
- `decimal(${numericPrecision || ""}${numericScale ? `, ${numericScale}` : ""})`
2541
+ return `${quotedAs ? `${quotedAs}.` : ""}"${column}"${column === as ? "" : ` "${as}"`}`;
2542
+ };
2543
+ const rawOrColumnToSql = (ctx, data, expr, quotedAs, shape = data.shape, select) => {
2544
+ return typeof expr === "string" ? columnToSql(ctx, data, shape, expr, quotedAs, select) : expr.toSQL(ctx, quotedAs);
2545
+ };
2546
+ const quoteSchemaAndTable = (schema, table) => {
2547
+ return schema ? `"${schema}"."${table}"` : `"${table}"`;
2548
+ };
2549
+ const makeRowToJson = (table, shape, aliasName) => {
2550
+ let isSimple = true;
2551
+ const list = [];
2552
+ for (const key in shape) {
2553
+ const column = shape[key];
2554
+ if (column.data.explicitSelect) {
2555
+ continue;
2556
+ }
2557
+ if (aliasName && column.data.name || column.data.jsonCast) {
2558
+ isSimple = false;
2559
+ }
2560
+ list.push(
2561
+ `'${key}', "${table}"."${aliasName && column.data.name || key}"${column.data.jsonCast ? `::${column.data.jsonCast}` : ""}`
2556
2562
  );
2557
2563
  }
2558
- toSQL() {
2559
- const { numericPrecision, numericScale } = this.data;
2560
- return joinTruthy(
2561
- this.dataType,
2562
- numericPrecision ? numericScale ? `(${numericPrecision}, ${numericScale})` : `(${numericPrecision})` : void 0
2564
+ return isSimple ? `row_to_json("${table}".*)` : `CASE WHEN "${table}".* IS NULL THEN NULL ELSE json_build_object(` + list.join(", ") + ") END";
2565
+ };
2566
+
2567
+ const queryTypeWithLimitOne = {
2568
+ one: true,
2569
+ oneOrThrow: true,
2570
+ value: true,
2571
+ valueOrThrow: true
2572
+ };
2573
+ const isQueryReturnsAll = (q) => !q.q.returnType || q.q.returnType === "all";
2574
+
2575
+ const pushDistinctSql = (ctx, table, distinct, quotedAs) => {
2576
+ ctx.sql.push("DISTINCT");
2577
+ if (distinct.length) {
2578
+ const columns = distinct?.map(
2579
+ (item) => rawOrColumnToSql(ctx, table.q, item, quotedAs)
2563
2580
  );
2581
+ ctx.sql.push(`ON (${columns?.join(", ") || ""})`);
2564
2582
  }
2565
- }
2566
- const skipNumberMethods = { int: true };
2567
- const intToCode = (column, ctx, key, alias) => {
2568
- let code;
2569
- if (column.data.identity) {
2570
- code = identityToCode(column.data.identity, alias);
2583
+ };
2584
+
2585
+ const noneResult = (q, queryData, type) => {
2586
+ if (!type || type === "all" || type === "rows" || type === "pluck") {
2587
+ return [];
2588
+ } else if (type === "one" || type === "value" || type === "void") {
2589
+ return queryData.notFoundDefault;
2590
+ } else if (type === "valueOrThrow" && queryData.returning) {
2591
+ return 0;
2571
2592
  } else {
2572
- code = [`${alias}()`];
2593
+ throw new NotFoundError(q);
2573
2594
  }
2574
- addCode(
2575
- code,
2576
- numberDataToCode(column.data, ctx.migration, skipNumberMethods)
2595
+ };
2596
+ const noneMethods = {
2597
+ // `then` resolves or rejects based on a return type of the query.
2598
+ // It is `async` so it returns a chainable Promise.
2599
+ async then(resolve, reject) {
2600
+ try {
2601
+ const result = noneResult(this, this.q, this.q.returnType);
2602
+ resolve?.(result);
2603
+ } catch (err) {
2604
+ reject?.(err);
2605
+ }
2606
+ },
2607
+ // `catch` returns a Promise, so it is chainable with then/catch.
2608
+ catch: () => new Promise(noop)
2609
+ };
2610
+ const _queryNone = (q) => {
2611
+ if (isQueryNone(q)) return q;
2612
+ q = extendQuery(q, noneMethods);
2613
+ pushQueryValueImmutable(q, "and", new RawSQL("false"));
2614
+ pushQueryValueImmutable(
2615
+ q,
2616
+ "transform",
2617
+ (_, queryData) => noneResult(q, queryData, queryData.returnType)
2577
2618
  );
2578
- return columnCode(column, ctx, key, code);
2619
+ return q;
2579
2620
  };
2580
- class SmallIntColumn extends IntegerBaseColumn {
2581
- constructor(schema) {
2582
- super(schema);
2583
- this.dataType = "int2";
2584
- this.data.alias = "smallint";
2585
- this.data.parseItem = parseInt;
2586
- }
2587
- toCode(ctx, key) {
2588
- return intToCode(this, ctx, key, "smallint");
2589
- }
2590
- identity(options = {}) {
2591
- return setColumnData(this, "identity", options);
2592
- }
2593
- }
2594
- class IntegerColumn extends IntegerBaseColumn {
2595
- constructor(schema) {
2596
- super(schema);
2597
- this.dataType = "int4";
2598
- this.data.alias = "integer";
2599
- this.data.parseItem = parseInt;
2600
- }
2601
- toCode(ctx, key) {
2602
- return intToCode(this, ctx, key, "integer");
2603
- }
2604
- identity(options = {}) {
2605
- return setColumnData(this, "identity", options);
2606
- }
2607
- }
2608
- class BigIntColumn extends NumberAsStringBaseColumn {
2609
- constructor(schema) {
2610
- super(schema);
2611
- this.dataType = "int8";
2612
- this.data.alias = "bigint";
2613
- }
2614
- toCode(ctx, key) {
2615
- return intToCode(this, ctx, key, "bigint");
2616
- }
2617
- identity(options = {}) {
2618
- return setColumnData(this, "identity", options);
2619
- }
2620
- }
2621
- class RealColumn extends NumberBaseColumn {
2622
- constructor(schema) {
2623
- super(schema, schema.number());
2624
- this.dataType = "float4";
2625
- this.data.alias = "real";
2626
- this.data.parseItem = parseFloat;
2627
- }
2628
- toCode(ctx, key) {
2629
- return columnCode(
2630
- this,
2631
- ctx,
2632
- key,
2633
- `real()${numberDataToCode(this.data, ctx.migration)}`
2634
- );
2635
- }
2636
- }
2637
- class DoublePrecisionColumn extends NumberAsStringBaseColumn {
2638
- constructor(schema) {
2639
- super(schema);
2640
- this.dataType = "float8";
2641
- this.data.alias = "doublePrecision";
2642
- }
2643
- toCode(ctx, key) {
2644
- return columnCode(this, ctx, key, `doublePrecision()`);
2645
- }
2646
- }
2647
- class SmallSerialColumn extends IntegerBaseColumn {
2648
- constructor(schema) {
2649
- super(schema);
2650
- this.dataType = "int2";
2651
- this.data.int = true;
2652
- this.data.alias = "smallSerial";
2653
- this.data.parseItem = parseInt;
2621
+ const isQueryNone = (q) => q.then === noneMethods.then;
2622
+
2623
+ const _join = (query, require, type, first, args) => {
2624
+ let joinKey;
2625
+ let shape;
2626
+ let parsers;
2627
+ let batchParsers;
2628
+ let computeds;
2629
+ let joinSubQuery = false;
2630
+ first = preprocessJoinArg(query, first);
2631
+ if (typeof first === "object") {
2632
+ let isInternalJoin;
2633
+ if ("_internalJoin" in first) {
2634
+ isInternalJoin = true;
2635
+ first = first._internalJoin;
2636
+ }
2637
+ if (require && isQueryNone(first)) {
2638
+ return _queryNone(query);
2639
+ }
2640
+ const q = first;
2641
+ if (!isInternalJoin) {
2642
+ joinSubQuery = getIsJoinSubQuery(q);
2643
+ }
2644
+ joinKey = q.q.as || q.table;
2645
+ if (joinKey) {
2646
+ shape = getShapeFromSelect(q, joinSubQuery && !!q.q.select);
2647
+ parsers = q.q.parsers;
2648
+ batchParsers = q.q.batchParsers;
2649
+ computeds = q.q.computeds;
2650
+ if (joinSubQuery) {
2651
+ first = q.clone();
2652
+ first.shape = shape;
2653
+ }
2654
+ }
2655
+ } else {
2656
+ joinKey = first;
2657
+ const relation = query.relations[joinKey];
2658
+ if (relation) {
2659
+ shape = getShapeFromSelect(relation.relationConfig.query);
2660
+ const r = relation.relationConfig.query;
2661
+ parsers = r.q.parsers;
2662
+ batchParsers = r.q.batchParsers;
2663
+ computeds = r.q.computeds;
2664
+ } else {
2665
+ const w = query.q.withShapes?.[joinKey];
2666
+ shape = w?.shape;
2667
+ computeds = w?.computeds;
2668
+ if (shape) {
2669
+ if (!require) shape = { ...shape };
2670
+ const arg = { parsers: {} };
2671
+ for (const key in shape) {
2672
+ addColumnParserToQuery(arg, key, shape[key]);
2673
+ }
2674
+ }
2675
+ }
2654
2676
  }
2655
- toSQL() {
2656
- return "smallserial";
2677
+ const joinArgs = processJoinArgs(
2678
+ query,
2679
+ first,
2680
+ args,
2681
+ joinSubQuery
2682
+ );
2683
+ if (require && "r" in joinArgs && isQueryNone(joinArgs.r)) {
2684
+ return _queryNone(query);
2685
+ } else if (joinKey && "s" in joinArgs && joinArgs.s) {
2686
+ const j = "j" in joinArgs ? joinArgs.r ?? joinArgs.j : "r" in joinArgs ? joinArgs.r : joinArgs.q;
2687
+ const jq = j.q;
2688
+ if (jq.select || !jq.selectAllColumns) {
2689
+ const { q } = query;
2690
+ const shape2 = getShapeFromSelect(j, true);
2691
+ setObjectValueImmutable(q, "joinedShapes", joinKey, shape2);
2692
+ setObjectValueImmutable(q, "joinedParsers", joinKey, jq.parsers);
2693
+ if (jq.batchParsers) {
2694
+ setObjectValueImmutable(
2695
+ jq,
2696
+ "joinedBatchParsers",
2697
+ joinKey,
2698
+ jq.batchParsers
2699
+ );
2700
+ }
2701
+ setObjectValueImmutable(q, "joinedComputeds", joinKey, jq.computeds);
2702
+ } else {
2703
+ addAllShapesAndParsers(
2704
+ query,
2705
+ joinKey,
2706
+ shape,
2707
+ parsers,
2708
+ batchParsers,
2709
+ computeds
2710
+ );
2711
+ }
2712
+ } else {
2713
+ addAllShapesAndParsers(
2714
+ query,
2715
+ joinKey,
2716
+ shape,
2717
+ parsers,
2718
+ batchParsers,
2719
+ computeds
2720
+ );
2657
2721
  }
2658
- toCode(ctx, key) {
2659
- return columnCode(
2660
- this,
2661
- ctx,
2662
- key,
2663
- `smallSerial()${numberDataToCode(
2664
- this.data,
2665
- ctx.migration,
2666
- skipNumberMethods
2667
- )}`
2722
+ pushQueryValueImmutable(query, "join", {
2723
+ type,
2724
+ args: joinArgs
2725
+ });
2726
+ if (query.q.type === "delete") {
2727
+ throwIfJoinLateral(
2728
+ query,
2729
+ query.q.type
2668
2730
  );
2669
2731
  }
2670
- }
2671
- class SerialColumn extends IntegerBaseColumn {
2672
- constructor(schema) {
2673
- super(schema);
2674
- this.dataType = "int4";
2675
- this.data.int = true;
2676
- this.data.alias = "serial";
2677
- this.data.parseItem = parseInt;
2732
+ return query;
2733
+ };
2734
+ const addAllShapesAndParsers = (query, joinKey, shape, parsers, batchParsers, computeds) => {
2735
+ if (!joinKey) return;
2736
+ const { q } = query;
2737
+ setObjectValueImmutable(q, "joinedShapes", joinKey, shape);
2738
+ setObjectValueImmutable(q, "joinedParsers", joinKey, parsers);
2739
+ if (batchParsers) {
2740
+ setObjectValueImmutable(q, "joinedBatchParsers", joinKey, batchParsers);
2678
2741
  }
2679
- toSQL() {
2680
- return "serial";
2742
+ setObjectValueImmutable(q, "joinedComputeds", joinKey, computeds);
2743
+ };
2744
+ const _joinLateralProcessArg = (q, arg, cb) => {
2745
+ let relation;
2746
+ if (typeof arg === "string") {
2747
+ relation = q.relations[arg];
2748
+ if (relation) {
2749
+ arg = _clone(relation.relationConfig.query);
2750
+ } else {
2751
+ const w = q.q.withShapes?.[arg];
2752
+ if (w) {
2753
+ const t = Object.create(q.queryBuilder);
2754
+ t.table = arg;
2755
+ t.shape = w.shape;
2756
+ t.computeds = w.computeds;
2757
+ t.q = {
2758
+ ...t.q,
2759
+ shape: w.shape
2760
+ };
2761
+ t.baseQuery = t;
2762
+ arg = t;
2763
+ }
2764
+ }
2681
2765
  }
2682
- toCode(ctx, key) {
2683
- return columnCode(
2684
- this,
2685
- ctx,
2686
- key,
2687
- `serial()${numberDataToCode(
2688
- this.data,
2689
- ctx.migration,
2690
- skipNumberMethods
2691
- )}`
2766
+ let result = resolveSubQueryCallbackV2(
2767
+ arg,
2768
+ cb
2769
+ );
2770
+ if (relation) {
2771
+ result = relation.relationConfig.joinQuery(
2772
+ result,
2773
+ q
2692
2774
  );
2693
2775
  }
2694
- }
2695
- class BigSerialColumn extends NumberAsStringBaseColumn {
2696
- constructor(schema) {
2697
- super(schema);
2698
- this.dataType = "int8";
2699
- this.data.alias = "bigint";
2700
- }
2701
- toSQL() {
2702
- return "bigserial";
2703
- }
2704
- toCode(ctx, key) {
2705
- return columnCode(this, ctx, key, `bigSerial()`);
2776
+ return result;
2777
+ };
2778
+ const _joinLateral = (self, type, arg, as, innerJoinLateral) => {
2779
+ const q = self;
2780
+ arg.q.joinTo = q;
2781
+ const joinedAs = getQueryAs(q);
2782
+ setObjectValueImmutable(arg.q, "joinedShapes", joinedAs, q.q.shape);
2783
+ const joinKey = as || arg.q.as || arg.table;
2784
+ if (joinKey) {
2785
+ const shape = getShapeFromSelect(arg, true);
2786
+ setObjectValueImmutable(q.q, "joinedShapes", joinKey, shape);
2787
+ setObjectValueImmutable(q.q, "joinedParsers", joinKey, arg.q.parsers);
2788
+ if (arg.q.batchParsers) {
2789
+ setObjectValueImmutable(
2790
+ q.q,
2791
+ "joinedBatchParsers",
2792
+ joinKey,
2793
+ arg.q.batchParsers
2794
+ );
2795
+ }
2706
2796
  }
2707
- }
2708
-
2709
- const parseDateToDate = (value) => new Date(value);
2710
- const defaultSchemaConfig = {
2711
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2712
- parse(fn) {
2713
- return setColumnParse(this, fn);
2714
- },
2715
- parseNull(fn) {
2716
- return setColumnParseNull(this, fn);
2717
- },
2718
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2719
- encode(fn) {
2720
- return setColumnData(this, "encode", fn);
2721
- },
2722
- asType() {
2723
- return this;
2724
- },
2725
- dateAsNumber() {
2726
- return this.parse(Date.parse);
2727
- },
2728
- dateAsDate() {
2729
- return this.parse(parseDateToDate);
2730
- },
2731
- enum(dataType, type) {
2732
- return new EnumColumn(defaultSchemaConfig, dataType, type, void 0);
2733
- },
2734
- array(item) {
2735
- return new ArrayColumn(defaultSchemaConfig, item, void 0);
2736
- },
2737
- boolean: noop,
2738
- buffer: noop,
2739
- unknown: noop,
2740
- never: noop,
2741
- stringSchema: noop,
2742
- stringMin: noop,
2743
- stringMax: noop,
2744
- stringMinMax: noop,
2745
- number: noop,
2746
- int: noop,
2747
- stringNumberDate: noop,
2748
- timeInterval: noop,
2749
- bit: noop,
2750
- uuid: noop,
2751
- nullable() {
2752
- return setColumnData(this, "isNullable", true);
2753
- },
2754
- json() {
2755
- return new JSONColumn(defaultSchemaConfig, void 0);
2756
- },
2757
- setErrors: noop,
2758
- smallint: () => new SmallIntColumn(defaultSchemaConfig),
2759
- integer: () => new IntegerColumn(defaultSchemaConfig),
2760
- real: () => new RealColumn(defaultSchemaConfig),
2761
- smallSerial: () => new SmallSerialColumn(defaultSchemaConfig),
2762
- serial: () => new SerialColumn(defaultSchemaConfig),
2763
- bigint: () => new BigIntColumn(defaultSchemaConfig),
2764
- decimal: (precision, scale) => new DecimalColumn(defaultSchemaConfig, precision, scale),
2765
- doublePrecision: () => new DoublePrecisionColumn(defaultSchemaConfig),
2766
- bigSerial: () => new BigSerialColumn(defaultSchemaConfig),
2767
- money: () => new MoneyColumn(defaultSchemaConfig),
2768
- varchar: (limit) => new VarCharColumn(defaultSchemaConfig, limit),
2769
- text: () => new TextColumn(defaultSchemaConfig),
2770
- string: (limit) => new StringColumn(defaultSchemaConfig, limit),
2771
- citext: () => new CitextColumn(defaultSchemaConfig),
2772
- date: () => new DateColumn(defaultSchemaConfig),
2773
- timestampNoTZ: (precision) => new TimestampColumn(defaultSchemaConfig, precision),
2774
- timestamp: (precision) => new TimestampTZColumn(defaultSchemaConfig, precision),
2775
- geographyPointSchema: noop
2797
+ as || (as = getQueryAs(arg));
2798
+ setObjectValueImmutable(q.q, "joinedComputeds", as, arg.q.computeds);
2799
+ pushQueryValueImmutable(q, "join", {
2800
+ type: `${type} LATERAL`,
2801
+ args: { l: arg, a: as, i: innerJoinLateral }
2802
+ });
2803
+ return q;
2776
2804
  };
2777
2805
 
2778
2806
  const escape = (value, migration, nested) => {
@@ -4223,10 +4251,12 @@ const processSelectArg = (q, as, arg, columnAs) => {
4223
4251
  joinQuery = true;
4224
4252
  value = value.joinQuery(value, q);
4225
4253
  let query;
4226
- const returnType = value.q.returnType;
4254
+ const { returnType, innerJoinLateral } = value.q;
4227
4255
  if (!returnType || returnType === "all") {
4228
4256
  query = value.json(false);
4229
- value.q.coalesceValue = emptyArrSQL;
4257
+ if (!innerJoinLateral) {
4258
+ value.q.coalesceValue = emptyArrSQL;
4259
+ }
4230
4260
  } else if (returnType === "pluck") {
4231
4261
  query = value.q.select ? value.wrap(cloneQueryBaseUnscoped(value)).jsonAgg(value.q.select[0]) : value.json(false);
4232
4262
  value.q.coalesceValue = emptyArrSQL;
@@ -4253,9 +4283,12 @@ const processSelectArg = (q, as, arg, columnAs) => {
4253
4283
  }
4254
4284
  _joinLateral(
4255
4285
  q,
4256
- value.q.innerJoinLateral ? "JOIN" : "LEFT JOIN",
4286
+ innerJoinLateral ? "JOIN" : "LEFT JOIN",
4257
4287
  query,
4258
- key
4288
+ key,
4289
+ // no need for `ON p.r IS NOT NULL` check when joining a single record,
4290
+ // `JOIN` will handle it on itself.
4291
+ innerJoinLateral && returnType !== "one" && returnType !== "oneOrThrow"
4259
4292
  );
4260
4293
  }
4261
4294
  }
@@ -4383,7 +4416,7 @@ const getShapeFromSelect = (q, isSubQuery) => {
4383
4416
  const { returnType } = it.q;
4384
4417
  if (returnType === "value" || returnType === "valueOrThrow") {
4385
4418
  const type = it.q.getColumn;
4386
- if (type) result[key] = type;
4419
+ result[key] = type || UnknownColumn.instance;
4387
4420
  } else {
4388
4421
  result[key] = new JSONTextColumn(defaultSchemaConfig);
4389
4422
  }
@@ -6022,7 +6055,13 @@ const pushIn = (ctx, query, ands, quotedAs, arg) => {
6022
6055
  const processJoinItem = (ctx, table, query, args, quotedAs) => {
6023
6056
  let target;
6024
6057
  let on;
6025
- if ("j" in args) {
6058
+ if ("l" in args) {
6059
+ const { aliasValue } = ctx;
6060
+ ctx.aliasValue = true;
6061
+ target = `(${getSqlText(args.l.toSQL(ctx))}) "${query.aliases?.[args.a] || args.a}"`;
6062
+ on = `${args.i ? `"${args.a}".r IS NOT NULL` : "true"}`;
6063
+ ctx.aliasValue = aliasValue;
6064
+ } else if ("j" in args) {
6026
6065
  const { j, s, r } = args;
6027
6066
  const tableName = typeof j.q.from === "string" ? j.q.from : j.table;
6028
6067
  const quotedTable = quoteSchemaAndTable(j.q.schema, tableName);
@@ -6192,24 +6231,14 @@ const getObjectOrRawConditions = (ctx, query, data, quotedAs, joinAs, joinShape)
6192
6231
  const pushJoinSql = (ctx, table, query, quotedAs) => {
6193
6232
  const joinSet = query.join.length > 1 ? /* @__PURE__ */ new Set() : null;
6194
6233
  for (const item of query.join) {
6195
- let sql;
6196
- if (Array.isArray(item)) {
6197
- const q = item[1];
6198
- const { aliasValue } = ctx;
6199
- ctx.aliasValue = true;
6200
- const as = item[2];
6201
- sql = `${item[0]} LATERAL (${getSqlText(q.toSQL(ctx))}) "${query.aliases?.[as] || as}" ON true`;
6202
- ctx.aliasValue = aliasValue;
6203
- } else {
6204
- const { target, on = "true" } = processJoinItem(
6205
- ctx,
6206
- table,
6207
- query,
6208
- item.args,
6209
- quotedAs
6210
- );
6211
- sql = `${item.type} ${target} ON ${on}`;
6212
- }
6234
+ const { target, on = "true" } = processJoinItem(
6235
+ ctx,
6236
+ table,
6237
+ query,
6238
+ item.args,
6239
+ quotedAs
6240
+ );
6241
+ const sql = `${item.type} ${target} ON ${on}`;
6213
6242
  if (joinSet) {
6214
6243
  if (joinSet.has(sql)) continue;
6215
6244
  joinSet.add(sql);
@@ -8032,7 +8061,7 @@ class AggregateMethods {
8032
8061
  boolAnd(arg, options) {
8033
8062
  return makeFnExpression(
8034
8063
  this,
8035
- emptyObject,
8064
+ BooleanColumn.instance,
8036
8065
  "bool_and",
8037
8066
  [arg],
8038
8067
  options
@@ -8061,7 +8090,7 @@ class AggregateMethods {
8061
8090
  boolOr(arg, options) {
8062
8091
  return makeFnExpression(
8063
8092
  this,
8064
- emptyObject,
8093
+ BooleanColumn.instance,
8065
8094
  "bool_or",
8066
8095
  [arg],
8067
8096
  options
@@ -8073,7 +8102,7 @@ class AggregateMethods {
8073
8102
  every(arg, options) {
8074
8103
  return makeFnExpression(
8075
8104
  this,
8076
- emptyObject,
8105
+ BooleanColumn.instance,
8077
8106
  "every",
8078
8107
  [arg],
8079
8108
  options
@@ -8106,7 +8135,7 @@ class AggregateMethods {
8106
8135
  jsonAgg(arg, options) {
8107
8136
  return makeFnExpression(
8108
8137
  this,
8109
- emptyObject,
8138
+ JSONTextColumn.instance,
8110
8139
  "json_agg",
8111
8140
  [arg],
8112
8141
  options
@@ -8118,7 +8147,7 @@ class AggregateMethods {
8118
8147
  jsonbAgg(arg, options) {
8119
8148
  return makeFnExpression(
8120
8149
  this,
8121
- emptyObject,
8150
+ JSONTextColumn.instance,
8122
8151
  "jsonb_agg",
8123
8152
  [arg],
8124
8153
  options
@@ -8159,7 +8188,7 @@ class AggregateMethods {
8159
8188
  jsonObjectAgg(arg, options) {
8160
8189
  return makeFnExpression(
8161
8190
  this,
8162
- emptyObject,
8191
+ JSONTextColumn.instance,
8163
8192
  "json_object_agg",
8164
8193
  [{ pairs: arg }],
8165
8194
  options
@@ -8171,7 +8200,7 @@ class AggregateMethods {
8171
8200
  jsonbObjectAgg(arg, options) {
8172
8201
  return makeFnExpression(
8173
8202
  this,
8174
- emptyObject,
8203
+ JSONTextColumn.instance,
8175
8204
  "jsonb_object_agg",
8176
8205
  [{ pairs: arg }],
8177
8206
  options
@@ -8202,7 +8231,7 @@ class AggregateMethods {
8202
8231
  stringAgg(arg, delimiter, options) {
8203
8232
  return makeFnExpression(
8204
8233
  this,
8205
- emptyObject,
8234
+ TextColumn.instance,
8206
8235
  "string_agg",
8207
8236
  [arg, { value: delimiter }],
8208
8237
  options
@@ -8228,7 +8257,7 @@ class AggregateMethods {
8228
8257
  xmlAgg(arg, options) {
8229
8258
  return makeFnExpression(
8230
8259
  this,
8231
- emptyObject,
8260
+ XMLColumn.instance,
8232
8261
  "xmlagg",
8233
8262
  [arg],
8234
8263
  options