@dreamtree-org/korm-js 1.0.36 → 1.0.38

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:s=null,resolver:a=({current:e,part:r,source:t})=>e[r]}=r,l=e.split(".");let i=t;for(const e of l){const r=e.match(/^(\w+)\[(.*?)\]$/);if(r){const e=r[1],l=r[2]||0;if(i=i[e]||[],i=a({current:i,part:l,source:t}),void 0===i)return s}else{if(void 0===i[e])return s;if(i=a({current:i,part:e,source:t}),void 0===i)return s}}return i}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,l=s,i=0;for(const u of e){let e=i===a-1;l[u]=l[u]||t({current:l,part:u,source:s,path:r,isLastPart:e}),l=l[u],i++}}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)}}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=""){console.log({query:e,prefix:r});let t=this.dotWalkTree(Object.keys(e).filter(e=>e.includes(r)),{resolver:({current:r,part:t,source:s,path:a,isLastPart:l})=>l?e[a]:{}});return r&&(t=t[r]),t}setNested(e,r,t){let s={name:r,value:t},a=e,l=a,i="",u=s.name.split(".");return u.length>1?(u.forEach(e=>{a=l,l[e]=l[e]||{},l=l[e],i=e}),a[i]=s.value):(i=s.name,a=e[i],e[i]=s.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)}}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;
@@ -1 +1 @@
1
- const mysqlWrapper=require("./clients/mysql"),sqliteWrapper=require("./clients/sqlite"),pgWrapper=require("./clients/pg"),BaseHelperUtility=require("./BaseHelperUtility"),InstanceMapper={mysql2:mysqlWrapper,sqlite:sqliteWrapper,pg:pgWrapper},dbClientMapper={mysql2:"mysql2",mysql:"mysql2",pg:"pg",postgresql:"pg",sqlite:"sqlite",sqlite3:"sqlite"};class ControllerWrapper{static db=null;static dbClient=null;static schema=null;static resolverPath=null;static dbInstance=null;requestInstance=null;constructor(){this.requestInstance={}}static initializeKORM({db:e,dbClient:t,schema:s,resolverPath:a=null}){this.db=e,this.dbClient=t,this.schema=s,this.resolverPath=a;const r=dbClientMapper[t];if(!r)throw new Error(`Database client ${t} not found`);const n=InstanceMapper[r];if(!n)throw new Error(`Database client ${t} not found`);return this.dbInstance=new n(this),this}static setSchema(e){return this.schema=e,this}static async processRequest(e,t=null,s=null){return await this.dbInstance.processRequest(e,t,s)}static async syncDatabase(){return await this.dbInstance.syncDatabase()}static async generateSchema(){return await this.dbInstance.generateSchema()}}module.exports=ControllerWrapper;
1
+ const mysqlWrapper=require("./clients/mysql"),sqliteWrapper=require("./clients/sqlite"),pgWrapper=require("./clients/pg"),BaseHelperUtility=require("./BaseHelperUtility"),InstanceMapper={mysql2:mysqlWrapper,sqlite:sqliteWrapper,pg:pgWrapper},dbClientMapper={mysql2:"mysql2",mysql:"mysql2",pg:"pg",postgresql:"pg",sqlite:"sqlite",sqlite3:"sqlite"};class ControllerWrapper{static db=null;static dbClient=null;static dbClientClass=null;static schema=null;static resolverPath=null;static dbInstance=null;requestInstance=null;constructor(){this.requestInstance={}}static initializeKORM({db:t,dbClient:e,schema:s,resolverPath:a=null}){this.db=t,this.dbClient=e,this.schema=s,this.resolverPath=a;const n=dbClientMapper[e];if(!n)throw new Error(`Database client ${e} not found`);const r=InstanceMapper[n];if(!r)throw new Error(`Database client ${e} not found`);return this.dbClientClass=r,this}static setSchema(t){this.schema=t;const e=this.dbClientClass;if(!e)throw new Error(`Database client ${dbClient} not found`);return this.dbInstance=new e(this),this}static async processRequest(t,e=null,s=null){return await this.dbInstance.processRequest(t,e,s)}static async syncDatabase(){return await this.dbInstance.syncDatabase()}static async generateSchema(){return await this.dbInstance.generateSchema()}static loadModelClass(t){return this.dbInstance.hookService.loadModelClass(t)}static getModelInstance(t){return this.dbInstance.hookService.getModelInstance(t)}}module.exports=ControllerWrapper;
@@ -1 +1 @@
1
- const QueryService=require("./QueryService"),HookService=require("./HookService");class CurdTable{constructor(e,t,r=null){if(this.db=e,this.utils=t,this.controllerWrapper=r,this.hookService=new HookService(e,t,r),this.queryService=new QueryService(e,t,r),!this.queryService)throw new Error("CurdTable requires queryService (execute*Query / getQuery).")}async processRequest(e,t=null,r={}){const o=this.controllerWrapper;let s=this.utils.getModel(this.controllerWrapper,t);const c=e?.action||"list";let i=null;const a={model:s,action:c,request:e,ctx:r,controller:o};switch(this.hookService?.executeValidatorHook&&await this.hookService.executeValidatorHook({...a}),this.hookService?.executeBeforeHook&&(e.beforeActionData=await this.hookService.executeBeforeHook({...a})),c){case"count":i=await this.queryService.executeCountQuery(s,e);break;case"list":i=await this.queryService.getQuery(s,e);break;case"show":i=await this.queryService.executeShowQuery(s,e);break;case"create":i=await this.queryService.executeCreateQuery(s,e);break;case"update":{const t=await this.queryService.executeUpdateQuery(s,e);if(!t)throw new Error(`Record not found or not updated: ${s.table} returned ${t}`);i={message:"Record updated successfully",data:t,success:!0};break}case"delete":{const r=await this.queryService.executeDeleteQuery(s,e);if(!r)throw new Error(`Record not found or not deleted: ${t} returned ${r}`);i={message:"Record deleted successfully",data:r,success:!0};break}default:if(!this.hookService?.executeCustomAction)throw new Error(`Unknown action "${c}" and no custom action hook provided.`);i=await this.hookService.executeCustomAction({...a})}return this.hookService?.executeAfterHook&&(i=await this.hookService.executeAfterHook({...a,data:i})),i}async processRequestWithOthers(e,t=null,r={}){const o=await this.processRequest(e,t,r);if(e?.other_requests&&"object"==typeof e.other_requests){const t={},s=Object.entries(e.other_requests);for(const[e,o]of s)Array.isArray(o)?t[e]=await Promise.all(o.map(t=>this.processRequestWithOthers(t,e,r))):t[e]=await this.processRequestWithOthers(o,e,r);o.other_responses=t}return o}}module.exports=CurdTable;
1
+ const QueryService=require("./QueryService"),HookService=require("./HookService");class CurdTable{constructor(e,t,r=null){if(this.db=e,this.utils=t,this.controllerWrapper=r,this.hookService=new HookService(e,t,r),this.queryService=new QueryService(e,t,r),!this.queryService)throw new Error("CurdTable requires queryService (execute*Query / getQuery).")}async processRequest(e,t=null,r={}){const o=this.controllerWrapper;let s=this.utils.getModel(this.controllerWrapper,t);const i=e?.action||"list";let c=null;const a={model:s,action:i,request:e,ctx:r,controller:o};switch(this.hookService?.executeValidatorHook&&await this.hookService.executeValidatorHook({...a}),this.hookService?.executeBeforeHook&&(e.beforeActionData=await this.hookService.executeBeforeHook({...a})),i){case"count":c=await this.queryService.executeCountQuery(s,e);break;case"list":c=await this.hookService.executeHasSoftDeleteHook(s)?await this.queryService.getSoftDeleteQuery(s,e):await this.queryService.getQuery(s,e);break;case"show":c=await this.queryService.executeShowQuery(s,e);break;case"create":c=await this.queryService.executeCreateQuery(s,e);break;case"update":{const t=await this.queryService.executeUpdateQuery(s,e);if(!t)throw new Error(`Record not found or not updated: ${s.table} returned ${t}`);c={message:"Record updated successfully",data:t,success:!0};break}case"delete":{let r=null;if(r=await this.hookService.executeHasSoftDeleteHook(s)?await this.queryService.executeSoftDeleteQuery(s,e):await this.queryService.executeDeleteQuery(s,e),!r)throw new Error(`Record not found or not deleted: ${t} returned ${r}`);c={message:"Record deleted successfully",data:r,success:!0};break}default:if(!this.hookService?.executeCustomAction)throw new Error(`Unknown action "${i}" and no custom action hook provided.`);c=await this.hookService.executeCustomAction({...a})}return this.hookService?.executeAfterHook&&(c=await this.hookService.executeAfterHook({...a,data:c})),c}async processRequestWithOthers(e,t=null,r={}){const o=await this.processRequest(e,t,r);if(e?.other_requests&&"object"==typeof e.other_requests){const t={},s=Object.entries(e.other_requests);for(const[e,o]of s)Array.isArray(o)?t[e]=await Promise.all(o.map(t=>this.processRequestWithOthers(t,e,r))):t[e]=await this.processRequestWithOthers(o,e,r);o.other_responses=t}return o}}module.exports=CurdTable;
@@ -1 +1 @@
1
- const path=require("path");class HookService{constructor(e,o,t=null){this.db=e,this.utils=o,this.controllerWrapper=t,this.appRoot=t&&t.resolverPath?t.resolverPath:process.cwd()}loadModelClass(e){try{const o=path.join(this.appRoot,"models",`${e}.model.js`);delete require.cache[require.resolve(o)];return require(o)}catch(e){return void console.log("loadModelClass error",{err:e})}}resolveModelHook(e,o,t){const r=e.modelName,s=this.loadModelClass(r);if(!s)return;const l="function"==typeof s?new s:s;let i;if("validate"===o)i="validate";else if("on"===o)i=`on${t.charAt(0).toUpperCase()+t.slice(1)}`;else if("before"===o)i=`before${t.charAt(0).toUpperCase()+t.slice(1)}`;else if("after"===o)i=`after${t.charAt(0).toUpperCase()+t.slice(1)}`;else{if("custom"!==o)return;i=`on${t.charAt(0).toUpperCase()+t.slice(1)}Action`}return"function"==typeof l[i]?l[i].bind(l):"function"==typeof s[i]?s[i].bind(s):void 0}async executeValidatorHook({model:e,action:o,request:t,ctx:r,controller:s}){const l=this.resolveModelHook(e,"validate",o);if(l)return await l({model:e,action:o,request:t,context:r,db:this.db,utils:this.utils,controller:s})}async executeBeforeHook({model:e,action:o,request:t,ctx:r,controller:s}){const l=this.resolveModelHook(e,"before",o);if(l)return await l({model:e,action:o,request:t,context:r,db:this.db,utils:this.utils,controller:s})}async executeAfterHook({model:e,action:o,data:t,request:r,ctx:s,controller:l}){const i=this.resolveModelHook(e,"after",o);return i?await i({model:e,action:o,data:t,request:r,context:s,db:this.db,utils:this.utils,controller:l}):t}async executeCustomAction({model:e,action:o,request:t,ctx:r,controller:s}){const l=this.resolveModelHook(e,"custom",o);if(l)return await l({model:e,action:o,request:t,context:r,db:this.db,utils:this.utils,controller:s});throw new Error(`No custom action hook found for ${e.modelName}.${o}`)}}module.exports=HookService;
1
+ const path=require("path");class HookService{constructor(e,t,o=null){this.db=e,this.utils=t,this.controllerWrapper=o,this.appRoot=o&&o.resolverPath?o.resolverPath:process.cwd()}loadModelClass(e){try{const t=path.join(this.appRoot,"models",`${e}.model.js`);delete require.cache[require.resolve(t)];return require(t)}catch(e){return void console.log("loadModelClass error",{err:e})}}getModelInstance(e){const t=e.modelName,o=this.loadModelClass(t);if(o)return"function"==typeof o?new o:o}resolveModelHook(e,t,o){const r=e.modelName,s=this.loadModelClass(r);if(!s)return;const l=this.getModelInstance(e);let i;if("validate"===t)i="validate";else if("on"===t)i=`on${o.charAt(0).toUpperCase()+o.slice(1)}`;else if("before"===t)i=`before${o.charAt(0).toUpperCase()+o.slice(1)}`;else if("after"===t)i=`after${o.charAt(0).toUpperCase()+o.slice(1)}`;else{if("custom"!==t)return;i=`on${o.charAt(0).toUpperCase()+o.slice(1)}Action`}return"function"==typeof l[i]?l[i].bind(l):"function"==typeof s[i]?s[i].bind(s):void 0}async executeValidatorHook({model:e,action:t,request:o,ctx:r,controller:s}){const l=this.resolveModelHook(e,"validate",t);if(l)return await l({model:e,action:t,request:o,context:r,db:this.db,utils:this.utils,controller:s})}async executeBeforeHook({model:e,action:t,request:o,ctx:r,controller:s}){const l=this.resolveModelHook(e,"before",t);if(l)return await l({model:e,action:t,request:o,context:r,db:this.db,utils:this.utils,controller:s})}async executeAfterHook({model:e,action:t,data:o,request:r,ctx:s,controller:l}){const i=this.resolveModelHook(e,"after",t);return i?await i({model:e,action:t,data:o,request:r,context:s,db:this.db,utils:this.utils,controller:l}):o}async executeCustomAction({model:e,action:t,request:o,ctx:r,controller:s}){const l=this.resolveModelHook(e,"custom",t);if(l)return await l({model:e,action:t,request:o,context:r,db:this.db,utils:this.utils,controller:s});throw new Error(`No custom action hook found for ${e.modelName}.${t}`)}async executeHasSoftDeleteHook(e){const t=this.getModelInstance(e);if(!t)return!1;return t.hasOwnProperty("hasSoftDelete")&&!0===t.hasSoftDelete}}module.exports=HookService;
@@ -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)}_applyWhereCondition(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.whereLike(t,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:l,relation:o}=e;let a=t.map(e=>e[o.localKey]),s=[];s="one"===o?.type?await this.fetchRelatedRows(o,a).first():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];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:c,having:p,distinct:y,join:u,leftJoin:f,rightJoin:d,innerJoin:g,count:w=!1}=t;let b=this.getQueryBuilder(e);o&&(Array.isArray(o)||"string"==typeof o)?b.select(o):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,m=n,j=1,A=0;h&&s>0&&(j=Math.max(1,parseInt(h)),m=(j-1)*s),s>0&&(b.limit(_),m>0&&b.offset(m));const k=await b;if(i&&i.length>0){const t=this.buildWithTree(i);for(const r of Object.keys(t))await this.fetchAndAttachRelated({parentRows:k,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=k.length}s>0&&null!==B&&(A=Math.ceil(B/s),W=j<A);return{data:k,totalCount:B,...s>0?{pagination:{page:j,limit:_,offset:m,totalPages:A,hasNext:W,hasPrev:j>1,nextPage:W?j+1:null,prevPage:j>1?j-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:l}=this.parseWhereValue(i);this._applyWhereCondition(e,t,r,l)}}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
+ 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)}_applyWhereCondition(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.whereLike(t,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: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:c,having:p,distinct:y,join:u,leftJoin:f,rightJoin:d,innerJoin:g,count:w=!1}=t;let b=this.getQueryBuilder(e);o&&(Array.isArray(o)||"string"==typeof o)?b.select(o):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,m=n,j=1,A=0;h&&s>0&&(j=Math.max(1,parseInt(h)),m=(j-1)*s),s>0&&(b.limit(_),m>0&&b.offset(m));const k=await b;if(i&&i.length>0){const t=this.buildWithTree(i);for(const r of Object.keys(t))await this.fetchAndAttachRelated({parentRows:k,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=k.length}s>0&&null!==B&&(A=Math.ceil(B/s),W=j<A);return{data:k,totalCount:B,...s>0?{pagination:{page:j,limit:_,offset:m,totalPages:A,hasNext:W,hasPrev:j>1,nextPage:W?j+1:null,prevPage:j>1?j-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:l}=this.parseWhereValue(i);this._applyWhereCondition(e,t,r,l)}}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 QueryBuilder=require("./QueryBuilder");class QueryService{constructor(e,t,r=null){this.db=e,this.utils=t,this.controllerWrapper=r,this.queryBuilder=new QueryBuilder(e,t,r)}async getQuery(e,t){return await this.queryBuilder.getQuery(e,t)}async executeShowQuery(e,t){let r=await this.getQuery(e,{...t,limit:1,offset:0});return r.data.length>0?r.data[0]:null}async executeCountQuery(e,t){let r=await this.db(e.table).count();return Object.values(r[0])[0]}async executeCreateQuery(e,t){return await this.db(e.table).insert(t.data).returning("*")}async executeUpdateQuery(e,t){return await this.db(e.table).where(t.where).update(t.data).returning("*")}async executeDeleteQuery(e,t){return await this.db(e.table).where(t.where).delete()}async executeUpsertQuery(e,t){return await this.db(e.table).insert(t.data).onConflict(t.conflict).update(t.data)}async executeReplaceQuery(e,t){return await this.db(e.table).replace(t.data)}}module.exports=QueryService;
1
+ const QueryBuilder=require("./QueryBuilder");class QueryService{constructor(e,t,r=null){this.db=e,this.utils=t,this.controllerWrapper=r,this.queryBuilder=new QueryBuilder(e,t,r)}async getQuery(e,t){return await this.queryBuilder.getQuery(e,t)}async getSoftDeleteQuery(e,t){return await this.queryBuilder.getQuery(e,{...t,where:{...t.where,deleted_at:null}})}async executeShowQuery(e,t){let r=await this.getQuery(e,{...t,limit:1,offset:0});return r.data.length>0?r.data[0]:null}async executeCountQuery(e,t){let r=await this.db(e.table).count();return Object.values(r[0])[0]}async executeCreateQuery(e,t){return await this.db(e.table).insert(t.data).returning("*")}async executeUpdateQuery(e,t){return await this.db(e.table).where(t.where).update(t.data).returning("*")}async executeDeleteQuery(e,t){return await this.db(e.table).where(t.where).delete()}async executeSoftDeleteQuery(e,t){return await this.db(e.table).where(t.where).update({deleted_at:new Date}).returning("*")}async executeUpsertQuery(e,t){return await this.db(e.table).insert(t.data).onConflict(t.conflict).update(t.data)}async executeReplaceQuery(e,t){return await this.db(e.table).replace(t.data)}}module.exports=QueryService;
@@ -1 +1 @@
1
- const QueryService=require("./QueryService"),HookService=require("./HookService");class CurdTable{constructor(e,t,r=null){if(this.db=e,this.utils=t,this.controllerWrapper=r,this.hookService=new HookService(e,t,r),this.queryService=new QueryService(e,t,r),!this.queryService)throw new Error("CurdTable requires queryService (execute*Query / getQuery).")}async processRequest(e,t=null,r=null){const o=this.controllerWrapper;let s=this.utils.getModel(this.controllerWrapper,t);const c=e?.action||"list";let i=null;const u={model:s,action:c,request:e,ctx:r,controller:o};switch(this.hookService?.executeValidatorHook&&await this.hookService.executeValidatorHook({...u}),this.hookService?.executeBeforeHook&&(e.beforeActionData=await this.hookService.executeBeforeHook({...u})),c){case"count":i=await this.queryService.executeCountQuery(s,e);break;case"list":i=await this.queryService.getQuery(s,e);break;case"show":i=await this.queryService.executeShowQuery(s,e);break;case"create":i=await this.queryService.executeCreateQuery(s,e);break;case"update":{const t=await this.queryService.executeUpdateQuery(s,e);if(!t)throw new Error(`Record not found or not updated: ${s.table} returned ${t}`);i={message:"Record updated successfully",data:t,success:!0};break}case"delete":{const r=await this.queryService.executeDeleteQuery(s,e);if(!r)throw new Error(`Record not found or not deleted: ${t} returned ${r}`);i={message:"Record deleted successfully",data:r,success:!0};break}default:if(!this.hookService?.executeCustomAction)throw new Error(`Unknown action "${c}" and no custom action hook provided.`);i=await this.hookService.executeCustomAction({...u})}return this.hookService?.executeAfterHook&&(i=await this.hookService.executeAfterHook({...u,data:i})),i}async processRequestWithOthers(e,t=null,r={}){const o=await this.processRequest(e,t,r);if(e?.other_requests&&"object"==typeof e.other_requests){const t={},s=Object.entries(e.other_requests);for(const[e,o]of s)Array.isArray(o)?t[e]=await Promise.all(o.map(t=>this.processRequestWithOthers(t,e,r))):t[e]=await this.processRequestWithOthers(o,e,r);o.other_responses=t}return o}}module.exports=CurdTable;
1
+ const QueryService=require("./QueryService"),HookService=require("./HookService");class CurdTable{constructor(e,t,r=null){if(this.db=e,this.utils=t,this.controllerWrapper=r,this.hookService=new HookService(e,t,r),this.queryService=new QueryService(e,t,r),!this.queryService)throw new Error("CurdTable requires queryService (execute*Query / getQuery).")}async processRequest(e,t=null,r=null){const o=this.controllerWrapper;let s=this.utils.getModel(this.controllerWrapper,t);const i=e?.action||"list";let c=null;const a={model:s,action:i,request:e,ctx:r,controller:o};switch(this.hookService?.executeValidatorHook&&await this.hookService.executeValidatorHook({...a}),this.hookService?.executeBeforeHook&&(e.beforeActionData=await this.hookService.executeBeforeHook({...a})),i){case"count":c=await this.queryService.executeCountQuery(s,e);break;case"list":c=await this.hookService.executeHasSoftDeleteHook(s)?await this.queryService.getSoftDeleteQuery(s,e):await this.queryService.getQuery(s,e);break;case"show":c=await this.queryService.executeShowQuery(s,e);break;case"create":c=await this.queryService.executeCreateQuery(s,e);break;case"update":{const t=await this.queryService.executeUpdateQuery(s,e);if(!t)throw new Error(`Record not found or not updated: ${s.table} returned ${t}`);c={message:"Record updated successfully",data:t,success:!0};break}case"delete":{let r=null;if(r=await this.hookService.executeHasSoftDeleteHook(s)?await this.queryService.executeSoftDeleteQuery(s,e):await this.queryService.executeDeleteQuery(s,e),!r)throw new Error(`Record not found or not deleted: ${t} returned ${r}`);c={message:"Record deleted successfully",data:r,success:!0};break}default:if(!this.hookService?.executeCustomAction)throw new Error(`Unknown action "${i}" and no custom action hook provided.`);c=await this.hookService.executeCustomAction({...a})}return this.hookService?.executeAfterHook&&(c=await this.hookService.executeAfterHook({...a,data:c})),c}async processRequestWithOthers(e,t=null,r={}){const o=await this.processRequest(e,t,r);if(e?.other_requests&&"object"==typeof e.other_requests){const t={},s=Object.entries(e.other_requests);for(const[e,o]of s)Array.isArray(o)?t[e]=await Promise.all(o.map(t=>this.processRequestWithOthers(t,e,r))):t[e]=await this.processRequestWithOthers(o,e,r);o.other_responses=t}return o}}module.exports=CurdTable;
@@ -1 +1 @@
1
- const path=require("path");class HookService{constructor(e,o,t=null){this.db=e,this.utils=o,this.controllerWrapper=t,this.appRoot=t&&t.resolverPath?t.resolverPath:process.cwd()}loadModelClass(e){try{const o=path.join(this.appRoot,"models",`${e}.model.js`);delete require.cache[require.resolve(o)];return require(o)}catch(e){return void console.log("loadModelClass error",{err:e})}}resolveModelHook(e,o,t){const r=e.modelName,s=this.loadModelClass(r);if(!s)return;const l="function"==typeof s?new s:s;let i;if("validate"===o)i="validate";else if("on"===o)i=`on${t.charAt(0).toUpperCase()+t.slice(1)}`;else if("before"===o)i=`before${t.charAt(0).toUpperCase()+t.slice(1)}`;else if("after"===o)i=`after${t.charAt(0).toUpperCase()+t.slice(1)}`;else{if("custom"!==o)return;i=`on${t.charAt(0).toUpperCase()+t.slice(1)}Action`}return"function"==typeof l[i]?l[i].bind(l):"function"==typeof s[i]?s[i].bind(s):void 0}async executeValidatorHook({model:e,action:o,request:t,ctx:r,controller:s}){const l=this.resolveModelHook(e,"validate",o);if(l)return await l({model:e,action:o,request:t,context:r,db:this.db,utils:this.utils,controller:s})}async executeBeforeHook({model:e,action:o,request:t,ctx:r,controller:s}){const l=this.resolveModelHook(e,"before",o);if(l)return await l({model:e,action:o,request:t,context:r,db:this.db,utils:this.utils,controller:s})}async executeAfterHook({model:e,action:o,data:t,request:r,ctx:s,controller:l}){const i=this.resolveModelHook(e,"after",o);return i?await i({model:e,action:o,data:t,request:r,context:s,db:this.db,utils:this.utils,controller:l}):t}async executeCustomAction({model:e,action:o,request:t,ctx:r,controller:s}){const l=this.resolveModelHook(e,"custom",o);if(l)return await l({model:e,action:o,request:t,context:r,db:this.db,utils:this.utils,controller:s});throw new Error(`No custom action hook found for ${e.modelName}.${o}`)}}module.exports=HookService;
1
+ const path=require("path");class HookService{constructor(e,t,o=null){this.db=e,this.utils=t,this.controllerWrapper=o,this.appRoot=o&&o.resolverPath?o.resolverPath:process.cwd()}loadModelClass(e){try{const t=path.join(this.appRoot,"models",`${e}.model.js`);delete require.cache[require.resolve(t)];return require(t)}catch(e){return void console.log("loadModelClass error",{err:e})}}getModelInstance(e){const t=e.modelName,o=this.loadModelClass(t);if(o)return"function"==typeof o?new o:o}resolveModelHook(e,t,o){const r=e.modelName,s=this.loadModelClass(r);if(!s)return;const l=this.getModelInstance(e);let i;if("validate"===t)i="validate";else if("on"===t)i=`on${o.charAt(0).toUpperCase()+o.slice(1)}`;else if("before"===t)i=`before${o.charAt(0).toUpperCase()+o.slice(1)}`;else if("after"===t)i=`after${o.charAt(0).toUpperCase()+o.slice(1)}`;else{if("custom"!==t)return;i=`on${o.charAt(0).toUpperCase()+o.slice(1)}Action`}return"function"==typeof l[i]?l[i].bind(l):"function"==typeof s[i]?s[i].bind(s):void 0}async executeValidatorHook({model:e,action:t,request:o,ctx:r,controller:s}){const l=this.resolveModelHook(e,"validate",t);if(l)return await l({model:e,action:t,request:o,context:r,db:this.db,utils:this.utils,controller:s})}async executeBeforeHook({model:e,action:t,request:o,ctx:r,controller:s}){const l=this.resolveModelHook(e,"before",t);if(l)return await l({model:e,action:t,request:o,context:r,db:this.db,utils:this.utils,controller:s})}async executeAfterHook({model:e,action:t,data:o,request:r,ctx:s,controller:l}){const i=this.resolveModelHook(e,"after",t);return i?await i({model:e,action:t,data:o,request:r,context:s,db:this.db,utils:this.utils,controller:l}):o}async executeCustomAction({model:e,action:t,request:o,ctx:r,controller:s}){const l=this.resolveModelHook(e,"custom",t);if(l)return await l({model:e,action:t,request:o,context:r,db:this.db,utils:this.utils,controller:s});throw new Error(`No custom action hook found for ${e.modelName}.${t}`)}async executeHasSoftDeleteHook(e){const t=this.getModelInstance(e);if(!t)return!1;return t.hasOwnProperty("hasSoftDelete")&&!0===t.hasSoftDelete}}module.exports=HookService;
@@ -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)}_applyWhereCondition(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.whereLike(t,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: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];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:c,having:p,distinct:y,join:u,leftJoin:f,rightJoin:d,innerJoin:g,count:w=!1}=t;let b=this.getQueryBuilder(e);o&&(Array.isArray(o)||"string"==typeof o)?b.select(o):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,m=n,j=1,A=0;h&&s>0&&(j=Math.max(1,parseInt(h)),m=(j-1)*s),s>0&&(b.limit(_),m>0&&b.offset(m));const k=await b;if(i&&i.length>0){const t=this.buildWithTree(i);for(const r of Object.keys(t))await this.fetchAndAttachRelated({parentRows:k,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=k.length}s>0&&null!==B&&(A=Math.ceil(B/s),W=j<A);return{data:k,totalCount:B,...s>0?{pagination:{page:j,limit:_,offset:m,totalPages:A,hasNext:W,hasPrev:j>1,nextPage:W?j+1:null,prevPage:j>1?j-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:l}=this.parseWhereValue(i);this._applyWhereCondition(e,t,r,l)}}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
+ 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)}_applyWhereCondition(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.whereLike(t,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: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:c,having:p,distinct:y,join:u,leftJoin:f,rightJoin:d,innerJoin:g,count:w=!1}=t;let b=this.getQueryBuilder(e);o&&(Array.isArray(o)||"string"==typeof o)?b.select(o):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,m=n,j=1,A=0;h&&s>0&&(j=Math.max(1,parseInt(h)),m=(j-1)*s),s>0&&(b.limit(_),m>0&&b.offset(m));const k=await b;if(i&&i.length>0){const t=this.buildWithTree(i);for(const r of Object.keys(t))await this.fetchAndAttachRelated({parentRows:k,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=k.length}s>0&&null!==B&&(A=Math.ceil(B/s),W=j<A);return{data:k,totalCount:B,...s>0?{pagination:{page:j,limit:_,offset:m,totalPages:A,hasNext:W,hasPrev:j>1,nextPage:W?j+1:null,prevPage:j>1?j-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:l}=this.parseWhereValue(i);this._applyWhereCondition(e,t,r,l)}}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 QueryBuilder=require("./QueryBuilder");class QueryService{constructor(e,t,r=null){this.db=e,this.utils=t,this.controllerWrapper=r,this.queryBuilder=new QueryBuilder(e,t,r)}async getQuery(e,t){return await this.queryBuilder.getQuery(e,t)}async executeShowQuery(e,t){let r=await this.getQuery(e,{...t,limit:1,offset:0});return r.data.length>0?r.data[0]:null}async executeCountQuery(e,t){let r=await this.db(e.table).count();return Object.values(r[0])[0]}async executeCreateQuery(e,t){return await this.db(e.table).insert(t.data).returning("*")}async executeUpdateQuery(e,t){return await this.db(e.table).where(t.where).update(t.data).returning("*")}async executeDeleteQuery(e,t){return await this.db(e.table).where(t.where).delete()}async executeUpsertQuery(e,t){return await this.db(e.table).insert(t.data).onConflict(t.conflict).update(t.data)}async executeReplaceQuery(e,t){return await this.db(e.table).replace(t.data)}}module.exports=QueryService;
1
+ const QueryBuilder=require("./QueryBuilder");class QueryService{constructor(e,t,r=null){this.db=e,this.utils=t,this.controllerWrapper=r,this.queryBuilder=new QueryBuilder(e,t,r)}async getQuery(e,t){return await this.queryBuilder.getQuery(e,t)}async getSoftDeleteQuery(e,t){return await this.queryBuilder.getQuery(e,{...t,where:{...t.where,deleted_at:null}})}async executeShowQuery(e,t){let r=await this.getQuery(e,{...t,limit:1,offset:0});return r.data.length>0?r.data[0]:null}async executeCountQuery(e,t){let r=await this.db(e.table).count();return Object.values(r[0])[0]}async executeCreateQuery(e,t){return await this.db(e.table).insert(t.data).returning("*")}async executeUpdateQuery(e,t){return await this.db(e.table).where(t.where).update(t.data).returning("*")}async executeDeleteQuery(e,t){return await this.db(e.table).where(t.where).delete()}async executeSoftDeleteQuery(e,t){return await this.db(e.table).where(t.where).update({deleted_at:new Date}).returning("*")}async executeUpsertQuery(e,t){return await this.db(e.table).insert(t.data).onConflict(t.conflict).update(t.data)}async executeReplaceQuery(e,t){return await this.db(e.table).replace(t.data)}}module.exports=QueryService;
@@ -1 +1 @@
1
- const QueryService=require("./QueryService"),HookService=require("./HookService");class CurdTable{constructor(e,t,r=null){if(this.db=e,this.utils=t,this.controllerWrapper=r,this.hookService=new HookService(e,t,r),this.queryService=new QueryService(e,t,r),!this.queryService)throw new Error("CurdTable requires queryService (execute*Query / getQuery).")}async processRequest(e,t=null,r={}){let o=this.utils.getModel(this.controllerWrapper,t);const s=e?.action||"list";let i=null;switch(this.hookService?.executeValidatorHook&&await this.hookService.executeValidatorHook(o,s,e,r),this.hookService?.executeBeforeHook&&(e.beforeActionData=await this.hookService.executeBeforeHook(o,s,e,r)),s){case"count":i=await this.queryService.executeCountQuery(o,e);break;case"list":i=await this.queryService.getQuery(o,e);break;case"show":i=await this.queryService.executeShowQuery(o,e);break;case"create":i=await this.queryService.executeCreateQuery(o,e);break;case"update":{const t=await this.queryService.executeUpdateQuery(o,e);if(!t)throw new Error(`Record not found or not updated: ${o.table} returned ${t}`);i={message:"Record updated successfully",data:t,success:!0};break}case"delete":{const r=await this.queryService.executeDeleteQuery(t,e);if(!r)throw new Error(`Record not found or not deleted: ${t} returned ${r}`);i={message:"Record deleted successfully",data:r,success:!0};break}default:if(!this.hookService?.executeCustomAction)throw new Error(`Unknown action "${s}" and no custom action hook provided.`);i=await this.hookService.executeCustomAction(t,s,e,r)}return this.hookService?.executeAfterHook&&(i=await this.hookService.executeAfterHook(t,s,i,e,r)),i}async processRequestWithOthers(e,t=null,r={}){const o=await this.processRequest(e,t,r);if(e?.other_requests&&"object"==typeof e.other_requests){const t={},s=Object.entries(e.other_requests);for(const[e,o]of s)Array.isArray(o)?t[e]=await Promise.all(o.map(t=>this.processRequestWithOthers(t,e,r))):t[e]=await this.processRequestWithOthers(o,e,r);o.other_responses=t}return o}}module.exports=CurdTable;
1
+ const QueryService=require("./QueryService"),HookService=require("./HookService");class CurdTable{constructor(e,t,r=null){if(this.db=e,this.utils=t,this.controllerWrapper=r,this.hookService=new HookService(e,t,r),this.queryService=new QueryService(e,t,r),!this.queryService)throw new Error("CurdTable requires queryService (execute*Query / getQuery).")}async processRequest(e,t=null,r={}){let o=this.utils.getModel(this.controllerWrapper,t);const s=e?.action||"list";let i=null;switch(this.hookService?.executeValidatorHook&&await this.hookService.executeValidatorHook(o,s,e,r),this.hookService?.executeBeforeHook&&(e.beforeActionData=await this.hookService.executeBeforeHook(o,s,e,r)),s){case"count":i=await this.queryService.executeCountQuery(o,e);break;case"list":i=await this.hookService.executeHasSoftDeleteHook(o)?await this.queryService.getSoftDeleteQuery(o,e):await this.queryService.getQuery(o,e);break;case"show":i=await this.queryService.executeShowQuery(o,e);break;case"create":i=await this.queryService.executeCreateQuery(o,e);break;case"update":{const t=await this.queryService.executeUpdateQuery(o,e);if(!t)throw new Error(`Record not found or not updated: ${o.table} returned ${t}`);i={message:"Record updated successfully",data:t,success:!0};break}case"delete":{let r=null;if(r=await this.hookService.executeHasSoftDeleteHook(o)?await this.queryService.executeSoftDeleteQuery(o,e):await this.queryService.executeDeleteQuery(o,e),!r)throw new Error(`Record not found or not deleted: ${t} returned ${r}`);i={message:"Record deleted successfully",data:r,success:!0};break}default:if(!this.hookService?.executeCustomAction)throw new Error(`Unknown action "${s}" and no custom action hook provided.`);i=await this.hookService.executeCustomAction(t,s,e,r)}return this.hookService?.executeAfterHook&&(i=await this.hookService.executeAfterHook(t,s,i,e,r)),i}async processRequestWithOthers(e,t=null,r={}){const o=await this.processRequest(e,t,r);if(e?.other_requests&&"object"==typeof e.other_requests){const t={},s=Object.entries(e.other_requests);for(const[e,o]of s)Array.isArray(o)?t[e]=await Promise.all(o.map(t=>this.processRequestWithOthers(t,e,r))):t[e]=await this.processRequestWithOthers(o,e,r);o.other_responses=t}return o}}module.exports=CurdTable;
@@ -1 +1 @@
1
- const path=require("path");class HookService{constructor(e,t,o=null){this.db=e,this.utils=t,this.controllerWrapper=o,this.appRoot=o&&o.resolverPath?o.resolverPath:process.cwd()}loadModelClass(e){try{const t=path.join(this.appRoot,"models",`${e}.model.js`);delete require.cache[require.resolve(t)];return require(t)}catch(e){return}}resolveModelHook(e,t,o){const s=e.name,r=this.loadModelClass(s);if(!r)return;const i="function"==typeof r?new r:r;let a;if("validate"===t)a="validate";else if("on"===t)a=`on${o.charAt(0).toUpperCase()+o.slice(1)}`;else if("before"===t)a=`before${o.charAt(0).toUpperCase()+o.slice(1)}`;else if("after"===t)a=`after${o.charAt(0).toUpperCase()+o.slice(1)}`;else{if("custom"!==t)return;a=`custom${o.charAt(0).toUpperCase()+o.slice(1)}`}return"function"==typeof i[a]?i[a].bind(i):"function"==typeof r[a]?r[a].bind(r):void 0}async executeValidatorHook(e,t,o,s){const r=this.resolveModelHook(e,"validate",t);if(r)return await r({model:e,action:t,request:o,context:s,db:this.db,utils:this.utils})}async executeBeforeHook(e,t,o,s){const r=this.resolveModelHook(e,"before",t);if(r)return await r({model:e,action:t,request:o,context:s,db:this.db,utils:this.utils})}async executeAfterHook(e,t,o,s,r){const i=this.resolveModelHook(e,"after",t);return i?await i({model:e,action:t,data:o,request:s,context:r,db:this.db,utils:this.utils}):o}async executeCustomAction(e,t,o,s){const r=this.resolveModelHook(e,"custom",t);if(r)return await r({model:e,action:t,request:o,context:s,db:this.db,utils:this.utils});throw new Error(`No custom action hook found for ${e}.${t}`)}}module.exports=HookService;
1
+ const path=require("path");class HookService{constructor(e,t,o=null){this.db=e,this.utils=t,this.controllerWrapper=o,this.appRoot=o&&o.resolverPath?o.resolverPath:process.cwd()}loadModelClass(e){try{const t=path.join(this.appRoot,"models",`${e}.model.js`);delete require.cache[require.resolve(t)];return require(t)}catch(e){return}}getModelInstance(e){const t=e.name,o=this.loadModelClass(t);if(o)return"function"==typeof o?new o:o}resolveModelHook(e,t,o){const s=e.name,r=this.loadModelClass(s);if(!r)return;const i=this.getModelInstance(e);let a;if("validate"===t)a="validate";else if("on"===t)a=`on${o.charAt(0).toUpperCase()+o.slice(1)}`;else if("before"===t)a=`before${o.charAt(0).toUpperCase()+o.slice(1)}`;else if("after"===t)a=`after${o.charAt(0).toUpperCase()+o.slice(1)}`;else{if("custom"!==t)return;a=`custom${o.charAt(0).toUpperCase()+o.slice(1)}`}return"function"==typeof i[a]?i[a].bind(i):"function"==typeof r[a]?r[a].bind(r):void 0}async executeValidatorHook(e,t,o,s){const r=this.resolveModelHook(e,"validate",t);if(r)return await r({model:e,action:t,request:o,context:s,db:this.db,utils:this.utils})}async executeBeforeHook(e,t,o,s){const r=this.resolveModelHook(e,"before",t);if(r)return await r({model:e,action:t,request:o,context:s,db:this.db,utils:this.utils})}async executeAfterHook(e,t,o,s,r){const i=this.resolveModelHook(e,"after",t);return i?await i({model:e,action:t,data:o,request:s,context:r,db:this.db,utils:this.utils}):o}async executeCustomAction(e,t,o,s){const r=this.resolveModelHook(e,"custom",t);if(r)return await r({model:e,action:t,request:o,context:s,db:this.db,utils:this.utils});throw new Error(`No custom action hook found for ${e}.${t}`)}async executeHasSoftDeleteHook(e){const t=this.getModelInstance(e);if(!t)return!1;return t.hasOwnProperty("hasSoftDelete")&&!0===t.hasSoftDelete}}module.exports=HookService;
@@ -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)}_applyWhereCondition(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.whereLike(t,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:l,relation:o}=e;let a=t.map(e=>e[o.localKey]),s=[];s="one"===o?.type?await this.fetchRelatedRows(o,a).first():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];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:c,having:p,distinct:y,join:u,leftJoin:f,rightJoin:d,innerJoin:g,count:w=!1}=t;let b=this.getQueryBuilder(e);o&&(Array.isArray(o)||"string"==typeof o)?b.select(o):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,m=s,_=n,j=1,A=0;h&&s>0&&(j=Math.max(1,parseInt(h)),_=(j-1)*s),s>0&&(b.limit(m),_>0&&b.offset(_));const k=await b;if(i&&i.length>0){const t=this.buildWithTree(i);for(const r of Object.keys(t))await this.fetchAndAttachRelated({parentRows:k,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=k.length}s>0&&null!==B&&(A=Math.ceil(B/s),W=j<A);return{data:k,totalCount:B,...s>0?{pagination:{page:j,limit:m,offset:_,totalPages:A,hasNext:W,hasPrev:j>1,nextPage:W?j+1:null,prevPage:j>1?j-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:i}=this.parseWhereValue(i);this._applyWhereCondition(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 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;
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)}_applyWhereCondition(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.whereLike(t,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: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:c,having:p,distinct:y,join:u,leftJoin:f,rightJoin:d,innerJoin:g,count:w=!1}=t;let b=this.getQueryBuilder(e);o&&(Array.isArray(o)||"string"==typeof o)?b.select(o):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,m=s,_=n,j=1,A=0;h&&s>0&&(j=Math.max(1,parseInt(h)),_=(j-1)*s),s>0&&(b.limit(m),_>0&&b.offset(_));const k=await b;if(i&&i.length>0){const t=this.buildWithTree(i);for(const r of Object.keys(t))await this.fetchAndAttachRelated({parentRows:k,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=k.length}s>0&&null!==B&&(A=Math.ceil(B/s),W=j<A);return{data:k,totalCount:B,...s>0?{pagination:{page:j,limit:m,offset:_,totalPages:A,hasNext:W,hasPrev:j>1,nextPage:W?j+1:null,prevPage:j>1?j-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:i}=this.parseWhereValue(i);this._applyWhereCondition(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 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;
@@ -1 +1 @@
1
- const QueryBuilder=require("./QueryBuilder");class QueryService{constructor(e,t,r=null){this.db=e,this.utils=t,this.controllerWrapper=r,this.queryBuilder=new QueryBuilder(e,t,r)}async getQuery(e,t){return await this.queryBuilder.getQuery(e,t)}async executeShowQuery(e,t){let r=await this.getQuery(e,{...t,limit:1,offset:0});return r.data.length>0?r.data[0]:null}async executeCountQuery(e,t){let r=await this.db(e.table).count();return Object.values(r[0])[0]}async executeCreateQuery(e,t){return await this.db(e.table).insert(t.data).returning("*")}async executeUpdateQuery(e,t){return await this.db(e.table).where(t.where).update(t.data).returning("*")}async executeDeleteQuery(e,t){return await this.db(e.table).where(t.where).delete()}async executeUpsertQuery(e,t){return await this.db(e.table).insert(t.data).onConflict(t.conflict).update(t.data)}async executeReplaceQuery(e,t){return await this.db(e.table).replace(t.data)}}module.exports=QueryService;
1
+ const QueryBuilder=require("./QueryBuilder");class QueryService{constructor(e,t,r=null){this.db=e,this.utils=t,this.controllerWrapper=r,this.queryBuilder=new QueryBuilder(e,t,r)}async getQuery(e,t){return await this.queryBuilder.getQuery(e,t)}async getSoftDeleteQuery(e,t){return await this.queryBuilder.getQuery(e,{...t,where:{...t.where,deleted_at:null}})}async executeShowQuery(e,t){let r=await this.getQuery(e,{...t,limit:1,offset:0});return r.data.length>0?r.data[0]:null}async executeCountQuery(e,t){let r=await this.db(e.table).count();return Object.values(r[0])[0]}async executeCreateQuery(e,t){return await this.db(e.table).insert(t.data).returning("*")}async executeUpdateQuery(e,t){return await this.db(e.table).where(t.where).update(t.data).returning("*")}async executeDeleteQuery(e,t){return await this.db(e.table).where(t.where).delete()}async executeSoftDeleteQuery(e,t){return await this.db(e.table).where(t.where).update({deleted_at:new Date}).returning("*")}async executeUpsertQuery(e,t){return await this.db(e.table).insert(t.data).onConflict(t.conflict).update(t.data)}async executeReplaceQuery(e,t){return await this.db(e.table).replace(t.data)}}module.exports=QueryService;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dreamtree-org/korm-js",
3
- "version": "1.0.36",
3
+ "version": "1.0.38",
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",
@@ -3,43 +3,50 @@ class {{modelName}} {
3
3
  this.table = '{{tableName}}';
4
4
  }
5
5
 
6
- validate(data) {
7
- console.log('validate', data);
6
+ validate(args) {
7
+ const { request, context, db } = args;
8
8
  return true;
9
9
  }
10
10
 
11
- onBeforeCreate(data) {
12
- console.log('onBeforeCreate', data);
11
+ onBeforeCreate(args) {
12
+ const { request, context, db, data } = args;
13
+ console.log('onBeforeCreate', { data, request });
13
14
  return data;
14
15
  }
15
16
 
16
- onAfterCreate(data) {
17
- console.log('onAfterCreate', data);
17
+ onAfterCreate(args) {
18
+ const { request, context, db, data } = args;
19
+ console.log('onAfterCreate', { data, request });
18
20
  return data;
19
21
  }
20
22
 
21
- onBeforeUpdate(data) {
22
- console.log('onBeforeUpdate', data);
23
+ onBeforeUpdate(args) {
24
+ const { request, context, db, data } = args;
25
+ console.log('onBeforeUpdate', { data, request });
23
26
  return data;
24
27
  }
25
28
 
26
- onAfterUpdate(data) {
27
- console.log('onAfterUpdate', data);
29
+ onAfterUpdate(args) {
30
+ const { request, context, db, data } = args;
31
+ console.log('onAfterUpdate', { data, request });
28
32
  return data;
29
33
  }
30
34
 
31
- onBeforeDelete(data) {
32
- console.log('onBeforeDelete', data);
35
+ onBeforeDelete(args) {
36
+ const { request, context, db, data } = args;
37
+ console.log('onBeforeDelete', { data, request });
33
38
  return data;
34
39
  }
35
40
 
36
- onAfterDelete(data) {
37
- console.log('onAfterDelete', data);
41
+ onAfterDelete(args) {
42
+ const { request, context, db, data } = args;
43
+ console.log('onAfterDelete', { data, request });
38
44
  return data;
39
45
  }
40
46
 
41
- {{action}}Action(data) {
42
- console.log('{{action}}Action', data);
47
+ {{action}}Action(args) {
48
+ const { request, context, db, data } = args;
49
+ console.log('{{action}}Action', { data, request });
43
50
  return data;
44
51
  }
45
52
  }