@dreamtree-org/korm-js 1.0.43 → 1.0.45

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.
@@ -1 +1 @@
1
- const Files=require("./helpers/files");class BaseHelperUtility{file=new Files;capitalize(e){return e.charAt(0).toUpperCase()+e.slice(1)}snakeCase(e){return e.replace(/([A-Z])/g,"_$1").toLowerCase()}camelCase(e){return e.replace(/([-_][a-z])/gi,e=>e.toUpperCase().replace("-","").replace("_",""))}kebabCase(e){return e.replace(/([A-Z])/g,"-$1").toLowerCase()}pascalCase(e){return e.replace(/([-_][a-z])/gi,e=>e.toUpperCase().replace("-","").replace("_",""))}pluralize(e){if(e.match(/[^aeiou]y$/i))return e.slice(0,-1)+"ies";if(e.match(/(s|x|z|ch|sh)$/i))return e+"es";if(e.match(/(f|fe)$/i)){if(e.endsWith("fe"))return e.slice(0,-2)+"ves";if(e.endsWith("f"))return e.slice(0,-1)+"ves"}return e.match(/(o)$/i)?e.length>1&&"aeiou".includes(e[e.length-2].toLowerCase())?e+"s":e+"es":e.match(/us$/i)?e.slice(0,-2)+"i":e.match(/is$/i)?e.slice(0,-2)+"es":e.match(/on$/i)||e.match(/um$/i)?e.slice(0,-2)+"a":e.match(/a$/i)?e+"s":e.match(/eau$/i)?e+"x":e.match(/ix$/i)||e.match(/ex$/i)?e.slice(0,-2)+"ices":e.match(/s$/i)?e:e+"s"}singularize(e){return String(e||"").trim().replace(/([b-df-hj-np-tv-z])ies$/i,"$1y").replace(/eaux$/i,"eau").replace(/oes$/i,"o").replace(/(xes|zes|ches|shes|sses)$/i,e=>e.slice(0,-2)).replace(/(us)es$/i,"$1").replace(/ves$/i,"f").replace(/([^s])s$/i,"$1")}modelName(e){let r=this.singularize(e);return r=this.camelCase(r),r=this.capitalize(r),r}dotParse(e,r,t=null){return this.dotWalk(e,{source:r,defaultValue:t})}dotWalk(e,r={}){const{source:t={},defaultValue:a=null,resolver:s=({current:e,part:r,source:t})=>e[r]}=r,i=e.split(".");let l=t;for(const e of i){const r=e.match(/^(\w+)\[(.*?)\]$/);if(r){const e=r[1],i=r[2]||0;if(l=l[e]||[],l=s({current:l,part:i,source:t}),void 0===l)return a}else{if(void 0===l[e])return a;if(l=s({current:l,part:e,source:t}),void 0===l)return a}}return l}dotWalkTree(e,r={}){const{resolver:t=({current:e,part:r,source:t})=>{}}=r,a={};for(const r of e){const e=r.split(".");let s=e.length,i=a,l=0;for(const o of e){let e=l===s-1;i[o]=i[o]||t({current:i,part:o,source:a,path:r,isLastPart:e}),i=i[o],l++}}return a}parseValue(e){return isNaN(e)||""===e?"true"===e.toLowerCase()||"false"!==e.toLowerCase()&&("null"===e.toLowerCase()?null:e):Number(e)}parseWhereValue(e){if("object"==typeof e&&Array.isArray(e))return{operator:"orCondition",value:e.map(e=>this.parseWhereValue(e))};if("string"!=typeof e)return{operator:"=",value:e};if(e.startsWith("!")){const r=e.substring(1);return{operator:"!=",value:this.parseValue(r)}}if(e.includes("%"))return{operator:"like",value:e};const r=e.match(/^(><|<>)(.+)$/);if(r){const[,e,t]=r,a=t.split(",").map(e=>this.parseValue(e.trim()));if("><"===e){if(2===a.length)return{operator:"between",value:a}}else if("<>"===e&&2===a.length)return{operator:"notBetween",value:a}}const t=e.match(/^(>=|<=|<|>)(.+)$/);if(t){const[,e,r]=t;return{operator:e,value:this.parseValue(r)}}const a=e.match(/^(!?)\[\]?(.+)$/);if(a){const[,e,r]=a;return{operator:e?"notIn":"in",value:r.split(",").map(e=>this.parseValue(e.trim()))}}return{operator:"=",value:this.parseValue(e)}}objectFilter(e,r){return Object.keys(e).filter(t=>r(t,e[t])).reduce((r,t)=>(r[t]=e[t],r),{})}pluckDotWalkKey(e,r=1,t="."){let a=e.split(t);return[...a].splice(-1*a.length+r).join(t)}getDotWalkQuery(e,r=""){let t=this.dotWalkTree(Object.keys(e).filter(e=>e.includes(r)),{resolver:({current:r,part:t,source:a,path:s,isLastPart:i})=>i?e[s]:{}});return r&&(t=t[r]),t}setNested(e,r,t){let a={name:r,value:t},s=e,i=s,l="",o=a.name.split(".");return o.length>1?(o.forEach(e=>{s=i,i[e]=i[e]||{},i=i[e],l=e}),s[l]=a.value):(l=a.name,s=e[l],e[l]=a.value),e}}module.exports=BaseHelperUtility;
1
+ const Files=require("./helpers/files");class BaseHelperUtility{file=new Files;capitalize(e){return e.charAt(0).toUpperCase()+e.slice(1)}snakeCase(e){return e.replace(/([A-Z])/g,"_$1").toLowerCase()}camelCase(e){return e.replace(/([-_][a-z])/gi,e=>e.toUpperCase().replace("-","").replace("_",""))}kebabCase(e){return e.replace(/([A-Z])/g,"-$1").toLowerCase()}pascalCase(e){return e.replace(/([-_][a-z])/gi,e=>e.toUpperCase().replace("-","").replace("_",""))}pluralize(e){if(e.match(/[^aeiou]y$/i))return e.slice(0,-1)+"ies";if(e.match(/(s|x|z|ch|sh)$/i))return e+"es";if(e.match(/(f|fe)$/i)){if(e.endsWith("fe"))return e.slice(0,-2)+"ves";if(e.endsWith("f"))return e.slice(0,-1)+"ves"}return e.match(/(o)$/i)?e.length>1&&"aeiou".includes(e[e.length-2].toLowerCase())?e+"s":e+"es":e.match(/us$/i)?e.slice(0,-2)+"i":e.match(/is$/i)?e.slice(0,-2)+"es":e.match(/on$/i)||e.match(/um$/i)?e.slice(0,-2)+"a":e.match(/a$/i)?e+"s":e.match(/eau$/i)?e+"x":e.match(/ix$/i)||e.match(/ex$/i)?e.slice(0,-2)+"ices":e.match(/s$/i)?e:e+"s"}singularize(e){return String(e||"").trim().replace(/([b-df-hj-np-tv-z])ies$/i,"$1y").replace(/eaux$/i,"eau").replace(/oes$/i,"o").replace(/(xes|zes|ches|shes|sses)$/i,e=>e.slice(0,-2)).replace(/(us)es$/i,"$1").replace(/ves$/i,"f").replace(/([^s])s$/i,"$1")}modelName(e){let r=this.singularize(e);return r=this.camelCase(r),r=this.capitalize(r),r}dotParse(e,r,t=null){return this.dotWalk(e,{source:r,defaultValue:t})}dotWalk(e,r={}){const{source:t={},defaultValue:s=null,resolver:a=({current:e,part:r,source:t})=>e[r]}=r,i=e.split(".");let l=t;for(const e of i){const r=e.match(/^(\w+)\[(.*?)\]$/);if(r){const e=r[1],i=r[2]||0;if(l=l[e]||[],l=a({current:l,part:i,source:t}),void 0===l)return s}else{if(void 0===l[e])return s;if(l=a({current:l,part:e,source:t}),void 0===l)return s}}return l}dotWalkTree(e,r={}){const{resolver:t=({current:e,part:r,source:t})=>{}}=r,s={};for(const r of e){const e=r.split(".");let a=e.length,i=s,l=0;for(const u of e){let e=l===a-1;i[u]=i[u]||t({current:i,part:u,source:s,path:r,isLastPart:e}),i=i[u],l++}}return s}parseValue(e){return isNaN(e)||""===e?"true"===e.toLowerCase()||"false"!==e.toLowerCase()&&("null"===e.toLowerCase()?null:e):Number(e)}parseWhereValue(e){if("string"!=typeof e)return{operator:"=",value:e};if(e.startsWith("!")){const r=e.substring(1);return{operator:"!=",value:this.parseValue(r)}}if(e.includes("%"))return{operator:"like",value:e};const r=e.match(/^(><|<>)(.+)$/);if(r){const[,e,t]=r,s=t.split(",").map(e=>this.parseValue(e.trim()));if("><"===e){if(2===s.length)return{operator:"between",value:s}}else if("<>"===e&&2===s.length)return{operator:"notBetween",value:s}}const t=e.match(/^(>=|<=|<|>)(.+)$/);if(t){const[,e,r]=t;return{operator:e,value:this.parseValue(r)}}const s=e.match(/^(!?)\[\]?(.+)$/);if(s){const[,e,r]=s;return{operator:e?"notIn":"in",value:r.split(",").map(e=>this.parseValue(e.trim()))}}return{operator:"=",value:this.parseValue(e)}}parseWhereColumn(e){let r={joinType:"AND",column:e};return e.startsWith("Or:")&&(r.joinType="OR",r.column=e.substring(3)),r}objectFilter(e,r){return Object.keys(e).filter(t=>r(t,e[t])).reduce((r,t)=>(r[t]=e[t],r),{})}pluckDotWalkKey(e,r=1,t="."){let s=e.split(t);return[...s].splice(-1*s.length+r).join(t)}getDotWalkQuery(e,r=""){let t=this.dotWalkTree(Object.keys(e).filter(e=>e.includes(r)),{resolver:({current:r,part:t,source:s,path:a,isLastPart:i})=>i?e[a]:{}});return r&&(t=t[r]),t}setNested(e,r,t){let s={name:r,value:t},a=e,i=a,l="",u=s.name.split(".");return u.length>1?(u.forEach(e=>{a=i,i[e]=i[e]||{},i=i[e],l=e}),a[l]=s.value):(l=s.name,a=e[l],e[l]=s.value),e}}module.exports=BaseHelperUtility;
package/README.md CHANGED
@@ -175,9 +175,9 @@ POST /api/Users/crud
175
175
  {
176
176
  "action": "list",
177
177
  "where": {
178
- "first_name": { "like": "%John%" },
179
- "email": { "like": "%@example.com" },
180
- "age": { ">=": 18, "<=": 65 },
178
+ "first_name": "%John%",
179
+ "email": "%@example.com",
180
+ "age": "><18,65",
181
181
  "is_active": true
182
182
  },
183
183
  "select": ["id", "username", "email", "first_name", "last_name"],
@@ -315,7 +315,7 @@ POST /api/Users/crud
315
315
  "action": "count",
316
316
  "where": {
317
317
  "is_active": true,
318
- "created_at": { ">=": "2024-01-01" }
318
+ "created_at": ">=2024-01-01"
319
319
  }
320
320
  }
