pqb 0.49.1 → 0.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1943,9 +1943,9 @@ const collectPrimaryKeys = (q) => {
1943
1943
  primaryKeys.push(key);
1944
1944
  }
1945
1945
  }
1946
- const pKeys = q.internal.primaryKeys;
1947
- if (pKeys) {
1948
- primaryKeys.push(...pKeys);
1946
+ const pkey = q.internal.tableData.primaryKey;
1947
+ if (pkey) {
1948
+ primaryKeys.push(...pkey.columns);
1949
1949
  }
1950
1950
  return primaryKeys;
1951
1951
  };
@@ -2226,11 +2226,18 @@ const _join = (query, require, type, first, args) => {
2226
2226
  let joinSubQuery = false;
2227
2227
  first = preprocessJoinArg(query, first);
2228
2228
  if (typeof first === "object") {
2229
+ let isInternalJoin;
2230
+ if ("_internalJoin" in first) {
2231
+ isInternalJoin = true;
2232
+ first = first._internalJoin;
2233
+ }
2229
2234
  if (require && isQueryNone(first)) {
2230
2235
  return _queryNone(query);
2231
2236
  }
2232
2237
  const q = first;
2233
- joinSubQuery = getIsJoinSubQuery(q);
2238
+ if (!isInternalJoin) {
2239
+ joinSubQuery = getIsJoinSubQuery(q);
2240
+ }
2234
2241
  joinKey = q.q.as || q.table;
2235
2242
  if (joinKey) {
2236
2243
  shape = getShapeFromSelect(q, joinSubQuery && !!q.q.select);
@@ -3717,6 +3724,171 @@ const filterAllResult = (result, tempColumns, hasAfterHook) => {
3717
3724
  return result;
3718
3725
  };
3719
3726
 
3727
+ const _queryAs = (self, as) => {
3728
+ const { q } = self;
3729
+ q.as = as;
3730
+ q.aliases = {
3731
+ ...q.aliases,
3732
+ [as]: q.aliases ? _queryResolveAlias(q.aliases, as) : as
3733
+ };
3734
+ return self;
3735
+ };
3736
+ const _queryResolveAlias = (aliases, as) => {
3737
+ if (!aliases[as]) return as;
3738
+ let suffix = 2;
3739
+ let privateAs;
3740
+ while (aliases[privateAs = as + suffix]) {
3741
+ suffix++;
3742
+ }
3743
+ return privateAs;
3744
+ };
3745
+ class AsMethods {
3746
+ /**
3747
+ * Sets table alias:
3748
+ *
3749
+ * ```ts
3750
+ * db.table.as('u').select('u.name');
3751
+ *
3752
+ * // Can be used in the join:
3753
+ * db.table.join(Profile.as('p'), 'p.userId', 'user.id');
3754
+ * ```
3755
+ *
3756
+ * @param as - alias for the table of this query
3757
+ */
3758
+ as(as) {
3759
+ return _queryAs(_clone(this), as);
3760
+ }
3761
+ }
3762
+
3763
+ function queryFrom(self, arg) {
3764
+ const data = self.q;
3765
+ if (typeof arg === "string") {
3766
+ data.as || (data.as = arg);
3767
+ const w = data.withShapes?.[arg];
3768
+ data.shape = w?.shape ?? orchidCore.emptyObject;
3769
+ data.computeds = w?.computeds;
3770
+ } else if (orchidCore.isExpression(arg)) {
3771
+ data.as || (data.as = "t");
3772
+ } else if (Array.isArray(arg)) {
3773
+ const { shape } = data;
3774
+ let clonedParsers = false;
3775
+ for (const item of arg) {
3776
+ if (typeof item === "string") {
3777
+ const w = data.withShapes[item];
3778
+ Object.assign(shape, w.shape);
3779
+ if (w.computeds) data.computeds = { ...data.computeds, ...w.computeds };
3780
+ for (const key in w.shape) {
3781
+ addColumnParserToQuery(
3782
+ self,
3783
+ key,
3784
+ w.shape[key]
3785
+ );
3786
+ }
3787
+ } else if (!orchidCore.isExpression(item)) {
3788
+ Object.assign(shape, getShapeFromSelect(item, true));
3789
+ if (!clonedParsers) {
3790
+ data.parsers = { ...data.parsers };
3791
+ clonedParsers = true;
3792
+ }
3793
+ Object.assign(data.parsers, item.q.parsers);
3794
+ }
3795
+ }
3796
+ } else {
3797
+ const q = arg;
3798
+ data.as || (data.as = q.q.as || q.table || "t");
3799
+ data.shape = getShapeFromSelect(q, true);
3800
+ data.parsers = q.q.parsers;
3801
+ data.batchParsers = q.q.batchParsers;
3802
+ }
3803
+ data.from = arg;
3804
+ data.selectAllColumns = data.scopes = void 0;
3805
+ return self;
3806
+ }
3807
+ function queryFromSql(self, args) {
3808
+ const data = self.q;
3809
+ data.as || (data.as = "t");
3810
+ data.from = sqlQueryArgsToExpression(args);
3811
+ data.selectAllColumns = void 0;
3812
+ return self;
3813
+ }
3814
+ class FromMethods {
3815
+ /**
3816
+ * Set the `FROM` value, by default the table name is used.
3817
+ *
3818
+ * `from` determines a set of available tables and columns withing the query,
3819
+ * and thus it must not follow `select`, use `select` only after `from`.
3820
+ *
3821
+ * ```ts
3822
+ * // accepts sub-query:
3823
+ * db.table.from(db.otherTable.select('foo', 'bar'));
3824
+ *
3825
+ * // accepts alias of `WITH` expression:
3826
+ * q.with('withTable', db.table.select('id', 'name'))
3827
+ * .from('withTable')
3828
+ * // `select` is after `from`
3829
+ * .select('id', 'name');
3830
+ * ```
3831
+ *
3832
+ * `from` can accept multiple sources:
3833
+ *
3834
+ * ```ts
3835
+ * db.table
3836
+ * // add a `WITH` statement called `withTable
3837
+ * .with('withTable', db.table.select('one'))
3838
+ * // select from `withTable` and from `otherTable`
3839
+ * .from('withTable', db.otherTable.select('two'))
3840
+ * // source names and column names are properly typed when selecting
3841
+ * .select('withTable.one', 'otherTable.two');
3842
+ * ```
3843
+ *
3844
+ * @param arg - query or name of CTE table
3845
+ */
3846
+ from(arg) {
3847
+ return queryFrom(_clone(this), arg);
3848
+ }
3849
+ /**
3850
+ * Set the `FROM` value with custom SQL:
3851
+ *
3852
+ * ```ts
3853
+ * const value = 123;
3854
+ * db.table.fromSql`value = ${value}`;
3855
+ * ```
3856
+ *
3857
+ * @param args - SQL expression
3858
+ */
3859
+ fromSql(...args) {
3860
+ return queryFromSql(_clone(this), args);
3861
+ }
3862
+ /**
3863
+ * Adds `ONLY` SQL keyword to the `FROM`.
3864
+ * When selecting from a parent table that has a table inheritance,
3865
+ * setting `only` will make it to select rows only from the parent table.
3866
+ *
3867
+ * ```ts
3868
+ * db.table.only();
3869
+ *
3870
+ * // disabling `only` after being enabled
3871
+ * db.table.only().only(false);
3872
+ * ```
3873
+ *
3874
+ * @param only - can be disabled by passing `false` if was enabled previously.
3875
+ */
3876
+ only(only = true) {
3877
+ const q = _clone(this);
3878
+ q.q.only = only;
3879
+ return q;
3880
+ }
3881
+ }
3882
+
3883
+ function queryWrap(self, query, as = "t") {
3884
+ return _queryAs(queryFrom(query, self), as);
3885
+ }
3886
+ function cloneQueryBaseUnscoped(query) {
3887
+ const q = query.baseQuery.clone();
3888
+ q.q.or = q.q.and = q.q.scopes = void 0;
3889
+ return q;
3890
+ }
3891
+
3720
3892
  const addParserForRawExpression = (q, key, raw) => {
3721
3893
  if (raw.result.value) addColumnParserToQuery(q.q, key, raw.result.value);
3722
3894
  };
@@ -3964,7 +4136,7 @@ const processSelectArg = (q, as, arg, columnAs) => {
3964
4136
  query = value.json(false);
3965
4137
  value.q.coalesceValue = emptyArrSQL;
3966
4138
  } else if (returnType === "pluck") {
3967
- query = value.q.select ? value.wrap(value.baseQuery.clone()).jsonAgg(value.q.select[0]) : value.json(false);
4139
+ query = value.q.select ? value.wrap(cloneQueryBaseUnscoped(value)).jsonAgg(value.q.select[0]) : value.json(false);
3968
4140
  value.q.coalesceValue = emptyArrSQL;
3969
4141
  } else {
3970
4142
  if (returnType === "value" || returnType === "valueOrThrow") {
@@ -4294,171 +4466,6 @@ function _queryGetOptional(self, arg) {
4294
4466
  return _get(self, "value", arg);
4295
4467
  }
4296
4468
 
4297
- const _queryAs = (self, as) => {
4298
- const { q } = self;
4299
- q.as = as;
4300
- q.aliases = {
4301
- ...q.aliases,
4302
- [as]: q.aliases ? _queryResolveAlias(q.aliases, as) : as
4303
- };
4304
- return self;
4305
- };
4306
- const _queryResolveAlias = (aliases, as) => {
4307
- if (!aliases[as]) return as;
4308
- let suffix = 2;
4309
- let privateAs;
4310
- while (aliases[privateAs = as + suffix]) {
4311
- suffix++;
4312
- }
4313
- return privateAs;
4314
- };
4315
- class AsMethods {
4316
- /**
4317
- * Sets table alias:
4318
- *
4319
- * ```ts
4320
- * db.table.as('u').select('u.name');
4321
- *
4322
- * // Can be used in the join:
4323
- * db.table.join(Profile.as('p'), 'p.userId', 'user.id');
4324
- * ```
4325
- *
4326
- * @param as - alias for the table of this query
4327
- */
4328
- as(as) {
4329
- return _queryAs(_clone(this), as);
4330
- }
4331
- }
4332
-
4333
- function queryFrom(self, arg) {
4334
- const data = self.q;
4335
- if (typeof arg === "string") {
4336
- data.as || (data.as = arg);
4337
- const w = data.withShapes?.[arg];
4338
- data.shape = w?.shape ?? orchidCore.emptyObject;
4339
- data.computeds = w?.computeds;
4340
- } else if (orchidCore.isExpression(arg)) {
4341
- data.as || (data.as = "t");
4342
- } else if (Array.isArray(arg)) {
4343
- const { shape } = data;
4344
- let clonedParsers = false;
4345
- for (const item of arg) {
4346
- if (typeof item === "string") {
4347
- const w = data.withShapes[item];
4348
- Object.assign(shape, w.shape);
4349
- if (w.computeds) data.computeds = { ...data.computeds, ...w.computeds };
4350
- for (const key in w.shape) {
4351
- addColumnParserToQuery(
4352
- self,
4353
- key,
4354
- w.shape[key]
4355
- );
4356
- }
4357
- } else if (!orchidCore.isExpression(item)) {
4358
- Object.assign(shape, getShapeFromSelect(item, true));
4359
- if (!clonedParsers) {
4360
- data.parsers = { ...data.parsers };
4361
- clonedParsers = true;
4362
- }
4363
- Object.assign(data.parsers, item.q.parsers);
4364
- }
4365
- }
4366
- } else {
4367
- const q = arg;
4368
- data.as || (data.as = q.q.as || q.table || "t");
4369
- data.shape = getShapeFromSelect(q, true);
4370
- data.parsers = q.q.parsers;
4371
- data.batchParsers = q.q.batchParsers;
4372
- }
4373
- data.from = arg;
4374
- data.selectAllColumns = data.scopes = void 0;
4375
- return self;
4376
- }
4377
- function queryFromSql(self, args) {
4378
- const data = self.q;
4379
- data.as || (data.as = "t");
4380
- data.from = sqlQueryArgsToExpression(args);
4381
- data.selectAllColumns = void 0;
4382
- return self;
4383
- }
4384
- class FromMethods {
4385
- /**
4386
- * Set the `FROM` value, by default the table name is used.
4387
- *
4388
- * `from` determines a set of available tables and columns withing the query,
4389
- * and thus it must not follow `select`, use `select` only after `from`.
4390
- *
4391
- * ```ts
4392
- * // accepts sub-query:
4393
- * db.table.from(db.otherTable.select('foo', 'bar'));
4394
- *
4395
- * // accepts alias of `WITH` expression:
4396
- * q.with('withTable', db.table.select('id', 'name'))
4397
- * .from('withTable')
4398
- * // `select` is after `from`
4399
- * .select('id', 'name');
4400
- * ```
4401
- *
4402
- * `from` can accept multiple sources:
4403
- *
4404
- * ```ts
4405
- * db.table
4406
- * // add a `WITH` statement called `withTable
4407
- * .with('withTable', db.table.select('one'))
4408
- * // select from `withTable` and from `otherTable`
4409
- * .from('withTable', db.otherTable.select('two'))
4410
- * // source names and column names are properly typed when selecting
4411
- * .select('withTable.one', 'otherTable.two');
4412
- * ```
4413
- *
4414
- * @param arg - query or name of CTE table
4415
- */
4416
- from(arg) {
4417
- return queryFrom(_clone(this), arg);
4418
- }
4419
- /**
4420
- * Set the `FROM` value with custom SQL:
4421
- *
4422
- * ```ts
4423
- * const value = 123;
4424
- * db.table.fromSql`value = ${value}`;
4425
- * ```
4426
- *
4427
- * @param args - SQL expression
4428
- */
4429
- fromSql(...args) {
4430
- return queryFromSql(_clone(this), args);
4431
- }
4432
- /**
4433
- * Adds `ONLY` SQL keyword to the `FROM`.
4434
- * When selecting from a parent table that has a table inheritance,
4435
- * setting `only` will make it to select rows only from the parent table.
4436
- *
4437
- * ```ts
4438
- * db.table.only();
4439
- *
4440
- * // disabling `only` after being enabled
4441
- * db.table.only().only(false);
4442
- * ```
4443
- *
4444
- * @param only - can be disabled by passing `false` if was enabled previously.
4445
- */
4446
- only(only = true) {
4447
- const q = _clone(this);
4448
- q.q.only = only;
4449
- return q;
4450
- }
4451
- }
4452
-
4453
- function queryWrap(self, query, as = "t") {
4454
- return _queryAs(queryFrom(query, self), as);
4455
- }
4456
- function cloneQueryBaseUnscoped(query) {
4457
- const q = query.baseQuery.clone();
4458
- q.q.or = q.q.and = q.q.scopes = void 0;
4459
- return q;
4460
- }
4461
-
4462
4469
  class RowToJsonExpression extends orchidCore.Expression {
4463
4470
  constructor(from, one, coalesce) {
4464
4471
  super();
@@ -4496,10 +4503,7 @@ class RowToJsonExpression extends orchidCore.Expression {
4496
4503
  }
4497
4504
  function queryJson(self, coalesce) {
4498
4505
  const inner = self.clone();
4499
- const q = queryWrap(
4500
- inner,
4501
- cloneQueryBaseUnscoped(self)
4502
- );
4506
+ const q = queryWrap(inner, cloneQueryBaseUnscoped(inner));
4503
4507
  _queryGetOptional(
4504
4508
  q,
4505
4509
  new RowToJsonExpression(
@@ -4938,18 +4942,23 @@ const selectToSql = (ctx, table, query, quotedAs, hookSelect = query.hookSelect,
4938
4942
  let quotedTable;
4939
4943
  let columnName;
4940
4944
  let col;
4941
- const index = select.indexOf(".");
4942
- if (index !== -1) {
4943
- const tableName = select.slice(0, index);
4944
- quotedTable = `"${tableName}"`;
4945
- columnName = select.slice(index + 1);
4946
- col = table.q.joinedShapes?.[tableName]?.[columnName];
4947
- sql = col?.data.computed ? col.data.computed.toSQL(ctx, `"${tableName}"`) : `"${tableName}"."${col?.data.name || columnName}"`;
4945
+ if (typeof select === "string") {
4946
+ const index = select.indexOf(".");
4947
+ if (index !== -1) {
4948
+ const tableName = select.slice(0, index);
4949
+ quotedTable = `"${tableName}"`;
4950
+ columnName = select.slice(index + 1);
4951
+ col = table.q.joinedShapes?.[tableName]?.[columnName];
4952
+ sql = col?.data.computed ? col.data.computed.toSQL(ctx, `"${tableName}"`) : `"${tableName}"."${col?.data.name || columnName}"`;
4953
+ } else {
4954
+ quotedTable = quotedAs;
4955
+ columnName = select;
4956
+ col = query.shape[select];
4957
+ sql = simpleColumnToSQL(ctx, query, select, col, quotedAs);
4958
+ }
4948
4959
  } else {
4949
- quotedTable = quotedAs;
4950
- columnName = select;
4951
- col = query.shape[select];
4952
- sql = simpleColumnToSQL(ctx, query, select, col, quotedAs);
4960
+ columnName = column;
4961
+ sql = select.sql;
4953
4962
  }
4954
4963
  let name = columnName;
4955
4964
  if (selected?.[columnName]) {
@@ -4961,7 +4970,7 @@ const selectToSql = (ctx, table, query, quotedAs, hookSelect = query.hookSelect,
4961
4970
  while (selected[name = `${column}${i}`]) i++;
4962
4971
  item.as = name;
4963
4972
  sql += ` "${name}"`;
4964
- } else if (col?.data.name) {
4973
+ } else if (col?.data.name || typeof select === "object") {
4965
4974
  sql += ` "${columnName}"`;
4966
4975
  }
4967
4976
  if (jsonList) jsonList[name] = col;
@@ -5190,6 +5199,7 @@ const queryKeysOfNotSimpleQuery = [
5190
5199
  "for"
5191
5200
  ];
5192
5201
 
5202
+ let fromQuery;
5193
5203
  const pushFromAndAs = (ctx, table, data, quotedAs) => {
5194
5204
  let sql = "FROM ";
5195
5205
  const from = getFrom(ctx, table, data, quotedAs);
@@ -5226,8 +5236,15 @@ const pushFromAndAs = (ctx, table, data, quotedAs) => {
5226
5236
  sql += `, ${fn}(${lang}, ${querySql}) "${as}"`;
5227
5237
  }
5228
5238
  ctx.sql.push(sql);
5239
+ if (fromQuery) {
5240
+ const fq = fromQuery;
5241
+ fromQuery = void 0;
5242
+ return fq;
5243
+ }
5244
+ return;
5229
5245
  };
5230
5246
  const getFrom = (ctx, table, data, quotedAs) => {
5247
+ fromQuery = void 0;
5231
5248
  if (data.from) {
5232
5249
  const { from } = data;
5233
5250
  if (Array.isArray(from)) {
@@ -5254,6 +5271,7 @@ const fromToSql = (ctx, data, from, quotedAs) => {
5254
5271
  } else {
5255
5272
  sql = quoteSchemaAndTable(from.q.schema, from.table);
5256
5273
  }
5274
+ fromQuery = from;
5257
5275
  }
5258
5276
  } else {
5259
5277
  sql = quoteSchemaAndTable(data.schema, from);
@@ -5524,6 +5542,7 @@ const toSQL = (table, options) => {
5524
5542
  if (query.with) {
5525
5543
  pushWithSql(ctx, query.with);
5526
5544
  }
5545
+ let fromQuery;
5527
5546
  if (query.type && query.type !== "upsert") {
5528
5547
  const tableName = table.table ?? query.as;
5529
5548
  if (!tableName) throw new Error(`Table is missing for ${query.type}`);
@@ -5573,9 +5592,7 @@ const toSQL = (table, options) => {
5573
5592
  }
5574
5593
  const aliases = query.group ? [] : void 0;
5575
5594
  pushSelectSql(ctx, table, query, quotedAs, aliases);
5576
- if (table.table || query.from) {
5577
- pushFromAndAs(ctx, table, query, quotedAs);
5578
- }
5595
+ fromQuery = (table.table || query.from) && pushFromAndAs(ctx, table, query, quotedAs) || void 0;
5579
5596
  if (query.join) {
5580
5597
  pushJoinSql(
5581
5598
  ctx,
@@ -5614,9 +5631,19 @@ const toSQL = (table, options) => {
5614
5631
  if (query.order) {
5615
5632
  pushOrderBySql(ctx, query, quotedAs, query.order);
5616
5633
  }
5617
- pushLimitSQL(sql, values, query);
5618
- if (query.offset) {
5619
- sql.push(`OFFSET ${orchidCore.addValue(values, query.offset)}`);
5634
+ if (query.useFromLimitOffset) {
5635
+ const q = fromQuery?.q;
5636
+ if (q.limit) {
5637
+ sql.push(`LIMIT ${orchidCore.addValue(values, q.limit)}`);
5638
+ }
5639
+ if (q.offset) {
5640
+ sql.push(`OFFSET ${orchidCore.addValue(values, q.offset)}`);
5641
+ }
5642
+ } else {
5643
+ pushLimitSQL(sql, values, query);
5644
+ if (query.offset && !query.returnsOne) {
5645
+ sql.push(`OFFSET ${orchidCore.addValue(values, query.offset)}`);
5646
+ }
5620
5647
  }
5621
5648
  if (query.for) {
5622
5649
  sql.push("FOR", query.for.type);
@@ -7021,7 +7048,9 @@ const _chain = (fromQuery, toQuery, rel) => {
7021
7048
  if (
7022
7049
  // `select({ q => q.rel })`: on the first relation it doesn't matter if the parent has chainMultiple
7023
7050
  self.q.subQuery > 1 && self.q.chainMultiple
7024
- ) ; else if (!rel.query.q.returnsOne) {
7051
+ ) {
7052
+ q.returnType = q.returnsOne = q.limit = void 0;
7053
+ } else if (!rel.query.q.returnsOne) {
7025
7054
  q.chainMultiple = true;
7026
7055
  }
7027
7056
  } else {
@@ -10266,7 +10295,7 @@ class JsonMethods {
10266
10295
  * @param coalesce
10267
10296
  */
10268
10297
  json(coalesce) {
10269
- return queryJson(_clone(this), coalesce);
10298
+ return queryJson(this, coalesce);
10270
10299
  }
10271
10300
  }
10272
10301