pqb 0.49.0 → 0.50.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") {
@@ -4074,7 +4246,16 @@ const handleComputed = (q, computeds, column) => {
4074
4246
  };
4075
4247
  const getShapeFromSelect = (q, isSubQuery) => {
4076
4248
  const query = q.q;
4077
- const { select, shape } = query;
4249
+ const { shape } = query;
4250
+ let select;
4251
+ if (query.selectedComputeds) {
4252
+ select = query.select ? [...query.select] : [];
4253
+ for (const key in query.selectedComputeds) {
4254
+ select.push(...query.selectedComputeds[key].deps);
4255
+ }
4256
+ } else {
4257
+ select = query.select;
4258
+ }
4078
4259
  let result;
4079
4260
  if (!select) {
4080
4261
  if (isSubQuery) {
@@ -4133,18 +4314,33 @@ const addColumnToShapeFromSelect = (q, arg, shape, query, result, isSubQuery, ke
4133
4314
  result[key || column] = shape[column];
4134
4315
  } else {
4135
4316
  const it = query.joinedShapes?.[table]?.[column];
4136
- if (it) result[key || column] = maybeUnNameColumn(it, isSubQuery);
4317
+ if (it)
4318
+ result[key || column] = mapSubSelectColumn(
4319
+ it,
4320
+ isSubQuery
4321
+ );
4137
4322
  }
4138
4323
  } else if (arg === "*") {
4139
4324
  for (const key2 in shape) {
4140
- result[key2] = maybeUnNameColumn(shape[key2], isSubQuery);
4325
+ result[key2] = mapSubSelectColumn(
4326
+ shape[key2],
4327
+ isSubQuery
4328
+ );
4141
4329
  }
4142
4330
  } else {
4143
- result[key || arg] = maybeUnNameColumn(shape[arg], isSubQuery);
4331
+ result[key || arg] = mapSubSelectColumn(
4332
+ shape[arg],
4333
+ isSubQuery
4334
+ );
4144
4335
  }
4145
4336
  };
4146
- const maybeUnNameColumn = (column, isSubQuery) => {
4147
- return isSubQuery && column?.data.name ? setColumnData(column, "name", void 0) : column;
4337
+ const mapSubSelectColumn = (column, isSubQuery) => {
4338
+ if (!isSubQuery || !column || !column.data.name && !column.data.explicitSelect) {
4339
+ return column;
4340
+ }
4341
+ const cloned = Object.create(column);
4342
+ cloned.data = { ...column.data, name: void 0, explicitSelect: void 0 };
4343
+ return cloned;
4148
4344
  };
4149
4345
  function _querySelect(q, args) {
4150
4346
  var _a;
@@ -4268,171 +4464,6 @@ function _queryGetOptional(self, arg) {
4268
4464
  return _get(self, "value", arg);
4269
4465
  }
4270
4466
 
4271
- const _queryAs = (self, as) => {
4272
- const { q } = self;
4273
- q.as = as;
4274
- q.aliases = {
4275
- ...q.aliases,
4276
- [as]: q.aliases ? _queryResolveAlias(q.aliases, as) : as
4277
- };
4278
- return self;
4279
- };
4280
- const _queryResolveAlias = (aliases, as) => {
4281
- if (!aliases[as]) return as;
4282
- let suffix = 2;
4283
- let privateAs;
4284
- while (aliases[privateAs = as + suffix]) {
4285
- suffix++;
4286
- }
4287
- return privateAs;
4288
- };
4289
- class AsMethods {
4290
- /**
4291
- * Sets table alias:
4292
- *
4293
- * ```ts
4294
- * db.table.as('u').select('u.name');
4295
- *
4296
- * // Can be used in the join:
4297
- * db.table.join(Profile.as('p'), 'p.userId', 'user.id');
4298
- * ```
4299
- *
4300
- * @param as - alias for the table of this query
4301
- */
4302
- as(as) {
4303
- return _queryAs(_clone(this), as);
4304
- }
4305
- }
4306
-
4307
- function queryFrom(self, arg) {
4308
- const data = self.q;
4309
- if (typeof arg === "string") {
4310
- data.as || (data.as = arg);
4311
- const w = data.withShapes?.[arg];
4312
- data.shape = w?.shape ?? emptyObject;
4313
- data.computeds = w?.computeds;
4314
- } else if (isExpression(arg)) {
4315
- data.as || (data.as = "t");
4316
- } else if (Array.isArray(arg)) {
4317
- const { shape } = data;
4318
- let clonedParsers = false;
4319
- for (const item of arg) {
4320
- if (typeof item === "string") {
4321
- const w = data.withShapes[item];
4322
- Object.assign(shape, w.shape);
4323
- if (w.computeds) data.computeds = { ...data.computeds, ...w.computeds };
4324
- for (const key in w.shape) {
4325
- addColumnParserToQuery(
4326
- self,
4327
- key,
4328
- w.shape[key]
4329
- );
4330
- }
4331
- } else if (!isExpression(item)) {
4332
- Object.assign(shape, getShapeFromSelect(item, true));
4333
- if (!clonedParsers) {
4334
- data.parsers = { ...data.parsers };
4335
- clonedParsers = true;
4336
- }
4337
- Object.assign(data.parsers, item.q.parsers);
4338
- }
4339
- }
4340
- } else {
4341
- const q = arg;
4342
- data.as || (data.as = q.q.as || q.table || "t");
4343
- data.shape = getShapeFromSelect(q, true);
4344
- data.parsers = q.q.parsers;
4345
- data.batchParsers = q.q.batchParsers;
4346
- }
4347
- data.from = arg;
4348
- data.selectAllColumns = data.scopes = void 0;
4349
- return self;
4350
- }
4351
- function queryFromSql(self, args) {
4352
- const data = self.q;
4353
- data.as || (data.as = "t");
4354
- data.from = sqlQueryArgsToExpression(args);
4355
- data.selectAllColumns = void 0;
4356
- return self;
4357
- }
4358
- class FromMethods {
4359
- /**
4360
- * Set the `FROM` value, by default the table name is used.
4361
- *
4362
- * `from` determines a set of available tables and columns withing the query,
4363
- * and thus it must not follow `select`, use `select` only after `from`.
4364
- *
4365
- * ```ts
4366
- * // accepts sub-query:
4367
- * db.table.from(db.otherTable.select('foo', 'bar'));
4368
- *
4369
- * // accepts alias of `WITH` expression:
4370
- * q.with('withTable', db.table.select('id', 'name'))
4371
- * .from('withTable')
4372
- * // `select` is after `from`
4373
- * .select('id', 'name');
4374
- * ```
4375
- *
4376
- * `from` can accept multiple sources:
4377
- *
4378
- * ```ts
4379
- * db.table
4380
- * // add a `WITH` statement called `withTable
4381
- * .with('withTable', db.table.select('one'))
4382
- * // select from `withTable` and from `otherTable`
4383
- * .from('withTable', db.otherTable.select('two'))
4384
- * // source names and column names are properly typed when selecting
4385
- * .select('withTable.one', 'otherTable.two');
4386
- * ```
4387
- *
4388
- * @param arg - query or name of CTE table
4389
- */
4390
- from(arg) {
4391
- return queryFrom(_clone(this), arg);
4392
- }
4393
- /**
4394
- * Set the `FROM` value with custom SQL:
4395
- *
4396
- * ```ts
4397
- * const value = 123;
4398
- * db.table.fromSql`value = ${value}`;
4399
- * ```
4400
- *
4401
- * @param args - SQL expression
4402
- */
4403
- fromSql(...args) {
4404
- return queryFromSql(_clone(this), args);
4405
- }
4406
- /**
4407
- * Adds `ONLY` SQL keyword to the `FROM`.
4408
- * When selecting from a parent table that has a table inheritance,
4409
- * setting `only` will make it to select rows only from the parent table.
4410
- *
4411
- * ```ts
4412
- * db.table.only();
4413
- *
4414
- * // disabling `only` after being enabled
4415
- * db.table.only().only(false);
4416
- * ```
4417
- *
4418
- * @param only - can be disabled by passing `false` if was enabled previously.
4419
- */
4420
- only(only = true) {
4421
- const q = _clone(this);
4422
- q.q.only = only;
4423
- return q;
4424
- }
4425
- }
4426
-
4427
- function queryWrap(self, query, as = "t") {
4428
- return _queryAs(queryFrom(query, self), as);
4429
- }
4430
- function cloneQueryBaseUnscoped(query) {
4431
- const q = query.baseQuery.clone();
4432
- q.q.or = q.q.and = q.q.scopes = void 0;
4433
- return q;
4434
- }
4435
-
4436
4467
  class RowToJsonExpression extends Expression {
4437
4468
  constructor(from, one, coalesce) {
4438
4469
  super();
@@ -4470,10 +4501,7 @@ class RowToJsonExpression extends Expression {
4470
4501
  }
4471
4502
  function queryJson(self, coalesce) {
4472
4503
  const inner = self.clone();
4473
- const q = queryWrap(
4474
- inner,
4475
- cloneQueryBaseUnscoped(self)
4476
- );
4504
+ const q = queryWrap(inner, cloneQueryBaseUnscoped(inner));
4477
4505
  _queryGetOptional(
4478
4506
  q,
4479
4507
  new RowToJsonExpression(
@@ -4912,18 +4940,23 @@ const selectToSql = (ctx, table, query, quotedAs, hookSelect = query.hookSelect,
4912
4940
  let quotedTable;
4913
4941
  let columnName;
4914
4942
  let col;
4915
- const index = select.indexOf(".");
4916
- if (index !== -1) {
4917
- const tableName = select.slice(0, index);
4918
- quotedTable = `"${tableName}"`;
4919
- columnName = select.slice(index + 1);
4920
- col = table.q.joinedShapes?.[tableName]?.[columnName];
4921
- 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
+ }
4922
4957
  } else {
4923
- quotedTable = quotedAs;
4924
- columnName = select;
4925
- col = query.shape[select];
4926
- sql = simpleColumnToSQL(ctx, query, select, col, quotedAs);
4958
+ columnName = column;
4959
+ sql = select.sql;
4927
4960
  }
4928
4961
  let name = columnName;
4929
4962
  if (selected?.[columnName]) {
@@ -4935,7 +4968,7 @@ const selectToSql = (ctx, table, query, quotedAs, hookSelect = query.hookSelect,
4935
4968
  while (selected[name = `${column}${i}`]) i++;
4936
4969
  item.as = name;
4937
4970
  sql += ` "${name}"`;
4938
- } else if (col?.data.name) {
4971
+ } else if (col?.data.name || typeof select === "object") {
4939
4972
  sql += ` "${columnName}"`;
4940
4973
  }
4941
4974
  if (jsonList) jsonList[name] = col;
@@ -5164,6 +5197,7 @@ const queryKeysOfNotSimpleQuery = [
5164
5197
  "for"
5165
5198
  ];
5166
5199
 
5200
+ let fromQuery;
5167
5201
  const pushFromAndAs = (ctx, table, data, quotedAs) => {
5168
5202
  let sql = "FROM ";
5169
5203
  const from = getFrom(ctx, table, data, quotedAs);
@@ -5200,8 +5234,15 @@ const pushFromAndAs = (ctx, table, data, quotedAs) => {
5200
5234
  sql += `, ${fn}(${lang}, ${querySql}) "${as}"`;
5201
5235
  }
5202
5236
  ctx.sql.push(sql);
5237
+ if (fromQuery) {
5238
+ const fq = fromQuery;
5239
+ fromQuery = void 0;
5240
+ return fq;
5241
+ }
5242
+ return;
5203
5243
  };
5204
5244
  const getFrom = (ctx, table, data, quotedAs) => {
5245
+ fromQuery = void 0;
5205
5246
  if (data.from) {
5206
5247
  const { from } = data;
5207
5248
  if (Array.isArray(from)) {
@@ -5228,6 +5269,7 @@ const fromToSql = (ctx, data, from, quotedAs) => {
5228
5269
  } else {
5229
5270
  sql = quoteSchemaAndTable(from.q.schema, from.table);
5230
5271
  }
5272
+ fromQuery = from;
5231
5273
  }
5232
5274
  } else {
5233
5275
  sql = quoteSchemaAndTable(data.schema, from);
@@ -5498,6 +5540,7 @@ const toSQL = (table, options) => {
5498
5540
  if (query.with) {
5499
5541
  pushWithSql(ctx, query.with);
5500
5542
  }
5543
+ let fromQuery;
5501
5544
  if (query.type && query.type !== "upsert") {
5502
5545
  const tableName = table.table ?? query.as;
5503
5546
  if (!tableName) throw new Error(`Table is missing for ${query.type}`);
@@ -5547,9 +5590,7 @@ const toSQL = (table, options) => {
5547
5590
  }
5548
5591
  const aliases = query.group ? [] : void 0;
5549
5592
  pushSelectSql(ctx, table, query, quotedAs, aliases);
5550
- if (table.table || query.from) {
5551
- pushFromAndAs(ctx, table, query, quotedAs);
5552
- }
5593
+ fromQuery = (table.table || query.from) && pushFromAndAs(ctx, table, query, quotedAs) || void 0;
5553
5594
  if (query.join) {
5554
5595
  pushJoinSql(
5555
5596
  ctx,
@@ -5588,9 +5629,19 @@ const toSQL = (table, options) => {
5588
5629
  if (query.order) {
5589
5630
  pushOrderBySql(ctx, query, quotedAs, query.order);
5590
5631
  }
5591
- pushLimitSQL(sql, values, query);
5592
- if (query.offset) {
5593
- 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
+ }
5594
5645
  }
5595
5646
  if (query.for) {
5596
5647
  sql.push("FOR", query.for.type);
@@ -6995,7 +7046,9 @@ const _chain = (fromQuery, toQuery, rel) => {
6995
7046
  if (
6996
7047
  // `select({ q => q.rel })`: on the first relation it doesn't matter if the parent has chainMultiple
6997
7048
  self.q.subQuery > 1 && self.q.chainMultiple
6998
- ) ; else if (!rel.query.q.returnsOne) {
7049
+ ) {
7050
+ q.returnType = q.returnsOne = q.limit = void 0;
7051
+ } else if (!rel.query.q.returnsOne) {
6999
7052
  q.chainMultiple = true;
7000
7053
  }
7001
7054
  } else {
@@ -10240,7 +10293,7 @@ class JsonMethods {
10240
10293
  * @param coalesce
10241
10294
  */
10242
10295
  json(coalesce) {
10243
- return queryJson(_clone(this), coalesce);
10296
+ return queryJson(this, coalesce);
10244
10297
  }
10245
10298
  }
10246
10299