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 +7 -5
- package/dist/index.cjs +19 -4
- package/dist/index.d.ts +2 -4
- package/dist/index.mjs +19 -4
- package/package.json +2 -2
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
|
+
<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
|
-
[](https://github.com/search?q=repo:kensnyder/sql-love++language:TypeScript&type=code)
|
|
6
|
+
[](https://codecov.io/gh/kensnyder/sql-love)
|
|
7
7
|

|
|
8
8
|

|
|
9
9
|

|
|
10
|
-
[](https://opensource.org/licenses/ISC)
|
|
11
11
|
|
|
12
|
-
Classes for parsing and building SQL select queries in Node/Bun/
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
58
|
+
"prettier": "3.9.10",
|
|
59
59
|
"prettier-plugin-organize-imports": "4.3.0",
|
|
60
60
|
"typescript": "5.9.3"
|
|
61
61
|
}
|