321
321
 
@@ -386,7 +386,7 @@ POST /api/Users/crud
386
386
  },
387
387
  "conflict": ["username"],
388
388
  "where": {
389
- "created_at": { "<": "2024-01-01" }
389
+ "created_at": "<2024-01-01"
390
390
  }
391
391
  }
392
392
 
@@ -411,34 +411,177 @@ POST /api/Users/crud
411
411
  {
412
412
  "action": "list",
413
413
  "where": {
414
- "age": { ">=": 18, "<=": 65 },
415
- "email": { "like": "%@example.com" },
416
- "first_name": { "in": ["John", "Jane", "Bob"] },
414
+ "age": "><18,65",
415
+ "email": "%@example.com",
416
+ "first_name": "[]John,Jane,Bob",
417
417
  "is_active": true,
418
- "created_at": { ">=": "2024-01-01", "<=": "2024-12-31" }
418
+ "created_at": "><2024-01-01,2024-12-31"
419
419
  }
420
420
  }
421
421
 
422
- // OR conditions (using arrays)
422
+ // NULL checks
423
423
  POST /api/Users/crud
424
424
  {
425
425
  "action": "list",
426
426
  "where": {
427
- "or": [
428
- { "first_name": "John" },
429
- { "last_name": "Doe" }
430
- ]
427
+ "deleted_at": null
431
428
  }
432
429
  }
430
+ ```
433
431
 
434
- // NULL checks
432
+ ### OR Conditions with `Or:` Prefix
433
+
434
+ Use the `Or:` prefix on column names to create OR conditions in your queries:
435
+
436
+ ```javascript
437
+ // OR condition on a single column
435
438
  POST /api/Users/crud
436
439
  {
437
440
  "action": "list",
438
441
  "where": {
439
- "deleted_at": null
442
+ "status": "active",
443
+ "Or:name": "%john%"
444
+ }
445
+ }
446
+ // Generated SQL: WHERE status = 'active' OR name LIKE '%john%'
447
+
448
+ // Multiple OR conditions
449
+ POST /api/Users/crud
450
+ {
451
+ "action": "list",
452
+ "where": {
453
+ "is_active": true,
454
+ "Or:first_name": "John",
455
+ "Or:last_name": "Doe"
456
+ }
457
+ }
458
+ // Generated SQL: WHERE is_active = 1 OR first_name = 'John' OR last_name = 'Doe'
459
+
460
+ // Combining AND and OR conditions
461
+ POST /api/Users/crud
462
+ {
463
+ "action": "list",
464
+ "where": {
465
+ "status": "active",
466
+ "age": ">=18",
467
+ "Or:role": "admin",
468
+ "Or:role": "super_admin"
469
+ }
470
+ }
471
+ // Generated SQL: WHERE status = 'active' AND age >= 18 OR role = 'admin' OR role = 'super_admin'
472
+
473
+ // OR with operators
474
+ POST /api/Users/crud
475
+ {
476
+ "action": "list",
477
+ "where": {
478
+ "department": "sales",
479
+ "Or:email": "%@company.com",
480
+ "Or:created_at": ">=2024-01-01"
481
+ }
482
+ }
483
+ // Generated SQL: WHERE department = 'sales' OR email LIKE '%@company.com' OR created_at >= '2024-01-01'
484
+
485
+ // OR with NULL checks
486
+ POST /api/Users/crud
487
+ {
488
+ "action": "list",
489
+ "where": {
490
+ "is_verified": true,
491
+ "Or:verified_at": null
492
+ }
493
+ }
494
+ // Generated SQL: WHERE is_verified = 1 OR verified_at IS NULL
495
+
496
+ // OR with IN operator
497
+ POST /api/Users/crud
498
+ {
499
+ "action": "list",
500
+ "where": {
501
+ "status": "pending",
502
+ "Or:role": ["admin", "moderator", "editor"]
503
+ }
504
+ }
505
+ // Generated SQL: WHERE status = 'pending' OR role IN ('admin', 'moderator', 'editor')
506
+ ```
507
+
508
+ ### Array-Based Where Conditions
509
+
510
+ You can also pass `where` as an array of condition objects for more complex queries:
511
+
512
+ ```javascript
513
+ // Array of conditions - each object is applied sequentially
514
+ POST /api/Users/crud
515
+ {
516
+ "action": "list",
517
+ "where": [
518
+ { "status": "active" },
519
+ { "Or:role": "admin" },
520
+ { "Or:role": "moderator" }
521
+ ]
522
+ }
523
+ // Generated SQL: WHERE status = 'active' OR role = 'admin' OR role = 'moderator'
524
+
525
+ // Combining multiple AND and OR groups
526
+ POST /api/Users/crud
527
+ {
528
+ "action": "list",
529
+ "where": [
530
+ { "is_active": true, "age": ">=18" },
531
+ { "Or:status": "verified" },
532
+ { "Or:role": "admin" }
533
+ ]
534
+ }
535
+ // Generated SQL: WHERE is_active = 1 AND age >= 18 OR status = 'verified' OR role = 'admin'
536
+
537
+ // Complex filtering with array conditions
538
+ POST /api/Users/crud
539
+ {
540
+ "action": "list",
541
+ "where": [
542
+ { "department": "engineering" },
543
+ { "Or:department": "product" },
544
+ { "created_at": ">=2024-01-01" }
545
+ ]
546
+ }
547
+ // Generated SQL: WHERE department = 'engineering' OR department = 'product' AND created_at >= '2024-01-01'
548
+ ```
549
+
550
+ ### Where Operators Reference
551
+
552
+ | Operator | Description | Syntax | Example |
553
+ |----------|-------------|--------|---------|
554
+ | `=` (default) | Equals | `value` | `"status": "active"` |
555
+ | `>=` | Greater than or equal | `>=value` | `"age": ">=18"` |
556
+ | `<=` | Less than or equal | `<=value` | `"age": "<=65"` |
557
+ | `>` | Greater than | `>value` | `"price": ">100"` |
558
+ | `<` | Less than | `<value` | `"price": "<500"` |
559
+ | `!=` | Not equal | `!value` | `"status": "!deleted"` |
560
+ | `like` | Pattern matching (auto) | `%value%` | `"name": "%john%"` |
561
+ | `in` | Value in list | `[]val1,val2` | `"status": "[]active,pending"` |
562
+ | `notIn` | Value not in list | `![]val1,val2` | `"role": "![]banned,suspended"` |
563
+ | `between` | Range (inclusive) | `><min,max` | `"age": "><18,65"` |
564
+ | `notBetween` | Outside range | `<>min,max` | `"score": "<>0,50"` |
565
+ | `null` | IS NULL check | `null` | `"deleted_at": null` |
566
+ | `Or:column` | OR condition prefix | `Or:column` | `"Or:name": "John"` |
567
+
568
+ **Examples:**
569
+
570
+ ```javascript
571
+ // Complex query with string-based operators
572
+ POST /api/Users/crud
573
+ {
574
+ "action": "list",
575
+ "where": {
576
+ "age": ">=18",
577
+ "status": "!deleted",
578
+ "name": "%john%",
579
+ "role": "[]admin,moderator,editor",
580
+ "score": "><50,100"
440
581
  }
441
582
  }
