pqb 0.26.0 → 0.26.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.d.ts CHANGED
@@ -863,6 +863,35 @@ declare class Join {
863
863
  *
864
864
  * When no matching record is found, it will skip records of the main table.
865
865
  *
866
+ * When joining the same table with the same condition more than once, duplicated joins will be ignored:
867
+ *
868
+ * ```ts
869
+ * // joining a relation
870
+ * db.post.join('comments').join('comments');
871
+ *
872
+ * // joining a table with a condition
873
+ * db.post
874
+ * .join('comments', 'comments.postId', 'post.id')
875
+ * .join('comments', 'comments.postId', 'post.id');
876
+ * ```
877
+ *
878
+ * Both queries will produce SQL with only 1 join
879
+ *
880
+ * ```sql
881
+ * SELECT * FROM post JOIN comments ON comments.postId = post.id
882
+ * ```
883
+ *
884
+ * However, this is only possible if the join has no dynamic values:
885
+ *
886
+ * ```ts
887
+ * db.post
888
+ * .join('comments', (q) => q.where({ rating: { gt: 5 } }))
889
+ * .join('comments', (q) => q.where({ rating: { gt: 5 } }));
890
+ * ```
891
+ *
892
+ * Both joins above have the same `{ gt: 5 }`, but still, the `5` is a dynamic value and in this case joins will be duplicated,
893
+ * resulting in a database error.
894
+ *
866
895
  * ### join relation
867
896
  *
868
897
  * When relations are defined between the tables, you can join them by a relation name.
package/dist/index.js CHANGED
@@ -991,6 +991,7 @@ const processWhere = (ands, ctx, table, query, data, quotedAs) => {
991
991
  });
992
992
  } else if (key === "EXISTS") {
993
993
  const joinItems = Array.isArray(value[0]) ? value : [value];
994
+ const joinSet = joinItems.length > 1 ? /* @__PURE__ */ new Set() : null;
994
995
  for (const args of joinItems) {
995
996
  const { target, conditions } = processJoinItem(
996
997
  ctx,
@@ -999,7 +1000,13 @@ const processWhere = (ands, ctx, table, query, data, quotedAs) => {
999
1000
  args,
1000
1001
  quotedAs
1001
1002
  );
1002
- ands.push(`EXISTS (SELECT 1 FROM ${target} WHERE ${conditions})`);
1003
+ const sql = `EXISTS (SELECT 1 FROM ${target} WHERE ${conditions})`;
1004
+ if (joinSet) {
1005
+ if (joinSet.has(sql))
1006
+ continue;
1007
+ joinSet.add(sql);
1008
+ }
1009
+ ands.push(sql);
1003
1010
  }
1004
1011
  } else if (key === "SEARCH") {
1005
1012
  const search = value;
@@ -1316,15 +1323,15 @@ const getObjectOrRawConditions = (ctx, query, data, quotedAs, joinAs, joinShape)
1316
1323
  };
1317
1324
  const pushJoinSql = (ctx, table, query, quotedAs) => {
1318
1325
  var _a;
1326
+ const joinSet = query.join.length > 1 ? /* @__PURE__ */ new Set() : null;
1319
1327
  for (const item of query.join) {
1328
+ let sql;
1320
1329
  if (Array.isArray(item)) {
1321
1330
  const q = item[1];
1322
1331
  const { aliasValue } = ctx;
1323
1332
  ctx.aliasValue = true;
1324
1333
  const as = item[2];
1325
- ctx.sql.push(
1326
- `${item[0]} LATERAL (${q.toSQL(ctx).text}) "${((_a = query.joinOverrides) == null ? void 0 : _a[as]) || as}" ON true`
1327
- );
1334
+ sql = `${item[0]} LATERAL (${q.toSQL(ctx).text}) "${((_a = query.joinOverrides) == null ? void 0 : _a[as]) || as}" ON true`;
1328
1335
  ctx.aliasValue = aliasValue;
1329
1336
  } else {
1330
1337
  const { target, conditions } = processJoinItem(
@@ -1334,10 +1341,14 @@ const pushJoinSql = (ctx, table, query, quotedAs) => {
1334
1341
  item,
1335
1342
  quotedAs
1336
1343
  );
1337
- ctx.sql.push(item.type, target);
1338
- if (conditions)
1339
- ctx.sql.push("ON", conditions);
1344
+ sql = conditions ? `${item.type} ${target} ON ${conditions}` : `${item.type} ${target} ON true`;
1345
+ }
1346
+ if (joinSet) {
1347
+ if (joinSet.has(sql))
1348
+ continue;
1349
+ joinSet.add(sql);
1340
1350
  }
1351
+ ctx.sql.push(sql);
1341
1352
  }
1342
1353
  };
1343
1354
  const skipQueryKeysForSubQuery = {
@@ -2921,9 +2932,17 @@ const pushDeleteSql = (ctx, table, query, quotedAs) => {
2921
2932
  let conditions;
2922
2933
  if ((_a = query.join) == null ? void 0 : _a.length) {
2923
2934
  const items = [];
2935
+ const joinSet = query.join.length > 1 ? /* @__PURE__ */ new Set() : null;
2924
2936
  for (const item of query.join) {
2925
2937
  if (!Array.isArray(item)) {
2926
- items.push(processJoinItem(ctx, table, query, item, quotedAs));
2938
+ const join = processJoinItem(ctx, table, query, item, quotedAs);
2939
+ const key = `${join.target}${join.conditions}`;
2940
+ if (joinSet) {
2941
+ if (joinSet.has(key))
2942
+ continue;
2943
+ joinSet.add(key);
2944
+ }
2945
+ items.push(join);
2927
2946
  }
2928
2947
  }
2929
2948
  if (items.length) {
@@ -7357,6 +7376,35 @@ class Join {
7357
7376
  *
7358
7377
  * When no matching record is found, it will skip records of the main table.
7359
7378
  *
7379
+ * When joining the same table with the same condition more than once, duplicated joins will be ignored:
7380
+ *
7381
+ * ```ts
7382
+ * // joining a relation
7383
+ * db.post.join('comments').join('comments');
7384
+ *
7385
+ * // joining a table with a condition
7386
+ * db.post
7387
+ * .join('comments', 'comments.postId', 'post.id')
7388
+ * .join('comments', 'comments.postId', 'post.id');
7389
+ * ```
7390
+ *
7391
+ * Both queries will produce SQL with only 1 join
7392
+ *
7393
+ * ```sql
7394
+ * SELECT * FROM post JOIN comments ON comments.postId = post.id
7395
+ * ```
7396
+ *
7397
+ * However, this is only possible if the join has no dynamic values:
7398
+ *
7399
+ * ```ts
7400
+ * db.post
7401
+ * .join('comments', (q) => q.where({ rating: { gt: 5 } }))
7402
+ * .join('comments', (q) => q.where({ rating: { gt: 5 } }));
7403
+ * ```
7404
+ *
7405
+ * Both joins above have the same `{ gt: 5 }`, but still, the `5` is a dynamic value and in this case joins will be duplicated,
7406
+ * resulting in a database error.
7407
+ *
7360
7408
  * ### join relation
7361
7409
  *
7362
7410
  * When relations are defined between the tables, you can join them by a relation name.