sql-love 1.1.5 → 1.2.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/README.md CHANGED
@@ -1,15 +1,15 @@
1
- <img alt="SQL Love Logo" src="https://github.com/kensnyder/sql-love/raw/main/assets/sql-love-logo.png?v=1.1.5" width="250" height="208" />
1
+ <img alt="SQL Love Logo" src="https://github.com/kensnyder/sql-love/raw/main/assets/sql-love-logo.png?v=1.2.0" width="250" height="208" />
2
2
 
3
3
  # sql-love
4
4
 
5
- [![Language](https://badgen.net/static/language/TS?v=1.1.5)](https://github.com/search?q=repo:kensnyder/sql-love++language:TypeScript&type=code)
6
- [![Code Coverage](https://codecov.io/gh/kensnyder/sql-love/branch/main/graph/badge.svg?v=1.1.5)](https://codecov.io/gh/kensnyder/sql-love)
5
+ [![Language](https://badgen.net/static/language/TS?v=1.2.0)](https://github.com/search?q=repo:kensnyder/sql-love++language:TypeScript&type=code)
6
+ [![Code Coverage](https://codecov.io/gh/kensnyder/sql-love/branch/main/graph/badge.svg?v=1.2.0)](https://codecov.io/gh/kensnyder/sql-love)
7
7
  ![Dependencies](https://badgen.net/static/dependencies/0/green)
8
8
  ![Tree shakeable](https://badgen.net/static/tree%20shakeable/Yes/green)
9
9
  ![Gzip Size](https://badgen.net/static/gzip%20size/9kb/blue)
10
- [![ISC License](https://badgen.net/static/license/ISC/green?v=1.1.5)](https://opensource.org/licenses/ISC)
10
+ [![ISC License](https://badgen.net/static/license/ISC/green?v=1.2.0)](https://opensource.org/licenses/ISC)
11
11
 
12
- Classes for parsing and building SQL select queries in Node/Bun/Deno.
12
+ Classes for parsing and building SQL select queries in Node/Bun/Workers.
13
13
 
14
14
  ## Installation
15
15
 
@@ -258,6 +258,8 @@ query.where('status', 'NOT IN', ['pending', 'approved']);
258
258
  query.where({ status: ['pending', 'approved'] });
259
259
  query.where({ 'status NOT IN': ['pending', 'approved'] });
260
260
  query.where({ 'status !=': ['pending', 'approved'] });
261
+ // IN and NOT IN with an empty array add no condition at all
262
+ query.where('status', 'IN', []); // (omitted)
261
263
  query.where({ 'status <>': ['pending', 'approved'] });
262
264
 
263
265
  // Question marks for binding
package/dist/index.cjs CHANGED
@@ -337,6 +337,10 @@ function substrCount(haystack, needle) {
337
337
  // src/SelectBuilder/SelectBuilder.ts
338
338
  var isNullish = (v) => v === void 0 || v === null || v === false || Object.is(NaN, v);
339
339
  var defaultEngine = "mysql";
340
+ var trailingOperatorRegex = /\s(=|!=|<>|<=|>=|<|>|(?:NOT\s+)?IN|(?:NOT\s+)?I?LIKE(?:\s+%?\??%?)?|(?:NOT\s+)?BETWEEN)$/i;
341
+ function isStandaloneExpression(column) {
342
+ return /\s/.test(column) && !trailingOperatorRegex.test(column);
343
+ }
340
344
  var SelectBuilder = class _SelectBuilder {
341
345
  /**
342
346
  * The list of values to bind to the query
@@ -847,6 +851,8 @@ UNION
847
851
  * this._conditions(this._wheres, ['price', '=', [10,20]]); // `price` IN(10,20)
848
852
  * this._conditions(this._wheres, ['price', 'IN', [10,20]]); // `price` IN(10,20)
849
853
  * this._conditions(this._wheres, ['price', 'NOT IN', [10,20]]); // `price` NOT IN(10,20)
854
+ * this._conditions(this._wheres, ['price', 'IN', []]); // (condition omitted)
855
+ * this._conditions(this._wheres, ['price', 'NOT IN', []]); // (condition omitted)
850
856
  */
851
857
  _conditions(collection, criteria) {
852
858
  const numArgs = criteria.length;
@@ -860,7 +866,7 @@ UNION
860
866
  if (numArgs === 1) {
861
867
  collection.push(column);
862
868
  return this;
863
- } else if (numArgs === 2 && Array.isArray(operator) && substrCount(column, "?") === operator.length) {
869
+ } else if (numArgs === 2 && Array.isArray(operator) && substrCount(column, "?") === operator.length && (operator.length > 0 || isStandaloneExpression(column))) {
864
870
  const values = operator;
865
871
  const sql = column.replace(/\?/g, () => {
866
872
  this._bindings.push(values.shift());
@@ -908,6 +914,9 @@ UNION
908
914
  operator === "=" ? `${column} IS NULL` : `${column} IS NOT NULL`
909
915
  );
910
916
  } else if (Array.isArray(value)) {
917
+ if (value.length === 0) {
918
+ return this;
919
+ }
911
920
  const inVals = [];
912
921
  for (let i = 0; i < value.length; i++) {
913
922
  inVals.push(`__BOUND_${this._bindings.length}__`);
@@ -979,7 +988,9 @@ UNION
979
988
  for (const [key, value] of Object.entries(conditions)) {
980
989
  const one = [];
981
990
  this._conditions(one, [key, value]);
982
- items.push(one[0]);
991
+ if (one.length > 0) {
992
+ items.push(one[0]);
993
+ }
983
994
  }
984
995
  }
985
996
  const joined = items.join(" OR ");
@@ -995,7 +1006,9 @@ UNION
995
1006
  */
996
1007
  orWhere(conditions) {
997
1008
  const joined = this._orConditions(conditions);
998
- this.where(`(${joined})`);
1009
+ if (joined !== "") {
1010
+ this.where(`(${joined})`);
1011
+ }
999
1012
  return this;
1000
1013
  }
1001
1014
  /**
@@ -1004,7 +1017,9 @@ UNION
1004
1017
  */
1005
1018
  orHaving(conditions) {
1006
1019
  const joined = this._orConditions(conditions);
1007
- this.having(`(${joined})`);
1020
+ if (joined !== "") {
1021
+ this.having(`(${joined})`);
1022
+ }
1008
1023
  return this;
1009
1024
  }
1010
1025
  /**
package/dist/index.d.ts CHANGED
@@ -14,10 +14,6 @@ export type WhereCriteria = [
14
14
  ] | [
15
15
  Record<string, any>
16
16
  ];
17
- /**
18
- * Build a select query
19
- * Class Select
20
- */
21
17
  export declare class SelectBuilder {
22
18
  /**
23
19
  * The list of values to bind to the query
@@ -306,6 +302,8 @@ export declare class SelectBuilder {
306
302
  * this._conditions(this._wheres, ['price', '=', [10,20]]); // `price` IN(10,20)
307
303
  * this._conditions(this._wheres, ['price', 'IN', [10,20]]); // `price` IN(10,20)
308
304
  * this._conditions(this._wheres, ['price', 'NOT IN', [10,20]]); // `price` NOT IN(10,20)
305
+ * this._conditions(this._wheres, ['price', 'IN', []]); // (condition omitted)
306
+ * this._conditions(this._wheres, ['price', 'NOT IN', []]); // (condition omitted)
309
307
  */
310
308
  _conditions(collection: string[], criteria: WhereCriteria): this;
311
309
  /**
package/dist/index.mjs CHANGED
@@ -297,6 +297,10 @@ function substrCount(haystack, needle) {
297
297
  // src/SelectBuilder/SelectBuilder.ts
298
298
  var isNullish = (v) => v === void 0 || v === null || v === false || Object.is(NaN, v);
299
299
  var defaultEngine = "mysql";
300
+ var trailingOperatorRegex = /\s(=|!=|<>|<=|>=|<|>|(?:NOT\s+)?IN|(?:NOT\s+)?I?LIKE(?:\s+%?\??%?)?|(?:NOT\s+)?BETWEEN)$/i;
301
+ function isStandaloneExpression(column) {
302
+ return /\s/.test(column) && !trailingOperatorRegex.test(column);
303
+ }
300
304
  var SelectBuilder = class _SelectBuilder {
301
305
  /**
302
306
  * The list of values to bind to the query
@@ -807,6 +811,8 @@ UNION
807
811
  * this._conditions(this._wheres, ['price', '=', [10,20]]); // `price` IN(10,20)
808
812
  * this._conditions(this._wheres, ['price', 'IN', [10,20]]); // `price` IN(10,20)
809
813
  * this._conditions(this._wheres, ['price', 'NOT IN', [10,20]]); // `price` NOT IN(10,20)
814
+ * this._conditions(this._wheres, ['price', 'IN', []]); // (condition omitted)
815
+ * this._conditions(this._wheres, ['price', 'NOT IN', []]); // (condition omitted)
810
816
  */
811
817
  _conditions(collection, criteria) {
812
818
  const numArgs = criteria.length;
@@ -820,7 +826,7 @@ UNION
820
826
  if (numArgs === 1) {
821
827
  collection.push(column);
822
828
  return this;
823
- } else if (numArgs === 2 && Array.isArray(operator) && substrCount(column, "?") === operator.length) {
829
+ } else if (numArgs === 2 && Array.isArray(operator) && substrCount(column, "?") === operator.length && (operator.length > 0 || isStandaloneExpression(column))) {
824
830
  const values = operator;
825
831
  const sql = column.replace(/\?/g, () => {
826
832
  this._bindings.push(values.shift());
@@ -868,6 +874,9 @@ UNION
868
874
  operator === "=" ? `${column} IS NULL` : `${column} IS NOT NULL`
869
875
  );
870
876
  } else if (Array.isArray(value)) {
877
+ if (value.length === 0) {
878
+ return this;
879
+ }
871
880
  const inVals = [];
872
881
  for (let i = 0; i < value.length; i++) {
873
882
  inVals.push(`__BOUND_${this._bindings.length}__`);
@@ -939,7 +948,9 @@ UNION
939
948
  for (const [key, value] of Object.entries(conditions)) {
940
949
  const one = [];
941
950
  this._conditions(one, [key, value]);
942
- items.push(one[0]);
951
+ if (one.length > 0) {
952
+ items.push(one[0]);
953
+ }
943
954
  }
944
955
  }
945
956
  const joined = items.join(" OR ");
@@ -955,7 +966,9 @@ UNION
955
966
  */
956
967
  orWhere(conditions) {
957
968
  const joined = this._orConditions(conditions);
958
- this.where(`(${joined})`);
969
+ if (joined !== "") {
970
+ this.where(`(${joined})`);
971
+ }
959
972
  return this;
960
973
  }
961
974
  /**
@@ -964,7 +977,9 @@ UNION
964
977
  */
965
978
  orHaving(conditions) {
966
979
  const joined = this._orConditions(conditions);
967
- this.having(`(${joined})`);
980
+ if (joined !== "") {
981
+ this.having(`(${joined})`);
982
+ }
968
983
  return this;
969
984
  }
970
985
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sql-love",
3
- "version": "1.1.5",
3
+ "version": "1.2.0",
4
4
  "description": "Build SQL queries with JavaScript",
5
5
  "type": "module",
6
6
  "engines": {
@@ -55,7 +55,7 @@
55
55
  "@types/bun": "latest",
56
56
  "@types/node": "latest",
57
57
  "dts-bundle-generator": "9.5.1",
58
- "prettier": "3.9.9",
58
+ "prettier": "3.9.10",
59
59
  "prettier-plugin-organize-imports": "4.3.0",
60
60
  "typescript": "5.9.3"
61
61
  }