583
+ // SQL: WHERE age >= 18 AND status != 'deleted' AND name LIKE '%john%'
584
+ // AND role IN ('admin', 'moderator', 'editor') AND score BETWEEN 50 AND 100
442
585
  ```
443
586
 
444
587
  ### Sorting
@@ -1 +1 @@
1
- const HelperUtility=require("./HelperUtility");class QueryBuilder{constructor(e,t,r=null){this.db=e,this.utils=t,this.controllerWrapper=r,this.helperUtility=new HelperUtility}getQueryBuilder(e,t=null){let r=this.db(e.table);return t&&(r=t),r._getMyModel=()=>e,r}parseValue(e){return this.helperUtility.parseValue(e)}parseWhereValue(e){return this.helperUtility.parseWhereValue(e)}_applyOrWhereCondition(e,t,r,i){switch(r){case"between":e.orWhereBetween(t,i);break;case"notBetween":e.orWhereNotBetween(t,i);break;case"in":e.orWhereIn(t,i);break;case"notIn":e.orWhereNotIn(t,i);break;case"like":e.orWhereRaw(`\`${t}\` LIKE ?`,[i]);break;default:e.orWhere(t,r,i)}}_applyAndWhereCondition(e,t,r,i){switch(r){case"between":e.whereBetween(t,i);break;case"notBetween":e.whereNotBetween(t,i);break;case"in":e.whereIn(t,i);break;case"notIn":e.whereNotIn(t,i);break;case"like":e.whereRaw(`\`${t}\` LIKE ?`,[i]);break;default:e.where(t,r,i)}}buildWithTree(e,t=null){return this.helperUtility.dotWalkTree(e,{resolver:({current:e,part:r,source:i})=>t?t({current:e,part:r,source:i}):{}})}async fetchRelatedRows(e,t){if(e.through){let r=await this.db(e.through).whereIn(e.throughLocalKey,t);return await this.db(e.table).whereIn(e.foreignKey,r.map(t=>t[e.throughForeignKey]))}return this.db(e.table).whereIn(e.foreignKey,t)}async fetchAndAttachRelated(e){const{parentRows:t,relName:r,model:i,withTree:o,relation:l}=e;let a=t.map(e=>e[l.localKey]),s=[];s=await this.fetchRelatedRows(l,a);let n=new Map;for(const e of s){let t=e[l.foreignKey];n.has(t)||n.set(t,[]),n.get(t).push(e)}for(const e of t){let t=e[l.localKey];"one"===l?.type&&1==n.get(t)?.length?e[r]=n.get(t)[0]:e[r]=n.get(t)||[]}let h=Object.keys(o);for(const e of h){let i=o[e],l=t.filter(e=>e[r].length>0).map(e=>e[r]).reduce((e,t)=>e.concat(t),[]),a=this.utils.getModel(this.controllerWrapper,r);await this.fetchAndAttachRelated({parentRows:l,relName:e,model:a,withTree:i,relation:a.hasRelations[e]})}return t}filterWhere(e,t=""){return t?Object.keys(e).filter(e=>e.includes(t)).reduce((r,i)=>(r[i.replace(t,"")]=e[i],r),{}):Object.keys(e).filter(e=>!e.includes(".")).reduce((t,r)=>(t[r]=e[r],t),{})}async getQuery(e,t){try{const{where:r={},with:i,withWhere:o,select:l,orderBy:a={column:"id",direction:"asc"},limit:s=10,offset:n=0,page:h,groupBy:c,having:p,distinct:y,join:u,leftJoin:f,rightJoin:d,innerJoin:g,count:w=!1}=t;let b=this.getQueryBuilder(e);l&&(Array.isArray(l)||"string"==typeof l)?b.select(l):b.select("*"),y&&(Array.isArray(y)||"string"==typeof y?b.distinct(y):b.distinct()),u&&this._applyJoins(b,u,"join"),f&&this._applyJoins(b,f,"leftJoin"),d&&this._applyJoins(b,d,"rightJoin"),g&&this._applyJoins(b,g,"innerJoin"),this._applyWhereClause(b,r,i),c&&(Array.isArray(c),b.groupBy(c)),p&&this._applyHavingClause(b,p),a&&this._applyOrderBy(b,a);let W=!1,_=s,k=n,m=1,A=0;h&&s>0&&(m=Math.max(1,parseInt(h)),k=(m-1)*s),s>0&&(b.limit(_),k>0&&b.offset(k));const j=await b;if(i&&i.length>0){const t=this.buildWithTree(i);for(const r of Object.keys(t))await this.fetchAndAttachRelated({parentRows:j,relName:r,model:e,withTree:t[r],relation:e.hasRelations[r]})}let B=null;if(s>0)try{let t=this.getQueryBuilder(e);r&&Object.keys(r).length>0&&this._applyWhereClause(t,r),u&&this._applyJoins(t,u,"join"),f&&this._applyJoins(t,f,"leftJoin"),d&&this._applyJoins(t,d,"rightJoin"),g&&this._applyJoins(t,g,"innerJoin");B=(await t.count("* as cnt").first()).cnt}catch(e){console.warn("Failed to get total count:",e.message),B=j.length}s>0&&null!==B&&(A=Math.ceil(B/s),W=m<A);return{data:j,totalCount:B,...s>0?{pagination:{page:m,limit:_,offset:k,totalPages:A,hasNext:W,hasPrev:m>1,nextPage:W?m+1:null,prevPage:m>1?m-1:null}}:{}}}catch(e){throw console.error("QueryService.getQuery error:",e),new Error(`Failed to execute query: ${e.message}`)}}_applyWhereClause(e,t,r=[]){if(t&&Object.keys(t).length>0){let r=this.helperUtility.getDotWalkQuery(t);console.log({filteredWhere:r}),r=this.helperUtility.objectFilter(r,(e,t)=>"object"!=typeof t||null===t);for(const[t,i]of Object.entries(r))if(null===i)e.whereNull(t);else if(Array.isArray(i))e.whereIn(t,i);else{const{operator:r,value:o}=this.parseWhereValue(i);if("orCondition"===r)for(const r of o){const{operator:i,value:o}=this.parseWhereValue(r);this._applyOrWhereCondition(e,t,i,o)}else this._applyAndWhereCondition(e,t,r,i)}}r&&r.length>0&&this._applyNestedWhere(e,t,r)}_applyNestedWhere(e,t,r){let i=this,o=e._getMyModel();if(r&&r.length>0)for(const l of r){let a=this.helperUtility.getDotWalkQuery(t,l);if(a&&Object.keys(a).length>0){let t=this.utils.getModel(this.controllerWrapper,l),s=o.hasRelations[l],n=r.map(e=>this.helperUtility.pluckDotWalkKey(e,1));e.whereExists(function(){let e=i.getQueryBuilder(t,this.select("*").from(t.table));e.whereRaw(`${s.foreignKey} = ${o.table}.${s.localKey}`),i._applyWhereClause(e,a,n)})}}}_applyJoins(e,t,r){const i=Array.isArray(t)?t:[t];for(const t of i)"string"==typeof t?e[r](t):"object"==typeof t&&(t.table&&t.on?e[r](t.table,t.on):t.table&&t.first&&t.operator&&t.second&&e[r](t.table,t.first,t.operator,t.second))}_applyWithWhere(e,t){try{if(Array.isArray(t))for(const r of t)"string"==typeof r?e.withWhere(r):"object"==typeof r&&e.withWhere(r.column,r.operator,r.value);else if("object"==typeof t)for(const[r,i]of Object.entries(t))e.withWhere(r,i)}catch(e){console.warn("Failed to apply withWhere:",e.message)}}_applyHavingClause(e,t){for(const[r,i]of Object.entries(t))"object"==typeof i&&i.operator?e.having(r,i.operator,i.value):e.having(r,i)}_applyOrderBy(e,t){if(Array.isArray(t))for(const r of t)"string"==typeof r?e.orderBy(r):"object"==typeof r&&e.orderBy(r.column,r.direction||"asc");else"string"==typeof t?e.orderBy(t):"object"==typeof t&&e.orderBy(t.column,t.direction||"asc")}}module.exports=QueryBuilder;
1
+ const HelperUtility=require("./HelperUtility");class QueryBuilder{constructor(e,t,r=null){this.db=e,this.utils=t,this.controllerWrapper=r,this.helperUtility=new HelperUtility}getQueryBuilder(e,t=null){let r=this.db(e.table);return t&&(r=t),r._getMyModel=()=>e,r}parseValue(e){return this.helperUtility.parseValue(e)}parseWhereValue(e){return this.helperUtility.parseWhereValue(e)}parseWhereColumn(e){return this.helperUtility.parseWhereColumn(e)}_applyOrWhereCondition(e,t,r,i){if(null!==i)if(Array.isArray(i))e.orWhereIn(t,i);else switch(r){case"between":e.orWhereBetween(t,i);break;case"notBetween":e.orWhereNotBetween(t,i);break;case"in":e.orWhereIn(t,i);break;case"notIn":e.orWhereNotIn(t,i);break;case"like":e.orWhereRaw(`\`${t}\` LIKE ?`,[i]);break;default:e.orWhere(t,r,i)}else e.orWhereNull(t)}_applyAndWhereCondition(e,t,r,i){if(null!==i)if(Array.isArray(i))e.whereIn(t,i);else switch(r){case"between":e.whereBetween(t,i);break;case"notBetween":e.whereNotBetween(t,i);break;case"in":e.whereIn(t,i);break;case"notIn":e.whereNotIn(t,i);break;case"like":e.whereRaw(`\`${t}\` LIKE ?`,[i]);break;default:e.where(t,r,i)}else e.whereNull(t)}buildWithTree(e,t=null){return this.helperUtility.dotWalkTree(e,{resolver:({current:e,part:r,source:i})=>t?t({current:e,part:r,source:i}):{}})}async fetchRelatedRows(e,t){if(e.through){let r=await this.db(e.through).whereIn(e.throughLocalKey,t);return await this.db(e.table).whereIn(e.foreignKey,r.map(t=>t[e.throughForeignKey]))}return this.db(e.table).whereIn(e.foreignKey,t)}async fetchAndAttachRelated(e){const{parentRows:t,relName:r,model:i,withTree:l,relation:o}=e;let a=t.map(e=>e[o.localKey]),s=[];s=await this.fetchRelatedRows(o,a);let n=new Map;for(const e of s){let t=e[o.foreignKey];n.has(t)||n.set(t,[]),n.get(t).push(e)}for(const e of t){let t=e[o.localKey];"one"===o?.type&&1==n.get(t)?.length?e[r]=n.get(t)[0]:e[r]=n.get(t)||[]}let h=Object.keys(l);for(const e of h){let i=l[e],o=t.filter(e=>e[r].length>0).map(e=>e[r]).reduce((e,t)=>e.concat(t),[]),a=this.utils.getModel(this.controllerWrapper,r);await this.fetchAndAttachRelated({parentRows:o,relName:e,model:a,withTree:i,relation:a.hasRelations[e]})}return t}filterWhere(e,t=""){return t?Object.keys(e).filter(e=>e.includes(t)).reduce((r,i)=>(r[i.replace(t,"")]=e[i],r),{}):Object.keys(e).filter(e=>!e.includes(".")).reduce((t,r)=>(t[r]=e[r],t),{})}async getQuery(e,t){try{const{where:r={},with:i,withWhere:l,select:o,orderBy:a={column:"id",direction:"asc"},limit:s=10,offset:n=0,page:h,groupBy:p,having:c,distinct:y,join:u,leftJoin:f,rightJoin:d,innerJoin:g,count:w=!1}=t;let W=this.getQueryBuilder(e);o&&(Array.isArray(o)||"string"==typeof o)?W.select(o):W.select("*"),y&&(Array.isArray(y)||"string"==typeof y?W.distinct(y):W.distinct()),u&&this._applyJoins(W,u,"join"),f&&this._applyJoins(W,f,"leftJoin"),d&&this._applyJoins(W,d,"rightJoin"),g&&this._applyJoins(W,g,"innerJoin"),this._applyWhereClause(W,r,i),p&&(Array.isArray(p),W.groupBy(p)),c&&this._applyHavingClause(W,c),a&&this._applyOrderBy(W,a);let b=!1,A=s,_=n,m=1,k=0;h&&s>0&&(m=Math.max(1,parseInt(h)),_=(m-1)*s),s>0&&(W.limit(A),_>0&&W.offset(_));const j=await W;if(i&&i.length>0){const t=this.buildWithTree(i);for(const r of Object.keys(t))await this.fetchAndAttachRelated({parentRows:j,relName:r,model:e,withTree:t[r],relation:e.hasRelations[r]})}let B=null;if(s>0)try{let t=this.getQueryBuilder(e);r&&Object.keys(r).length>0&&this._applyWhereClause(t,r),u&&this._applyJoins(t,u,"join"),f&&this._applyJoins(t,f,"leftJoin"),d&&this._applyJoins(t,d,"rightJoin"),g&&this._applyJoins(t,g,"innerJoin");B=(await t.count("* as cnt").first()).cnt}catch(e){console.warn("Failed to get total count:",e.message),B=j.length}s>0&&null!==B&&(k=Math.ceil(B/s),b=m<k);return{data:j,totalCount:B,...s>0?{pagination:{page:m,limit:A,offset:_,totalPages:k,hasNext:b,hasPrev:m>1,nextPage:b?m+1:null,prevPage:m>1?m-1:null}}:{}}}catch(e){throw console.error("QueryService.getQuery error:",e),new Error(`Failed to execute query: ${e.message}`)}}_applyWhereWithArray(e,t,r){for(const i of t)this._applyWhereClause(e,i,r)}_applyWhereClause(e,t,r=[]){if(Array.isArray(t))this._applyWhereWithArray(e,t,r);else{if(t&&Object.keys(t).length>0){let r=this.helperUtility.getDotWalkQuery(t);console.log({filteredWhere:r}),r=this.helperUtility.objectFilter(r,(e,t)=>"object"!=typeof t||null===t);for(const[t,i]of Object.entries(r)){const{joinType:r="AND",column:l}=this.parseWhereColumn(t),{operator:o,value:a}=this.parseWhereValue(i);"AND"===r?this._applyAndWhereCondition(e,l,o,a):this._applyOrWhereCondition(e,l,o,a)}}r&&r.length>0&&this._applyNestedWhere(e,t,r)}}_applyNestedWhere(e,t,r){let i=this,l=e._getMyModel();if(r&&r.length>0)for(const o of r){let a=this.helperUtility.getDotWalkQuery(t,o);if(a&&Object.keys(a).length>0){let t=this.utils.getModel(this.controllerWrapper,o),s=l.hasRelations[o],n=r.map(e=>this.helperUtility.pluckDotWalkKey(e,1));e.whereExists(function(){let e=i.getQueryBuilder(t,this.select("*").from(t.table));e.whereRaw(`${s.foreignKey} = ${l.table}.${s.localKey}`),i._applyWhereClause(e,a,n)})}}}_applyJoins(e,t,r){const i=Array.isArray(t)?t:[t];for(const t of i)"string"==typeof t?e[r](t):"object"==typeof t&&(t.table&&t.on?e[r](t.table,t.on):t.table&&t.first&&t.operator&&t.second&&e[r](t.table,t.first,t.operator,t.second))}_applyWithWhere(e,t){try{if(Array.isArray(t))for(const r of t)"string"==typeof r?e.withWhere(r):"object"==typeof r&&e.withWhere(r.column,r.operator,r.value);else if("object"==typeof t)for(const[r,i]of Object.entries(t))e.withWhere(r,i)}catch(e){console.warn("Failed to apply withWhere:",e.message)}}_applyHavingClause(e,t){for(const[r,i]of Object.entries(t))"object"==typeof i&&i.operator?e.having(r,i.operator,i.value):e.having(r,i)}_applyOrderBy(e,t){if(Array.isArray(t))for(const r of t)"string"==typeof r?e.orderBy(r):"object"==typeof r&&e.orderBy(r.column,r.direction||"asc");else"string"==typeof t?e.orderBy(t):"object"==typeof t&&e.orderBy(t.column,t.direction||"asc")}}module.exports=QueryBuilder;
@@ -1 +1 @@
1
- const HelperUtility=require("./HelperUtility");class QueryBuilder{constructor(e,t,r=null){this.db=e,this.utils=t,this.controllerWrapper=r,this.helperUtility=new HelperUtility}getQueryBuilder(e,t=null){let r=this.db(e.table);return t&&(r=t),r._getMyModel=()=>e,r}parseValue(e){return this.helperUtility.parseValue(e)}parseWhereValue(e){return this.helperUtility.parseWhereValue(e)}_applyOrWhereCondition(e,t,r,i){switch(r){case"between":e.orWhereBetween(t,i);break;case"notBetween":e.orWhereNotBetween(t,i);break;case"in":e.orWhereIn(t,i);break;case"notIn":e.orWhereNotIn(t,i);break;case"like":e.orWhere(t,"like",i);break;default:e.orWhere(t,r,i)}}_applyAndWhereCondition(e,t,r,i){switch(r){case"between":e.whereBetween(t,i);break;case"notBetween":e.whereNotBetween(t,i);break;case"in":e.whereIn(t,i);break;case"notIn":e.whereNotIn(t,i);break;case"like":e.where(t,"like",i);break;default:e.where(t,r,i)}}buildWithTree(e,t=null){return this.helperUtility.dotWalkTree(e,{resolver:({current:e,part:r,source:i})=>t?t({current:e,part:r,source:i}):{}})}async fetchRelatedRows(e,t){if(e.through){let r=await this.db(e.through).whereIn(e.throughLocalKey,t);return await this.db(e.table).whereIn(e.foreignKey,r.map(t=>t[e.throughForeignKey]))}return this.db(e.table).whereIn(e.foreignKey,t)}async fetchAndAttachRelated(e){const{parentRows:t,relName:r,model:i,withTree:o,relation:l}=e;let a=t.map(e=>e[l.localKey]),s=[];s=await this.fetchRelatedRows(l,a);let n=new Map;for(const e of s){let t=e[l.foreignKey];n.has(t)||n.set(t,[]),n.get(t).push(e)}for(const e of t){let t=e[l.localKey];"one"===l?.type&&1==n.get(t)?.length?e[r]=n.get(t)[0]:e[r]=n.get(t)||[]}let h=Object.keys(o);for(const e of h){let i=o[e],l=t.filter(e=>e[r].length>0).map(e=>e[r]).reduce((e,t)=>e.concat(t),[]),a=this.utils.getModel(this.controllerWrapper,r);await this.fetchAndAttachRelated({parentRows:l,relName:e,model:a,withTree:i,relation:a.hasRelations[e]})}return t}filterWhere(e,t=""){return t?Object.keys(e).filter(e=>e.includes(t)).reduce((r,i)=>(r[i.replace(t,"")]=e[i],r),{}):Object.keys(e).filter(e=>!e.includes(".")).reduce((t,r)=>(t[r]=e[r],t),{})}async getQuery(e,t){try{const{where:r={},with:i,withWhere:o,select:l,orderBy:a={column:"id",direction:"asc"},limit:s=10,offset:n=0,page:h,groupBy:c,having:p,distinct:y,join:u,leftJoin:f,rightJoin:d,innerJoin:g,count:w=!1}=t;let b=this.getQueryBuilder(e);l&&(Array.isArray(l)||"string"==typeof l)?b.select(l):b.select("*"),y&&(Array.isArray(y)||"string"==typeof y?b.distinct(y):b.distinct()),u&&this._applyJoins(b,u,"join"),f&&this._applyJoins(b,f,"leftJoin"),d&&this._applyJoins(b,d,"rightJoin"),g&&this._applyJoins(b,g,"innerJoin"),this._applyWhereClause(b,r,i),c&&(Array.isArray(c),b.groupBy(c)),p&&this._applyHavingClause(b,p),a&&this._applyOrderBy(b,a);let W=!1,k=s,_=n,m=1,A=0;h&&s>0&&(m=Math.max(1,parseInt(h)),_=(m-1)*s),s>0&&(b.limit(k),_>0&&b.offset(_));const j=await b;if(i&&i.length>0){const t=this.buildWithTree(i);for(const r of Object.keys(t))await this.fetchAndAttachRelated({parentRows:j,relName:r,model:e,withTree:t[r],relation:e.hasRelations[r]})}let B=null;if(s>0)try{let t=this.getQueryBuilder(e);r&&Object.keys(r).length>0&&this._applyWhereClause(t,r),u&&this._applyJoins(t,u,"join"),f&&this._applyJoins(t,f,"leftJoin"),d&&this._applyJoins(t,d,"rightJoin"),g&&this._applyJoins(t,g,"innerJoin");B=(await t.count("* as cnt").first()).cnt}catch(e){console.warn("Failed to get total count:",e.message),B=j.length}s>0&&null!==B&&(A=Math.ceil(B/s),W=m<A);return{data:j,totalCount:B,...s>0?{pagination:{page:m,limit:k,offset:_,totalPages:A,hasNext:W,hasPrev:m>1,nextPage:W?m+1:null,prevPage:m>1?m-1:null}}:{}}}catch(e){throw console.error("QueryService.getQuery error:",e),new Error(`Failed to execute query: ${e.message}`)}}_applyWhereClause(e,t,r=[]){if(t&&Object.keys(t).length>0){let r=this.helperUtility.getDotWalkQuery(t);console.log({filteredWhere:r}),r=this.helperUtility.objectFilter(r,(e,t)=>"object"!=typeof t||null===t);for(const[t,i]of Object.entries(r))if(null===i)e.whereNull(t);else if(Array.isArray(i))e.whereIn(t,i);else{const{operator:r,value:o}=this.parseWhereValue(i);if("orCondition"===r)for(const r of o){const{operator:i,value:o}=this.parseWhereValue(r);this._applyOrWhereCondition(e,t,i,o)}else this._applyAndWhereCondition(e,t,r,i)}}r&&r.length>0&&this._applyNestedWhere(e,t,r)}_applyNestedWhere(e,t,r){let i=this,o=e._getMyModel();if(r&&r.length>0)for(const l of r){let a=this.helperUtility.getDotWalkQuery(t,l);if(a&&Object.keys(a).length>0){let t=this.utils.getModel(this.controllerWrapper,l),s=o.hasRelations[l],n=r.map(e=>this.helperUtility.pluckDotWalkKey(e,1));e.whereExists(function(){let e=i.getQueryBuilder(t,this.select("*").from(t.table));e.whereRaw(`${s.foreignKey} = ${o.table}.${s.localKey}`),i._applyWhereClause(e,a,n)})}}}_applyJoins(e,t,r){const i=Array.isArray(t)?t:[t];for(const t of i)"string"==typeof t?e[r](t):"object"==typeof t&&(t.table&&t.on?e[r](t.table,t.on):t.table&&t.first&&t.operator&&t.second&&e[r](t.table,t.first,t.operator,t.second))}_applyWithWhere(e,t){try{if(Array.isArray(t))for(const r of t)"string"==typeof r?e.withWhere(r):"object"==typeof r&&e.withWhere(r.column,r.operator,r.value);else if("object"==typeof t)for(const[r,i]of Object.entries(t))e.withWhere(r,i)}catch(e){console.warn("Failed to apply withWhere:",e.message)}}_applyHavingClause(e,t){for(const[r,i]of Object.entries(t))"object"==typeof i&&i.operator?e.having(r,i.operator,i.value):e.having(r,i)}_applyOrderBy(e,t){if(Array.isArray(t))for(const r of t)"string"==typeof r?e.orderBy(r):"object"==typeof r&&e.orderBy(r.column,r.direction||"asc");else"string"==typeof t?e.orderBy(t):"object"==typeof t&&e.orderBy(t.column,t.direction||"asc")}}module.exports=QueryBuilder;
1
+ const HelperUtility=require("./HelperUtility");class QueryBuilder{constructor(e,t,r=null){this.db=e,this.utils=t,this.controllerWrapper=r,this.helperUtility=new HelperUtility}getQueryBuilder(e,t=null){let r=this.db(e.table);return t&&(r=t),r._getMyModel=()=>e,r}parseValue(e){return this.helperUtility.parseValue(e)}parseWhereValue(e){return this.helperUtility.parseWhereValue(e)}parseWhereColumn(e){return this.helperUtility.parseWhereColumn(e)}_applyOrWhereCondition(e,t,r,i){if(null!==i)if(Array.isArray(i))e.orWhereIn(t,i);else switch(r){case"between":e.orWhereBetween(t,i);break;case"notBetween":e.orWhereNotBetween(t,i);break;case"in":e.orWhereIn(t,i);break;case"notIn":e.orWhereNotIn(t,i);break;case"like":e.orWhere(t,"like",i);break;default:e.orWhere(t,r,i)}else e.orWhereNull(t)}_applyAndWhereCondition(e,t,r,i){if(null!==i)if(Array.isArray(i))e.whereIn(t,i);else switch(r){case"between":e.whereBetween(t,i);break;case"notBetween":e.whereNotBetween(t,i);break;case"in":e.whereIn(t,i);break;case"notIn":e.whereNotIn(t,i);break;case"like":e.where(t,"like",i);break;default:e.where(t,r,i)}else e.whereNull(t)}buildWithTree(e,t=null){return this.helperUtility.dotWalkTree(e,{resolver:({current:e,part:r,source:i})=>t?t({current:e,part:r,source:i}):{}})}async fetchRelatedRows(e,t){if(e.through){let r=await this.db(e.through).whereIn(e.throughLocalKey,t);return await this.db(e.table).whereIn(e.foreignKey,r.map(t=>t[e.throughForeignKey]))}return this.db(e.table).whereIn(e.foreignKey,t)}async fetchAndAttachRelated(e){const{parentRows:t,relName:r,model:i,withTree:l,relation:o}=e;let a=t.map(e=>e[o.localKey]),s=[];s=await this.fetchRelatedRows(o,a);let n=new Map;for(const e of s){let t=e[o.foreignKey];n.has(t)||n.set(t,[]),n.get(t).push(e)}for(const e of t){let t=e[o.localKey];"one"===o?.type&&1==n.get(t)?.length?e[r]=n.get(t)[0]:e[r]=n.get(t)||[]}let h=Object.keys(l);for(const e of h){let i=l[e],o=t.filter(e=>e[r].length>0).map(e=>e[r]).reduce((e,t)=>e.concat(t),[]),a=this.utils.getModel(this.controllerWrapper,r);await this.fetchAndAttachRelated({parentRows:o,relName:e,model:a,withTree:i,relation:a.hasRelations[e]})}return t}filterWhere(e,t=""){return t?Object.keys(e).filter(e=>e.includes(t)).reduce((r,i)=>(r[i.replace(t,"")]=e[i],r),{}):Object.keys(e).filter(e=>!e.includes(".")).reduce((t,r)=>(t[r]=e[r],t),{})}async getQuery(e,t){try{const{where:r={},with:i,withWhere:l,select:o,orderBy:a={column:"id",direction:"asc"},limit:s=10,offset:n=0,page:h,groupBy:p,having:c,distinct:y,join:u,leftJoin:f,rightJoin:d,innerJoin:g,count:w=!1}=t;let W=this.getQueryBuilder(e);o&&(Array.isArray(o)||"string"==typeof o)?W.select(o):W.select("*"),y&&(Array.isArray(y)||"string"==typeof y?W.distinct(y):W.distinct()),u&&this._applyJoins(W,u,"join"),f&&this._applyJoins(W,f,"leftJoin"),d&&this._applyJoins(W,d,"rightJoin"),g&&this._applyJoins(W,g,"innerJoin"),this._applyWhereClause(W,r,i),p&&(Array.isArray(p),W.groupBy(p)),c&&this._applyHavingClause(W,c),a&&this._applyOrderBy(W,a);let b=!1,A=s,_=n,m=1,k=0;h&&s>0&&(m=Math.max(1,parseInt(h)),_=(m-1)*s),s>0&&(W.limit(A),_>0&&W.offset(_));const j=await W;if(i&&i.length>0){const t=this.buildWithTree(i);for(const r of Object.keys(t))await this.fetchAndAttachRelated({parentRows:j,relName:r,model:e,withTree:t[r],relation:e.hasRelations[r]})}let B=null;if(s>0)try{let t=this.getQueryBuilder(e);r&&Object.keys(r).length>0&&this._applyWhereClause(t,r),u&&this._applyJoins(t,u,"join"),f&&this._applyJoins(t,f,"leftJoin"),d&&this._applyJoins(t,d,"rightJoin"),g&&this._applyJoins(t,g,"innerJoin");B=(await t.count("* as cnt").first()).cnt}catch(e){console.warn("Failed to get total count:",e.message),B=j.length}s>0&&null!==B&&(k=Math.ceil(B/s),b=m<k);return{data:j,totalCount:B,...s>0?{pagination:{page:m,limit:A,offset:_,totalPages:k,hasNext:b,hasPrev:m>1,nextPage:b?m+1:null,prevPage:m>1?m-1:null}}:{}}}catch(e){throw console.error("QueryService.getQuery error:",e),new Error(`Failed to execute query: ${e.message}`)}}_applyWhereWithArray(e,t,r){for(const i of t)this._applyWhereClause(e,i,r)}_applyWhereClause(e,t,r=[]){if(Array.isArray(t))this._applyWhereWithArray(e,t,r);else{if(t&&Object.keys(t).length>0){let r=this.helperUtility.getDotWalkQuery(t);console.log({filteredWhere:r}),r=this.helperUtility.objectFilter(r,(e,t)=>"object"!=typeof t||null===t);for(const[t,i]of Object.entries(r)){const{joinType:r="AND",column:l}=this.parseWhereColumn(t),{operator:o,value:a}=this.parseWhereValue(i);"AND"===r?this._applyAndWhereCondition(e,l,o,a):this._applyOrWhereCondition(e,l,o,a)}}r&&r.length>0&&this._applyNestedWhere(e,t,r)}}_applyNestedWhere(e,t,r){let i=this,l=e._getMyModel();if(r&&r.length>0)for(const o of r){let a=this.helperUtility.getDotWalkQuery(t,o);if(a&&Object.keys(a).length>0){let t=this.utils.getModel(this.controllerWrapper,o),s=l.hasRelations[o],n=r.map(e=>this.helperUtility.pluckDotWalkKey(e,1));e.whereExists(function(){let e=i.getQueryBuilder(t,this.select("*").from(t.table));e.whereRaw(`${s.foreignKey} = ${l.table}.${s.localKey}`),i._applyWhereClause(e,a,n)})}}}_applyJoins(e,t,r){const i=Array.isArray(t)?t:[t];for(const t of i)"string"==typeof t?e[r](t):"object"==typeof t&&(t.table&&t.on?e[r](t.table,t.on):t.table&&t.first&&t.operator&&t.second&&e[r](t.table,t.first,t.operator,t.second))}_applyWithWhere(e,t){try{if(Array.isArray(t))for(const r of t)"string"==typeof r?e.withWhere(r):"object"==typeof r&&e.withWhere(r.column,r.operator,r.value);else if("object"==typeof t)for(const[r,i]of Object.entries(t))e.withWhere(r,i)}catch(e){console.warn("Failed to apply withWhere:",e.message)}}_applyHavingClause(e,t){for(const[r,i]of Object.entries(t))"object"==typeof i&&i.operator?e.having(r,i.operator,i.value):e.having(r,i)}_applyOrderBy(e,t){if(Array.isArray(t))for(const r of t)"string"==typeof r?e.orderBy(r):"object"==typeof r&&e.orderBy(r.column,r.direction||"asc");else"string"==typeof t?e.orderBy(t):"object"==typeof t&&e.orderBy(t.column,t.direction||"asc")}}module.exports=QueryBuilder;
@@ -1 +1 @@
1
- const HelperUtility=require("./HelperUtility");class QueryBuilder{constructor(e,t,r=null){this.db=e,this.utils=t,this.controllerWrapper=r,this.helperUtility=new HelperUtility}getQueryBuilder(e){return this.db(e.table)}parseValue(e){return this.helperUtility.parseValue(e)}parseWhereValue(e){return this.helperUtility.parseWhereValue(e)}_applyOrWhereCondition(e,t,r,i){switch(r){case"between":e.orWhereBetween(t,i);break;case"notBetween":e.orWhereNotBetween(t,i);break;case"in":e.orWhereIn(t,i);break;case"notIn":e.orWhereNotIn(t,i);break;case"like":e.orWhere(t,"like",i);break;default:e.orWhere(t,r,i)}}_applyAndWhereCondition(e,t,r,i){switch(r){case"between":e.whereBetween(t,i);break;case"notBetween":e.whereNotBetween(t,i);break;case"in":e.whereIn(t,i);break;case"notIn":e.whereNotIn(t,i);break;case"like":e.where(t,"like",i);break;default:e.where(t,r,i)}}buildWithTree(e,t=null){return this.helperUtility.dotWalkTree(e,{resolver:({current:e,part:r,source:i})=>t?t({current:e,part:r,source:i}):{}})}async fetchRelatedRows(e,t){if(e.through){let r=await this.db(e.through).whereIn(e.throughLocalKey,t);return await this.db(e.table).whereIn(e.foreignKey,r.map(t=>t[e.throughForeignKey]))}return this.db(e.table).whereIn(e.foreignKey,t)}async fetchAndAttachRelated(e){const{parentRows:t,relName:r,model:i,withTree:o,relation:l}=e;let a=t.map(e=>e[l.localKey]),s=[];s=await this.fetchRelatedRows(l,a);let n=new Map;for(const e of s){let t=e[l.foreignKey];n.has(t)||n.set(t,[]),n.get(t).push(e)}for(const e of t){let t=e[l.localKey];"one"===l?.type&&1==n.get(t)?.length?e[r]=n.get(t)[0]:e[r]=n.get(t)||[]}let h=Object.keys(o);for(const e of h){let i=o[e],l=t.filter(e=>e[r].length>0).map(e=>e[r]).reduce((e,t)=>e.concat(t),[]),a=this.utils.getModel(this.controllerWrapper,r);await this.fetchAndAttachRelated({parentRows:l,relName:e,model:a,withTree:i,relation:a.hasRelations[e]})}return t}filterWhere(e,t=""){return t?Object.keys(e).filter(e=>e.includes(t)).reduce((r,i)=>(r[i.replace(t,"")]=e[i],r),{}):Object.keys(e).filter(e=>!e.includes(".")).reduce((t,r)=>(t[r]=e[r],t),{})}async getQuery(e,t){try{const{where:r={},with:i,withWhere:o,select:l,orderBy:a={column:"id",direction:"asc"},limit:s=10,offset:n=0,page:h,groupBy:c,having:p,distinct:y,join:u,leftJoin:f,rightJoin:d,innerJoin:g,count:w=!1}=t;let b=this.getQueryBuilder(e);l&&(Array.isArray(l)||"string"==typeof l)?b.select(l):b.select("*"),y&&(Array.isArray(y)||"string"==typeof y?b.distinct(y):b.distinct()),u&&this._applyJoins(b,u,"join"),f&&this._applyJoins(b,f,"leftJoin"),d&&this._applyJoins(b,d,"rightJoin"),g&&this._applyJoins(b,g,"innerJoin"),this._applyWhereClause(b,r,i),c&&(Array.isArray(c),b.groupBy(c)),p&&this._applyHavingClause(b,p),a&&this._applyOrderBy(b,a);let W=!1,k=s,_=n,m=1,A=0;h&&s>0&&(m=Math.max(1,parseInt(h)),_=(m-1)*s),s>0&&(b.limit(k),_>0&&b.offset(_));const j=await b;if(i&&i.length>0){const t=this.buildWithTree(i);for(const r of Object.keys(t))await this.fetchAndAttachRelated({parentRows:j,relName:r,model:e,withTree:t[r],relation:e.hasRelations[r]})}let B=null;if(s>0)try{let t=this.getQueryBuilder(e);r&&Object.keys(r).length>0&&this._applyWhereClause(t,r),u&&this._applyJoins(t,u,"join"),f&&this._applyJoins(t,f,"leftJoin"),d&&this._applyJoins(t,d,"rightJoin"),g&&this._applyJoins(t,g,"innerJoin");B=(await t.count("* as cnt").first()).cnt}catch(e){console.warn("Failed to get total count:",e.message),B=j.length}s>0&&null!==B&&(A=Math.ceil(B/s),W=m<A);return{data:j,totalCount:B,...s>0?{pagination:{page:m,limit:k,offset:_,totalPages:A,hasNext:W,hasPrev:m>1,nextPage:W?m+1:null,prevPage:m>1?m-1:null}}:{}}}catch(e){throw console.error("QueryService.getQuery error:",e),new Error(`Failed to execute query: ${e.message}`)}}_applyWhereClause(e,t,r=[]){if(t&&Object.keys(t).length>0){let r=this.helperUtility.getDotWalkQuery(t);r=this.helperUtility.objectFilter(r,(e,t)=>"object"!=typeof t||null===t);for(const[t,i]of Object.entries(r))if(null===i)e.whereNull(t);else if(Array.isArray(i))e.whereIn(t,i);else{const{operator:r,value:o}=this.parseWhereValue(i);if("orCondition"===r)for(const r of o){const{operator:i,value:o}=this.parseWhereValue(r);this._applyOrWhereCondition(e,t,i,o)}else this._applyAndWhereCondition(e,t,r,i)}}r&&r.length>0&&this._applyNestedWhere(e,t,r)}_applyNestedWhere(e,t,r){if(r&&r.length>0)for(const i of r){let o=this.helperUtility.getDotWalkQuery(t,i);if(o&&Object.keys(o).length>0){let t=this.getQueryBuilder(this.utils.getModel(this.controllerWrapper,i)),l=this.helperUtility.map(r,e=>this.helperUtility.pluckDotWalkKey(e,1));e.whereExists(this._applyWhereClause(t,o,l))}}}_applyJoins(e,t,r){const i=Array.isArray(t)?t:[t];for(const t of i)"string"==typeof t?e[r](t):"object"==typeof t&&(t.table&&t.on?e[r](t.table,t.on):t.table&&t.first&&t.operator&&t.second&&e[r](t.table,t.first,t.operator,t.second))}_applyWithWhere(e,t){try{if(Array.isArray(t))for(const r of t)"string"==typeof r?e.withWhere(r):"object"==typeof r&&e.withWhere(r.column,r.operator,r.value);else if("object"==typeof t)for(const[r,i]of Object.entries(t))e.withWhere(r,i)}catch(e){console.warn("Failed to apply withWhere:",e.message)}}_applyHavingClause(e,t){for(const[r,i]of Object.entries(t))"object"==typeof i&&i.operator?e.having(r,i.operator,i.value):e.having(r,i)}_applyOrderBy(e,t){if(Array.isArray(t))for(const r of t)"string"==typeof r?e.orderBy(r):"object"==typeof r&&e.orderBy(r.column,r.direction||"asc");else"string"==typeof t?e.orderBy(t):"object"==typeof t&&e.orderBy(t.column,t.direction||"asc")}}module.exports=QueryBuilder;
1
+ const HelperUtility=require("./HelperUtility");class QueryBuilder{constructor(e,t,r=null){this.db=e,this.utils=t,this.controllerWrapper=r,this.helperUtility=new HelperUtility}getQueryBuilder(e){return this.db(e.table)}parseValue(e){return this.helperUtility.parseValue(e)}parseWhereValue(e){return this.helperUtility.parseWhereValue(e)}parseWhereColumn(e){return this.helperUtility.parseWhereColumn(e)}_applyOrWhereCondition(e,t,r,i){if(null!==i)if(Array.isArray(i))e.orWhereIn(t,i);else switch(r){case"between":e.orWhereBetween(t,i);break;case"notBetween":e.orWhereNotBetween(t,i);break;case"in":e.orWhereIn(t,i);break;case"notIn":e.orWhereNotIn(t,i);break;case"like":e.orWhere(t,"like",i);break;default:e.orWhere(t,r,i)}else e.orWhereNull(t)}_applyAndWhereCondition(e,t,r,i){if(null!==i)if(Array.isArray(i))e.whereIn(t,i);else switch(r){case"between":e.whereBetween(t,i);break;case"notBetween":e.whereNotBetween(t,i);break;case"in":e.whereIn(t,i);break;case"notIn":e.whereNotIn(t,i);break;case"like":e.where(t,"like",i);break;default:e.where(t,r,i)}else e.whereNull(t)}buildWithTree(e,t=null){return this.helperUtility.dotWalkTree(e,{resolver:({current:e,part:r,source:i})=>t?t({current:e,part:r,source:i}):{}})}async fetchRelatedRows(e,t){if(e.through){let r=await this.db(e.through).whereIn(e.throughLocalKey,t);return await this.db(e.table).whereIn(e.foreignKey,r.map(t=>t[e.throughForeignKey]))}return this.db(e.table).whereIn(e.foreignKey,t)}async fetchAndAttachRelated(e){const{parentRows:t,relName:r,model:i,withTree:l,relation:o}=e;let a=t.map(e=>e[o.localKey]),s=[];s=await this.fetchRelatedRows(o,a);let n=new Map;for(const e of s){let t=e[o.foreignKey];n.has(t)||n.set(t,[]),n.get(t).push(e)}for(const e of t){let t=e[o.localKey];"one"===o?.type&&1==n.get(t)?.length?e[r]=n.get(t)[0]:e[r]=n.get(t)||[]}let h=Object.keys(l);for(const e of h){let i=l[e],o=t.filter(e=>e[r].length>0).map(e=>e[r]).reduce((e,t)=>e.concat(t),[]),a=this.utils.getModel(this.controllerWrapper,r);await this.fetchAndAttachRelated({parentRows:o,relName:e,model:a,withTree:i,relation:a.hasRelations[e]})}return t}filterWhere(e,t=""){return t?Object.keys(e).filter(e=>e.includes(t)).reduce((r,i)=>(r[i.replace(t,"")]=e[i],r),{}):Object.keys(e).filter(e=>!e.includes(".")).reduce((t,r)=>(t[r]=e[r],t),{})}async getQuery(e,t){try{const{where:r={},with:i,withWhere:l,select:o,orderBy:a={column:"id",direction:"asc"},limit:s=10,offset:n=0,page:h,groupBy:p,having:c,distinct:y,join:u,leftJoin:f,rightJoin:d,innerJoin:g,count:w=!1}=t;let W=this.getQueryBuilder(e);o&&(Array.isArray(o)||"string"==typeof o)?W.select(o):W.select("*"),y&&(Array.isArray(y)||"string"==typeof y?W.distinct(y):W.distinct()),u&&this._applyJoins(W,u,"join"),f&&this._applyJoins(W,f,"leftJoin"),d&&this._applyJoins(W,d,"rightJoin"),g&&this._applyJoins(W,g,"innerJoin"),this._applyWhereClause(W,r,i),p&&(Array.isArray(p),W.groupBy(p)),c&&this._applyHavingClause(W,c),a&&this._applyOrderBy(W,a);let b=!1,A=s,_=n,k=1,m=0;h&&s>0&&(k=Math.max(1,parseInt(h)),_=(k-1)*s),s>0&&(W.limit(A),_>0&&W.offset(_));const j=await W;if(i&&i.length>0){const t=this.buildWithTree(i);for(const r of Object.keys(t))await this.fetchAndAttachRelated({parentRows:j,relName:r,model:e,withTree:t[r],relation:e.hasRelations[r]})}let B=null;if(s>0)try{let t=this.getQueryBuilder(e);r&&Object.keys(r).length>0&&this._applyWhereClause(t,r),u&&this._applyJoins(t,u,"join"),f&&this._applyJoins(t,f,"leftJoin"),d&&this._applyJoins(t,d,"rightJoin"),g&&this._applyJoins(t,g,"innerJoin");B=(await t.count("* as cnt").first()).cnt}catch(e){console.warn("Failed to get total count:",e.message),B=j.length}s>0&&null!==B&&(m=Math.ceil(B/s),b=k<m);return{data:j,totalCount:B,...s>0?{pagination:{page:k,limit:A,offset:_,totalPages:m,hasNext:b,hasPrev:k>1,nextPage:b?k+1:null,prevPage:k>1?k-1:null}}:{}}}catch(e){throw console.error("QueryService.getQuery error:",e),new Error(`Failed to execute query: ${e.message}`)}}_applyWhereWithArray(e,t,r){for(const i of t)this._applyWhereClause(e,i,r)}_applyWhereClause(e,t,r=[]){if(Array.isArray(t))this._applyWhereWithArray(e,t,r);else{if(t&&Object.keys(t).length>0){let r=this.helperUtility.getDotWalkQuery(t);r=this.helperUtility.objectFilter(r,(e,t)=>"object"!=typeof t||null===t);for(const[t,i]of Object.entries(r)){const{joinType:r="AND",column:l}=this.parseWhereColumn(t),{operator:o,value:a}=this.parseWhereValue(i);"AND"===r?this._applyAndWhereCondition(e,l,o,a):this._applyOrWhereCondition(e,l,o,a)}}r&&r.length>0&&this._applyNestedWhere(e,t,r)}}_applyNestedWhere(e,t,r){if(r&&r.length>0)for(const i of r){let l=this.helperUtility.getDotWalkQuery(t,i);if(l&&Object.keys(l).length>0){let t=this.getQueryBuilder(this.utils.getModel(this.controllerWrapper,i)),o=this.helperUtility.map(r,e=>this.helperUtility.pluckDotWalkKey(e,1));e.whereExists(this._applyWhereClause(t,l,o))}}}_applyJoins(e,t,r){const i=Array.isArray(t)?t:[t];for(const t of i)"string"==typeof t?e[r](t):"object"==typeof t&&(t.table&&t.on?e[r](t.table,t.on):t.table&&t.first&&t.operator&&t.second&&e[r](t.table,t.first,t.operator,t.second))}_applyWithWhere(e,t){try{if(Array.isArray(t))for(const r of t)"string"==typeof r?e.withWhere(r):"object"==typeof r&&e.withWhere(r.column,r.operator,r.value);else if("object"==typeof t)for(const[r,i]of Object.entries(t))e.withWhere(r,i)}catch(e){console.warn("Failed to apply withWhere:",e.message)}}_applyHavingClause(e,t){for(const[r,i]of Object.entries(t))"object"==typeof i&&i.operator?e.having(r,i.operator,i.value):e.having(r,i)}_applyOrderBy(e,t){if(Array.isArray(t))for(const r of t)"string"==typeof r?e.orderBy(r):"object"==typeof r&&e.orderBy(r.column,r.direction||"asc");else"string"==typeof t?e.orderBy(t):"object"==typeof t&&e.orderBy(t.column,t.direction||"asc")}}module.exports=QueryBuilder;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dreamtree-org/korm-js",
3
- "version": "1.0.43",
3
+ "version": "1.0.45",
4
4
  "description": "Knowledge Object-Relational Mapping - A powerful, modular ORM system for Node.js with dynamic database operations, complex queries, relationships, and nested requests",
5
5
  "author": {
6
6
  "name": "Partha Preetham Krishna",