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