sql-love 1.0.3 → 1.0.4
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 +52 -32
- package/dist/index.cjs +16 -0
- package/dist/index.d.ts +732 -9
- package/dist/index.mjs +16 -0
- package/package.json +27 -10
- package/.github/workflows/node.js.yml +0 -37
- package/.prettierrc.json +0 -13
- package/CHANGELOG.md +0 -39
- package/CONTRIBUTING.md +0 -85
- package/assets/sql-love-logo.png +0 -0
- package/codecov.yml +0 -7
- package/dist/index.js +0 -9
- package/dist/src/Parser/Parser.d.ts +0 -157
- package/dist/src/Parser/Parser.js +0 -304
- package/dist/src/SelectBuilder/SelectBuilder.d.ts +0 -379
- package/dist/src/SelectBuilder/SelectBuilder.js +0 -810
- package/dist/src/extractGrouped/extractGrouped.d.ts +0 -17
- package/dist/src/extractGrouped/extractGrouped.js +0 -31
- package/dist/src/extractIndexed/extractIndexed.d.ts +0 -12
- package/dist/src/extractIndexed/extractIndexed.js +0 -23
- package/dist/src/extractLookup/extractLookup.d.ts +0 -9
- package/dist/src/extractLookup/extractLookup.js +0 -21
- package/dist/src/getPagination/getPagination.d.ts +0 -16
- package/dist/src/getPagination/getPagination.js +0 -40
- package/dist/src/runMysql/runMysql.d.ts +0 -58
- package/dist/src/runMysql/runMysql.js +0 -61
- package/dist/src/runPrisma/runPrisma.d.ts +0 -41
- package/dist/src/runPrisma/runPrisma.js +0 -34
- package/dist/src/substrCount/substrCount.d.ts +0 -6
- package/dist/src/substrCount/substrCount.js +0 -14
- package/dist/src/toSafeJson/toSafeJson.d.ts +0 -25
- package/dist/src/toSafeJson/toSafeJson.js +0 -45
- package/index.ts +0 -19
- package/src/Parser/Parser.spec.ts +0 -226
- package/src/Parser/Parser.ts +0 -325
- package/src/SelectBuilder/SelectBuilder.spec.ts +0 -785
- package/src/SelectBuilder/SelectBuilder.ts +0 -914
- package/src/extractGrouped/extractGrouped.spec.ts +0 -43
- package/src/extractGrouped/extractGrouped.ts +0 -36
- package/src/extractIndexed/extractIndexed.spec.ts +0 -40
- package/src/extractIndexed/extractIndexed.ts +0 -28
- package/src/extractLookup/extractLookup.spec.ts +0 -38
- package/src/extractLookup/extractLookup.ts +0 -33
- package/src/getPagination/getPagination.spec.ts +0 -75
- package/src/getPagination/getPagination.ts +0 -42
- package/src/runMysql/runMysql.spec.ts +0 -286
- package/src/runMysql/runMysql.ts +0 -106
- package/src/runPrisma/runPrisma.spec.ts +0 -99
- package/src/runPrisma/runPrisma.ts +0 -75
- package/src/substrCount/substrCount.spec.ts +0 -29
- package/src/substrCount/substrCount.ts +0 -14
- package/src/toSafeJson/toSafeJson.spec.ts +0 -28
- package/src/toSafeJson/toSafeJson.ts +0 -56
- package/tsconfig.build.json +0 -10
- package/tsconfig.json +0 -22
- package/vitest.config.ts +0 -11
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
var c=class{query;constructor(t){this.query=t}_stripComments(t){return t=t.replace(/\/\*[\s\S]*?\*\//g,""),t=t.replace(/--([\r\n]|\s+[^\r\n]+[\r\n])/g,""),t=t.replace(/#[^\r\n]+[\r\n]/g,""),t}_extractSubQueries(t){let e={},n=0,s=r=>{let o=`~~SUBQUERY_${n++}~~`;return e[o]=r,o};return t=t.replace(/\(\s*SELECT\s+.+\)\s+AS\s+[^\s,]+/,s),t=t.replace(/\bIF\s*\(.+\)\s+AS\s+[^\s,]+/,s),t=t.replace(/\bIN\s*\(\s*SELECT\s.+?\)/,s),{sql:t,subQueries:e}}_injectSubQueries(t){let e=s=>t[s]||s,n=s=>s.replace(/~~SUBQUERY_\d+~~/g,e);this.query._columns=this.query._columns.map(e),this.query._joins=this.query._joins.map(n),this.query._wheres=this.query._wheres.map(n),this.query._havings=this.query._havings.map(n)}_split(t){let e=/(?:^|\s)(SELECT|FROM|(?:INNER|LEFT\s+OUTER|RIGHT\s+OUTER|LEFT|RIGHT|CROSS|FULL|FULL\s+OUTER)\s+JOIN|WHERE|GROUP\s+BY|HAVING|ORDER\s+BY|LIMIT|OFFSET|FETCH\s+NEXT)\b/i;return t.split(e)}parse(t){let e=this._stripComments(t),{sql:n,subQueries:s}=this._extractSubQueries(e),r=this._split(n),o=1;for(;o<r.length;){let l=r[o++].trim().toUpperCase().replace(/\s+/g,"_"),h=r[o++].trim(),a=`_handle${l}`;this[a](h)}return this._injectSubQueries(s),!0}_handleSELECT(t){let e=t.split(/s*,s*/),n="";e.forEach((s,r)=>{if(r===0){let o=/^(SQL_CALC_FOUND_ROWS)\s+/i,u=s.match(o);u&&(this.query.option(u[1]),s=s.replace(o,""))}n.length?s.indexOf(")")>0?(n+=s,this.query.column(n.trim()),n=""):n+=s+",":s.match(/\([^)]+$/)?n=s+",":this.query.column(s.trim())})}_handleFROM(t){t.split(/\s*,\s*/).forEach(n=>this.query.table(n))}_handleINNER_JOIN(t){this.query.innerJoin(t)}_handleLEFT_JOIN(t){this.query.leftJoin(t)}_handleLEFT_OUTER_JOIN(t){this.query.leftOuterJoin(t)}_handleRIGHT_JOIN(t){this.query.rightJoin(t)}_handleRIGHT_OUTER_JOIN(t){this.query.rightOuterJoin(t)}_handleCROSS_JOIN(t){this.query.crossJoin(t)}_handleFULL_JOIN(t){this.query.fullJoin(t)}_handleFULL_OUTER_JOIN(t){this.query.fullOuterJoin(t)}_handleWHERE(t){/^(1|'1'|true)$/i.test(t)?this.query._wheres.push(t):this._handleConditions("where",t)}_handleHAVING(t){this._handleConditions("having",t)}_handleConditions(t,e){e.split(/\bAND\b/i).forEach(s=>{let r=s.split(/\bOR\b/i).map(o=>o.trim());if(r.length===1){let o=t;this.query[o](r[0])}else{let o=t==="where"?"orWhere":"orHaving";this.query[o](r.map(u=>[u]))}})}_handleGROUP_BY(t){t.split(/\s*,\s*/).forEach(n=>this.query.groupBy(n))}_handleORDER_BY(t){t.split(/\s*,\s*/).forEach(n=>this.query.orderBy(n))}_handleLIMIT(t){let e=t.match(/^(\d+|\?|:\w+)\s*,\s*(\d+|\?|:\w+)$/);e?(this.query.offset(e[1]),this.query.limit(e[2])):(t=t.replace(/ ROWS$/i,""),this.query.limit(t))}_handleOFFSET(t){t=t.replace(/^(\d+) ROWS$/i,"$1"),this.query.offset(t)}_handleFETCH_NEXT(t){t=t.replace(/^(\d+) ROWS ONLY$/i,"$1"),this.query.limit(t)}};function m(i,t){let e=0,n=i.indexOf(t);for(;n!==-1;)e+=1,n=i.indexOf(t,n+1);return e}var _=i=>i==null||i===!1||isNaN(i),f="mysql",y=class i{_bindings=[];_options=[];_tables=[];_columns=[];_joins=[];_wheres=[];_groupBys=[];_havings=[];_orderBys=[];_limit;_offset;_page;constructor(t=null,e=null){if(t){if(e){let n=Object.keys(e),s=new RegExp(`:(${n.join("|")})`,"g");t=t.replace(s,(r,o)=>(this._bindings.push(e[o]),`__BOUND_${this._bindings.length-1}__`))}new c(this).parse(t)}}static setDefaultEngine(t){return f=t,i}compile({engine:t=f,bindingIndex:e=1}={}){let n=["SELECT",this._options.length?` ${this._options.join(`
|
|
2
|
+
`)}`:null,this._columns.length?` ${this._columns.join(`,
|
|
3
|
+
`)}`:` *
|
|
4
|
+
`,`FROM ${this._tables.join(", ")}`,this._joins.length?this._joins.join(`
|
|
5
|
+
`):null,this._wheres.length?`WHERE ${this._wheres.join(`
|
|
6
|
+
AND `)}`:null,this._groupBys.length?`GROUP BY ${this._groupBys.join(`,
|
|
7
|
+
`)}`:null,this._havings.length?`HAVING ${this._havings.join(`
|
|
8
|
+
AND `)}`:null,this._orderBys.length?`ORDER BY ${this._orderBys.join(`,
|
|
9
|
+
`)}`:null];if(this._page>0){let l=(this._page-1)*this._limit;n.push(this._compileOFFSET(t,l)),n.push(this._compileLIMIT(t,this._limit))}else this._offset&&n.push(this._compileOFFSET(t,this._offset)),this._limit&&n.push(this._compileLIMIT(t,this._limit));let s=n.filter(Boolean).join(`
|
|
10
|
+
`).trim(),r,o=[];if(t==="pg"){let l=e;r=(h,a)=>(o.push(this._bindings[a]),"$"+l++)}else r=(l,h)=>(o.push(this._bindings[h]),"?");return{sql:s.replace(/__BOUND_(\d+)__/g,r),bindings:o}}_compileLIMIT(t,e){if(t==="pg"||t==="mysql")return`LIMIT ${e}`;if(t==="mssql")return`FETCH NEXT ${e} ROWS ONLY`}_compileOFFSET(t,e){if(t==="pg"||t==="mysql")return`OFFSET ${e}`;if(t==="mssql"||t==="oracle")return`OFFSET ${e} ROWS`}compileCount({countExpr:t="*",engine:e=f,bindingIndex:n=1}={}){let s=this.getFoundRowsQuery(t),{sql:r,bindings:o}=s.compile({engine:e,bindingIndex:n});return this._havings.length===0?{sql:r,bindings:o}:{sql:`SELECT COUNT(*) AS found_rows
|
|
11
|
+
FROM (
|
|
12
|
+
${r.replace(/\n/g,`
|
|
13
|
+
`)}
|
|
14
|
+
) AS subquery_results`,bindings:o}}compileUnion(t,{engine:e=f,bindingIndex:n=1}={}){let s=this.compile({engine:e,bindingIndex:n}),r=t.compile({engine:e,bindingIndex:s.bindings.length+n});return{sql:`(${s.sql})
|
|
15
|
+
UNION
|
|
16
|
+
(${r.sql})`,bindings:[...s.bindings,...r.bindings]}}reset(t=null){if(Array.isArray(t))return t.forEach(e=>this.reset(e)),this;if(t){let e=["option","column","table","where","having","groupBy","orderBy"],n="_"+t.replace(/s$/,"");e.indexOf(t)>-1&&(n+="s");let s=["limit","offset","page"].indexOf(t)>-1;this[n]=s?null:[]}else this._options=[],this._columns=[],this._tables=[],this._joins=[],this._wheres=[],this._groupBys=[],this._havings=[],this._orderBys=[],this._limit=null,this._offset=null,this._page=null,this._bindings=[];return this}getClone(){let t=new i;return t._options=[...this._options],t._columns=[...this._columns],t._tables=[...this._tables],t._joins=[...this._joins],t._wheres=[...this._wheres],t._havings=[...this._havings],t._groupBys=[...this._groupBys],t._orderBys=[...this._orderBys],t._limit=this._limit,t._offset=this._offset,t._page=this._page,t._bindings=[...this._bindings],t}getFoundRowsQuery(t="*"){if(this._havings.length===0){let e=this.getClone();return e._columns=[`COUNT(${t}) AS found_rows`],e._options=[],e._groupBys=[],e._orderBys=[],e._limit=null,e._offset=null,e._page=null,e}else{let e=this.getClone();return e._limit=null,e._offset=null,e._page=null,e}}select(t){return this._columns=this._columns.concat(t),this}columns(t){return this._columns=this._columns.concat(t),this}column(t){return this._columns.push(t),this}option(t){return this._options.push(t),this}table(t){return this._tables.push(t),this}tables(t){return this._tables.push(...t),this}from(t){return this._tables.push(t),this}_addJoin(t,e,n=[]){n.length>0&&(e=e.replace(/\?/g,()=>(this._bindings.push(n.shift()),`__BOUND_${this._bindings.length-1}__`))),this._joins.push(`${t} ${e}`)}join(t,e=[]){return this._addJoin("JOIN",t,e),this}leftJoin(t,e=[]){return this._addJoin("LEFT JOIN",t,e),this}fullJoin(t,e=[]){return this._addJoin("FULL JOIN",t,e),this}rightJoin(t,e=[]){return this._addJoin("RIGHT JOIN",t,e),this}crossJoin(t,e=[]){return this._addJoin("CROSS JOIN",t,e),this}innerJoin(t,e=[]){return this._addJoin("INNER JOIN",t,e),this}leftOuterJoin(t,e=[]){return this._addJoin("LEFT OUTER JOIN",t,e),this}fullOuterJoin(t,e=[]){return this._addJoin("FULL OUTER JOIN",t,e),this}rightOuterJoin(t,e=[]){return this._addJoin("RIGHT OUTER JOIN",t,e),this}unjoin(t){return Array.isArray(t)?(t.forEach(e=>this.unjoin(e)),this):(this._joins=this._joins.filter(e=>!new RegExp(`JOIN ${t}\\b`).test(e)),this)}_conditions(t,e){let n=e.length,[s,r,o]=e;if(typeof s=="object"){for(let l of Object.entries(s))this._conditions(t,l);return this}if(n===1)return t.push(s),this;if(n===2&&Array.isArray(r)&&r.length>0&&m(s,"?")===r.length){let l=r,h=s.replace(/\?/g,()=>(this._bindings.push(l.shift()),`__BOUND_${this._bindings.length-1}__`));return t.push(h),this}else if(n===2){o=r;let l=s.split(" ");s=l.shift(),r=l.join(" ")}(typeof r!="string"||r==="")&&(r="="),r=r.toLocaleUpperCase();let u=r.match(/^(LIKE|NOT LIKE|ILIKE|NOT ILIKE)(?: (\?|\?%|%\?|%\?%))?$/i);if(r==="NOT BETWEEN"||r==="BETWEEN"){let l=this._bindings.length,h=this._bindings.length+1;t.push(`${s} ${r} __BOUND_${l}__ AND __BOUND_${h}__`),this._bindings.push(o[0],o[1])}else if(u){let l=u[1].toUpperCase(),h=u[2]||"?";if(Array.isArray(o)){let a=[];for(let T of o)a.push(`${s} ${l} __BOUND_${this._bindings.length}__`),this._bindings.push(h.replace("?",T));let d=a.join(" OR ");t.push(`(${d})`)}else t.push(`${s} ${l} __BOUND_${this._bindings.length}__`),this._bindings.push(h.replace("?",o||""))}else if(o===null)t.push(r==="="?`${s} IS NULL`:`${s} IS NOT NULL`);else if(Array.isArray(o)){let l=[];for(let a=0;a<o.length;a++)l.push(`__BOUND_${this._bindings.length}__`),this._bindings.push(o[a]);let h=l.join(", ");t.push(r==="="||r==="IN"?`${s} IN(${h})`:`${s} NOT IN(${h})`)}else r==="IN"||r==="NOT IN"?(t.push(`${s} ${r}(__BOUND_${this._bindings.length}__)`),this._bindings.push(o)):(t.push(`${s} ${r} __BOUND_${this._bindings.length}__`),this._bindings.push(o));return this}groupBy(t){return this._groupBys.push(t),this}where(...t){return this._conditions(this._wheres,t),this}whereBetween(t,e){return!_(e[0])&&!_(e[1])?this.where(t,"BETWEEN",e):!_(e[0])&&_(e[1])?this.where(t,">=",e[0]):_(e[0])&&!_(e[1])&&this.where(t,"<=",e[1]),this}_orConditions(t){let e=[];if(Array.isArray(t))for(let s of t)Array.isArray(s)?this._conditions(e,s):this._conditions(e,[s]);else for(let[s,r]of Object.entries(t)){let o=[];this._conditions(o,[s,r]),e.push(o[0])}let n=e.join(" OR ");return n.startsWith("(")&&n.endsWith(")")?n.slice(1,-1):n}orWhere(t){let e=this._orConditions(t);return this.where(`(${e})`),this}orHaving(t){let e=this._orConditions(t);return this.having(`(${e})`),this}having(...t){return this._conditions(this._havings,t),this}orderBy(t,e=null){if(e)this._orderBys.push(`${t} ${e}`);else{let n=t.replace(/^-(.+)/,"$1 DESC");this._orderBys.push(n)}return this}sortField(t,e={}){let n="ASC";t.startsWith("-")&&(n="DESC",t=t.slice(1));let s=e[t]||t;return this.orderBy(s,n),this}_isEntirelyDigits(t){return/^(0|[1-9]\d*)$/.test(t)}_isEntirelyDigitsNoZeros(t){return/^[1-9]\d*$/.test(t)}limit(t){if(typeof t=="string")t=t.trim(),this._isEntirelyDigitsNoZeros(t)&&(this._limit=parseInt(t,10));else if(typeof t=="number"&&Number.isInteger(t)&&t>=1)this._limit=t;else throw new Error(`SelectBuilder: "limit(n)" must receive a positive integer (got "${t}")`);return this}offset(t){if(typeof t=="string"&&this._isEntirelyDigits(t.trim()))this._offset=parseInt(t,10);else if(typeof t=="number"&&Number.isInteger(t)&&t>=0)this._offset=t;else throw new Error(`SelectBuilder: "offset(n)" must receive a positive integer (got "${t}")`);return this}page(t){if(typeof t=="string"&&this._isEntirelyDigitsNoZeros(t.trim()))this._page=parseInt(t,10);else if(typeof t=="number"&&Number.isInteger(t)&&t>=1)this._page=t;else throw new Error('SelectBuilder: "page(n)" must receive a positive integer');return this}};function S(i,t){let e=0,n={};for(let s of t){if(!(i in s))throw new Error(`Column "${String(i)}" is not present in record ${e}`);n[s[i]]||(n[s[i]]=[]),n[s[i]].push(s),e++}return n}function E(i,t){let e=0,n={};for(let s of t){if(!(i in s))throw new Error(`Column "${String(i)}" is not present in record ${e}`);n[s[i]]=s,e++}return n}function R(i,t,e){let n={},s=0;for(let r of e){if(!(i in r))throw new Error(`Column "${String(i)}" is not present in record ${s}`);if(!(t in r))throw new Error(`Column "${String(t)}" is not present in record ${s}`);s++,n[String(r[i])]=r[t]}return n}function g(i,t){t=Number(t)||0;let e=Number(i._limit)||null,n=null;t===0?n=null:i._page?n=Number(i._page):i._limit&&i._offset?n=Math.floor(Number(i._offset)/Number(i._limit))+1:i._limit&&!i._offset?n=1:n=null;let s=t===0||e===null?0:Math.ceil(t/e)||0,r=n===1,o=s>0&&n===s,u=s===0?null:n-1||null,l=s>0&&n+1<=s?n+1:null;return{page:n,prevPage:u,nextPage:l,perPage:e,numPages:s,total:t,isFirst:r,isLast:o}}function b(i,t,e){return new Promise((n,s)=>{i.query(t,e,(r,o,u)=>{if(r){s(r);return}n([o,u])})})}async function N(i,t){let{sql:e,bindings:n}=t.compile({engine:"mysql"});return b(i,e,n)}async function B(i,t,{countExpr:e="*"}={}){let{sql:n,bindings:s}=t.compile({engine:"mysql"}),[r,o]=await b(i,n,s);if(r.length>0){let{sql:u,bindings:l}=t.compileCount({engine:"mysql",countExpr:e}),[h]=await b(i,u,l),a=h[0].found_rows;return{records:r,total:a,pagination:g(t,a),fields:o}}else return{records:r,total:0,pagination:g(t,0),fields:o}}async function $(i,t){let{sql:e,bindings:n}=t.compile({engine:"mysql"});return i.query(e,n)}async function I(i,t,{engine:e="mysql",countExpr:n="*"}={}){let{sql:s,bindings:r}=t.compile({engine:e}),[o,u]=await i.query(s,r);if(o.length>0){let{sql:l,bindings:h}=t.compileCount({engine:e,countExpr:n}),[a]=await i.query(l,h),d=a[0].found_rows;return{records:o,total:d,pagination:g(t,d),fields:u}}else return{records:o,total:0,pagination:g(t,0),fields:u}}function p(i){if(typeof i=="bigint"){let t=Number(i);return i==t?t:i.toString()}return i}function O(i){let t={};for(let e in i)Object.prototype.hasOwnProperty.call(i,e)&&(t[e]=p(i[e]));return t}function C(i){return i.map(O)}function w(i){return JSON.stringify(i,(t,e)=>p(e))}async function x(i,t,{engine:e=void 0}={}){let{sql:n,bindings:s}=t.compile({engine:e});return i.$queryRawUnsafe(n,...s)}async function q(i,t,{engine:e=void 0,countExpr:n="*"}={}){let{sql:s,bindings:r}=t.compile({engine:e}),o=await i.$queryRawUnsafe(s,...r);if(o.length>0){let{sql:u,bindings:l}=t.compileCount({engine:e,countExpr:n}),h=await i.$queryRawUnsafe(u,...l),a=p(h[0].found_rows);return{records:o,total:a,pagination:g(t,a)}}else return{records:o,total:0,pagination:g(t,0)}}export{c as Parser,y as SelectBuilder,S as extractGrouped,E as extractIndexed,R as extractLookup,g as getPagination,N as runMysql,$ as runMysqlAsync,I as runMysqlAsyncWithCount,B as runMysqlWithCount,x as runPrisma,q as runPrismaWithCount,O as toSafeJsonRecord,C as toSafeJsonRecords,w as toSafeJsonString,p as toSafeJsonValue};
|
package/package.json
CHANGED
|
@@ -1,18 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sql-love",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Build SQL queries with JavaScript",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
5
|
"type": "module",
|
|
7
|
-
"
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.mjs",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"require": "./dist/index.cjs",
|
|
12
|
+
"import": "./dist/index.mjs",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
8
16
|
"scripts": {
|
|
9
17
|
"test": "vitest run",
|
|
10
18
|
"test-watch": "vitest",
|
|
11
19
|
"coverage": "vitest run --coverage",
|
|
12
|
-
"
|
|
13
|
-
"build": "npm run clean &&
|
|
14
|
-
"
|
|
20
|
+
"view-coverage": "open ./coverage/lcov-report/index.html",
|
|
21
|
+
"build": "npm run build:clean && npm run build:dts && npm run build:esm && npm run build:cjs",
|
|
22
|
+
"build:clean": "rimraf dist/ && mkdir dist && touch dist/.gitkeep",
|
|
23
|
+
"build:dts": "yes | npx dts-bundle-generator -o dist/index.d.ts index.ts",
|
|
24
|
+
"build:esm": "yes | npx esbuild index.ts --minify --bundle --platform=node --format=esm --outfile=dist/index.mjs",
|
|
25
|
+
"build:cjs": "yes | npx esbuild index.ts --minify --bundle --platform=node --format=cjs --outfile=dist/index.cjs"
|
|
15
26
|
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md",
|
|
30
|
+
"LICENSE.md"
|
|
31
|
+
],
|
|
16
32
|
"repository": {
|
|
17
33
|
"type": "git",
|
|
18
34
|
"url": "git+https://github.com/kensnyder/sql-love.git"
|
|
@@ -32,11 +48,12 @@
|
|
|
32
48
|
},
|
|
33
49
|
"homepage": "https://github.com/kensnyder/sql-love#readme",
|
|
34
50
|
"devDependencies": {
|
|
35
|
-
"@
|
|
51
|
+
"@types/node": "22.6.1",
|
|
52
|
+
"@vitest/coverage-v8": "2.1.1",
|
|
36
53
|
"prettier": "3.3.3",
|
|
37
|
-
"prettier-plugin-organize-imports": "4.
|
|
54
|
+
"prettier-plugin-organize-imports": "4.1.0",
|
|
38
55
|
"rimraf": "6.0.1",
|
|
39
|
-
"typescript": "5.
|
|
40
|
-
"vitest": "2.
|
|
56
|
+
"typescript": "5.6.2",
|
|
57
|
+
"vitest": "2.1.1"
|
|
41
58
|
}
|
|
42
59
|
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
|
|
2
|
-
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
|
|
3
|
-
|
|
4
|
-
name: build
|
|
5
|
-
|
|
6
|
-
on:
|
|
7
|
-
push:
|
|
8
|
-
branches: ['main']
|
|
9
|
-
pull_request:
|
|
10
|
-
branches: ['main']
|
|
11
|
-
|
|
12
|
-
jobs:
|
|
13
|
-
build:
|
|
14
|
-
runs-on: ubuntu-latest
|
|
15
|
-
|
|
16
|
-
strategy:
|
|
17
|
-
matrix:
|
|
18
|
-
node-version: [18.x, 20.x]
|
|
19
|
-
# See supported Node.js release schedule at https://nodejs.org/en/about/previous-releases
|
|
20
|
-
|
|
21
|
-
steps:
|
|
22
|
-
- uses: actions/checkout@v3
|
|
23
|
-
- name: Use Node.js ${{ matrix.node-version }}
|
|
24
|
-
uses: actions/setup-node@v3
|
|
25
|
-
with:
|
|
26
|
-
node-version: ${{ matrix.node-version }}
|
|
27
|
-
cache: 'npm'
|
|
28
|
-
- run: |
|
|
29
|
-
npm ci
|
|
30
|
-
npm run build
|
|
31
|
-
npm test
|
|
32
|
-
npm run coverage
|
|
33
|
-
- name: Upload coverage to Codecov
|
|
34
|
-
uses: codecov/codecov-action@v3
|
|
35
|
-
with:
|
|
36
|
-
token: ${{ secrets.CODECOV_TOKEN }}
|
|
37
|
-
directory: ./coverage/
|
package/.prettierrc.json
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"plugins": ["prettier-plugin-organize-imports"],
|
|
3
|
-
"trailingComma": "es5",
|
|
4
|
-
"printWidth": 80,
|
|
5
|
-
"tabWidth": 2,
|
|
6
|
-
"useTabs": false,
|
|
7
|
-
"semi": true,
|
|
8
|
-
"singleQuote": true,
|
|
9
|
-
"bracketSpacing": true,
|
|
10
|
-
"jsxBracketSameLine": false,
|
|
11
|
-
"arrowParens": "avoid",
|
|
12
|
-
"endOfLine": "lf"
|
|
13
|
-
}
|
package/CHANGELOG.md
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
## Change Log
|
|
2
|
-
|
|
3
|
-
### v1.0.0 - 12 Dec 2023
|
|
4
|
-
|
|
5
|
-
- Upgrade to vitest v1
|
|
6
|
-
- More documentation
|
|
7
|
-
- 100% test coverage
|
|
8
|
-
- First stable release
|
|
9
|
-
|
|
10
|
-
### v0.9.7 - 7 Dec 2023
|
|
11
|
-
|
|
12
|
-
- Added extractLookup utility
|
|
13
|
-
- Added toSafeJson utilities
|
|
14
|
-
|
|
15
|
-
### v0.9.6 - 5 Dec 2023
|
|
16
|
-
|
|
17
|
-
- Utility functions (extractGrouped, extractIndexed, getPagination, runPrisma, runMysql)
|
|
18
|
-
- Added `SelectBuilder.setDefaultEngine(engine)`
|
|
19
|
-
- More documentation
|
|
20
|
-
- Fix `.sortField()` logic
|
|
21
|
-
|
|
22
|
-
### v0.9.4 - 30 Nov 2023
|
|
23
|
-
|
|
24
|
-
- Support parsing and building "ILIKE" and "NOT ILIKE"
|
|
25
|
-
|
|
26
|
-
### v0.9.2 - 30 Nov 2023
|
|
27
|
-
|
|
28
|
-
- Fixes to readme
|
|
29
|
-
|
|
30
|
-
### v0.9.1 - 30 Nov 2023
|
|
31
|
-
|
|
32
|
-
- More documentation
|
|
33
|
-
- GitHub Actions CI
|
|
34
|
-
- Support for parsing "OFFSET # ROWS"
|
|
35
|
-
- Support for parsing "FETCH NEXT # ROWS ONLY"
|
|
36
|
-
|
|
37
|
-
### v0.9.0 - 29 Nov 2023
|
|
38
|
-
|
|
39
|
-
- Initial release with `SelectBuilder`
|
package/CONTRIBUTING.md
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
# Contributing
|
|
2
|
-
|
|
3
|
-
When contributing to this repository, please note we have a code of conduct;
|
|
4
|
-
please follow it in all your interactions with the project.
|
|
5
|
-
|
|
6
|
-
## Pull Request Process
|
|
7
|
-
|
|
8
|
-
1. Ensure all unit tests pass. Add more unit tests if applicable.
|
|
9
|
-
2. Update the README.md with details of change if applicable.
|
|
10
|
-
3. Give maintainers some time to review the changes.
|
|
11
|
-
|
|
12
|
-
## Code of Conduct
|
|
13
|
-
|
|
14
|
-
### Our Pledge
|
|
15
|
-
|
|
16
|
-
In the interest of fostering an open and welcoming environment, we as
|
|
17
|
-
contributors and maintainers pledge to making participation in our project and
|
|
18
|
-
our community a harassment-free experience for everyone, regardless of age, body
|
|
19
|
-
size, disability, ethnicity, gender identity and expression, level of experience,
|
|
20
|
-
nationality, personal appearance, race, religion, or sexual identity and
|
|
21
|
-
orientation.
|
|
22
|
-
|
|
23
|
-
### Our Standards
|
|
24
|
-
|
|
25
|
-
Examples of behavior that contributes to creating a positive environment
|
|
26
|
-
include:
|
|
27
|
-
|
|
28
|
-
* Using welcoming and inclusive language
|
|
29
|
-
* Being respectful of differing viewpoints and experiences
|
|
30
|
-
* Gracefully accepting constructive criticism
|
|
31
|
-
* Focusing on what is best for the community
|
|
32
|
-
* Showing empathy towards other community members
|
|
33
|
-
|
|
34
|
-
Examples of unacceptable behavior by participants include:
|
|
35
|
-
|
|
36
|
-
* The use of sexualized language or imagery and unwelcome sexual attention or
|
|
37
|
-
advances
|
|
38
|
-
* Trolling, insulting/derogatory comments, and personal or political attacks
|
|
39
|
-
* Public or private harassment
|
|
40
|
-
* Publishing others' private information, such as a physical or electronic
|
|
41
|
-
address, without explicit permission
|
|
42
|
-
* Other conduct which could reasonably be considered inappropriate in a
|
|
43
|
-
professional setting
|
|
44
|
-
|
|
45
|
-
### Our Responsibilities
|
|
46
|
-
|
|
47
|
-
Project maintainers are responsible for clarifying the standards of acceptable
|
|
48
|
-
behavior and are expected to take appropriate and fair corrective action in
|
|
49
|
-
response to any instances of unacceptable behavior.
|
|
50
|
-
|
|
51
|
-
Project maintainers have the right and responsibility to remove, edit, or
|
|
52
|
-
reject comments, commits, code, wiki edits, issues, and other contributions
|
|
53
|
-
that are not aligned to this Code of Conduct, or to ban temporarily or
|
|
54
|
-
permanently any contributor for other behaviors that they deem inappropriate,
|
|
55
|
-
threatening, offensive, or harmful.
|
|
56
|
-
|
|
57
|
-
### Scope
|
|
58
|
-
|
|
59
|
-
This Code of Conduct applies both within project spaces and in public spaces
|
|
60
|
-
when an individual is representing the project or its community. Examples of
|
|
61
|
-
representing a project or community include using an official project e-mail
|
|
62
|
-
address, posting via an official social media account, or acting as an appointed
|
|
63
|
-
representative at an online or offline event. Representation of a project may be
|
|
64
|
-
further defined and clarified by project maintainers.
|
|
65
|
-
|
|
66
|
-
### Enforcement
|
|
67
|
-
|
|
68
|
-
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
69
|
-
reported by opening a GitHub ticket. All complaints will be reviewed and
|
|
70
|
-
investigated and will result in a response that is deemed necessary and
|
|
71
|
-
appropriate to the circumstances. The project team is obligated to maintain
|
|
72
|
-
confidentiality with regard to the reporter of an incident. Further details of
|
|
73
|
-
specific enforcement policies may be posted separately.
|
|
74
|
-
|
|
75
|
-
Project maintainers who do not follow or enforce the Code of Conduct in good
|
|
76
|
-
faith may face temporary or permanent repercussions as determined by other
|
|
77
|
-
members of the project's leadership.
|
|
78
|
-
|
|
79
|
-
### Attribution
|
|
80
|
-
|
|
81
|
-
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
|
82
|
-
available at [http://contributor-covenant.org/version/1/4][version]
|
|
83
|
-
|
|
84
|
-
[homepage]: http://contributor-covenant.org
|
|
85
|
-
[version]: http://contributor-covenant.org/version/1/4/
|
package/assets/sql-love-logo.png
DELETED
|
Binary file
|
package/codecov.yml
DELETED
package/dist/index.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export { default as Parser } from './src/Parser/Parser';
|
|
2
|
-
export { default as SelectBuilder } from './src/SelectBuilder/SelectBuilder';
|
|
3
|
-
export { default as extractGrouped } from './src/extractGrouped/extractGrouped';
|
|
4
|
-
export { default as extractIndexed } from './src/extractIndexed/extractIndexed';
|
|
5
|
-
export { default as extractLookup } from './src/extractLookup/extractLookup';
|
|
6
|
-
export { default as getPagination } from './src/getPagination/getPagination';
|
|
7
|
-
export { runMysql, runMysqlAsync, runMysqlAsyncWithCount, runMysqlWithCount, } from './src/runMysql/runMysql';
|
|
8
|
-
export { runPrisma, runPrismaWithCount } from './src/runPrisma/runPrisma';
|
|
9
|
-
export { toSafeJsonRecord, toSafeJsonRecords, toSafeJsonString, toSafeJsonValue, } from './src/toSafeJson/toSafeJson';
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import type Select from '../SelectBuilder/SelectBuilder';
|
|
2
|
-
/**
|
|
3
|
-
* Parse SQL and populate onto a Select query object
|
|
4
|
-
*/
|
|
5
|
-
export default class Parser {
|
|
6
|
-
query: Select;
|
|
7
|
-
/**
|
|
8
|
-
* Create a new instance
|
|
9
|
-
* @param query A Select object on which to build parsed conditions
|
|
10
|
-
*/
|
|
11
|
-
constructor(query: Select);
|
|
12
|
-
/**
|
|
13
|
-
* Strip single-line and multi-line comment blocks
|
|
14
|
-
* @param sql The SQL string
|
|
15
|
-
* @return The SQL string without comments
|
|
16
|
-
* @private
|
|
17
|
-
*/
|
|
18
|
-
_stripComments(sql: string): string;
|
|
19
|
-
/**
|
|
20
|
-
* Before splitting into SQL clauses, extract some regex-able subQueries
|
|
21
|
-
* @param sql The unparsed sql string
|
|
22
|
-
* @return An array with new sql and subQueries
|
|
23
|
-
* @private
|
|
24
|
-
*/
|
|
25
|
-
_extractSubQueries(sql: string): {
|
|
26
|
-
sql: string;
|
|
27
|
-
subQueries: {};
|
|
28
|
-
};
|
|
29
|
-
/**
|
|
30
|
-
* Inject column subQueries back into this object
|
|
31
|
-
* @param subQueries The lookup of extracted subQueries
|
|
32
|
-
* @private
|
|
33
|
-
*/
|
|
34
|
-
_injectSubQueries(subQueries: Record<string, string>): void;
|
|
35
|
-
/**
|
|
36
|
-
* Split SQL into clauses (used by parse())
|
|
37
|
-
* @param sql The SQL to split
|
|
38
|
-
* @return
|
|
39
|
-
* @private
|
|
40
|
-
*/
|
|
41
|
-
_split(sql: string): string[];
|
|
42
|
-
/**
|
|
43
|
-
* Get a QuickSelect object representing the given SQL SELECT statement
|
|
44
|
-
* @param rawSql The raw SQL for the SELECT statement
|
|
45
|
-
* @return True if the SQL was parsed successfully
|
|
46
|
-
*/
|
|
47
|
-
parse(rawSql: string): boolean;
|
|
48
|
-
/**
|
|
49
|
-
* Handle SQL_CALC_FOUND_ROWS and column names
|
|
50
|
-
* @param clause The clause after the SELECT
|
|
51
|
-
* @private
|
|
52
|
-
*/
|
|
53
|
-
_handleSELECT(clause: string): void;
|
|
54
|
-
/**
|
|
55
|
-
* Handle table names
|
|
56
|
-
* @param clause The clause after the FROM
|
|
57
|
-
* @private
|
|
58
|
-
*/
|
|
59
|
-
_handleFROM(clause: string): void;
|
|
60
|
-
/**
|
|
61
|
-
* Handle INNER JOIN statements
|
|
62
|
-
* @param clause The clause after the INNER JOIN
|
|
63
|
-
* @private
|
|
64
|
-
*/
|
|
65
|
-
_handleINNER_JOIN(clause: string): void;
|
|
66
|
-
/**
|
|
67
|
-
* Handle LEFT JOIN statements
|
|
68
|
-
* @param clause The clause after the LEFT JOIN
|
|
69
|
-
* @private
|
|
70
|
-
*/
|
|
71
|
-
_handleLEFT_JOIN(clause: string): void;
|
|
72
|
-
/**
|
|
73
|
-
* Handle LEFT OUTER JOIN statements
|
|
74
|
-
* @param clause The clause after the LEFT OUTER JOIN
|
|
75
|
-
* @private
|
|
76
|
-
*/
|
|
77
|
-
_handleLEFT_OUTER_JOIN(clause: string): void;
|
|
78
|
-
/**
|
|
79
|
-
* Handle RIGHT JOIN statements
|
|
80
|
-
* @param clause The clause after the RIGHT JOIN
|
|
81
|
-
* @private
|
|
82
|
-
*/
|
|
83
|
-
_handleRIGHT_JOIN(clause: string): void;
|
|
84
|
-
/**
|
|
85
|
-
* Handle RIGHT OUTER JOIN statements
|
|
86
|
-
* @param clause The clause after the RIGHT OUTER JOIN
|
|
87
|
-
* @private
|
|
88
|
-
*/
|
|
89
|
-
_handleRIGHT_OUTER_JOIN(clause: string): void;
|
|
90
|
-
/**
|
|
91
|
-
* Handle CROSS JOIN statements
|
|
92
|
-
* @param clause The clause after the CROSS JOIN
|
|
93
|
-
* @private
|
|
94
|
-
*/
|
|
95
|
-
_handleCROSS_JOIN(clause: string): void;
|
|
96
|
-
/**
|
|
97
|
-
* Handle FULL JOIN statements
|
|
98
|
-
* @param clause The clause after the FULL JOIN
|
|
99
|
-
* @private
|
|
100
|
-
*/
|
|
101
|
-
_handleFULL_JOIN(clause: string): void;
|
|
102
|
-
/**
|
|
103
|
-
* Handle FULL OUTER JOIN statements
|
|
104
|
-
* @param clause The clause after the FULL OUTER JOIN
|
|
105
|
-
* @private
|
|
106
|
-
*/
|
|
107
|
-
_handleFULL_OUTER_JOIN(clause: string): void;
|
|
108
|
-
/**
|
|
109
|
-
* Handle WHERE conditions
|
|
110
|
-
* @param clause All the conditions after WHERE
|
|
111
|
-
* @private
|
|
112
|
-
*/
|
|
113
|
-
_handleWHERE(clause: string): void;
|
|
114
|
-
/**
|
|
115
|
-
* Handle HAVING statements
|
|
116
|
-
* @param clause All the conditions after HAVING
|
|
117
|
-
* @private
|
|
118
|
-
*/
|
|
119
|
-
_handleHAVING(clause: string): void;
|
|
120
|
-
/**
|
|
121
|
-
* Build a conditions list
|
|
122
|
-
* @param type Either where or having
|
|
123
|
-
* @param clause The expressions following the type keyword
|
|
124
|
-
* @private
|
|
125
|
-
*/
|
|
126
|
-
_handleConditions(type: 'where' | 'having', clause: string): void;
|
|
127
|
-
/**
|
|
128
|
-
* Handle GROUP BY statements
|
|
129
|
-
* @param clause The clauses after the GROUP BY
|
|
130
|
-
* @private
|
|
131
|
-
*/
|
|
132
|
-
_handleGROUP_BY(clause: string): void;
|
|
133
|
-
/**
|
|
134
|
-
* Handle ORDER BY statements
|
|
135
|
-
* @param clause The clause after the ORDER BY
|
|
136
|
-
* @private
|
|
137
|
-
*/
|
|
138
|
-
_handleORDER_BY(clause: string): void;
|
|
139
|
-
/**
|
|
140
|
-
* Handle LIMIT statements including "LIMIT #" and "LIMIT #, #"
|
|
141
|
-
* @param clause The clause after the LIMIT
|
|
142
|
-
* @private
|
|
143
|
-
*/
|
|
144
|
-
_handleLIMIT(clause: string): void;
|
|
145
|
-
/**
|
|
146
|
-
* Handle OFFSET statements
|
|
147
|
-
* @param clause The number after the OFFSET
|
|
148
|
-
* @private
|
|
149
|
-
*/
|
|
150
|
-
_handleOFFSET(clause: string): void;
|
|
151
|
-
/**
|
|
152
|
-
* Handle OFFSET statements
|
|
153
|
-
* @param clause The number after the OFFSET
|
|
154
|
-
* @private
|
|
155
|
-
*/
|
|
156
|
-
_handleFETCH_NEXT(clause: string): void;
|
|
157
|
-
}
|