UNPKG

scyllinx

Version:

A modern TypeScript ORM for ScyllaDB and SQL databases with Laravel-inspired syntax

2 lines (1 loc) 8.61 kB
import{QueryGrammar as e,DatabaseDriver as t}from"./index.min.js";import"node-cache";import"redis";import"util";import"@faker-js/faker";import"reflect-metadata";class n extends e{compileSelect(e){const t=Array.isArray(e.groups)&&e.groups.length>0,n=Array.isArray(e.havings)&&e.havings.length>0;return t||n?this.compileAggregateSelect(e):this.compileFindSelect(e)}compileFindSelect(e){const t=e.from,n=this.compileWheres(e.wheres),o=this.compileOptions(e);return`${t}:find:${JSON.stringify({filter:n,options:o})}`}compileAggregateSelect(e){const t=e.from,n=[];e.wheres?.length&&n.push({$match:this.compileWheres(e.wheres)});const o=e.groups||[],r={};for(const e of o)r[e]=`$${e}`;const i=this.compileAggregateExpressions(e.columns||[]),s={$group:{_id:o.length?r:null,...i}};if((o.length||Object.keys(i).length)&&n.push(s),e.havings?.length&&n.push({$match:this.compileWheres(e.havings)}),e.columns&&e.columns.length&&!e.columns.includes("*")){const t={};for(const n of e.columns)n.includes("(")||o.includes(n)&&(t[n]=`$_id.${n}`);for(const e of Object.keys(i))t[e]=`$${e}`;n.push({$project:t})}const a=this.compileOptions(e);return a.sort&&n.push({$sort:a.sort}),a.skip&&n.push({$skip:a.skip}),a.limit&&n.push({$limit:a.limit}),`${t}:aggregate:${JSON.stringify(n)}`}compileAggregateExpressions(e){const t={};for(const n of e){const e=n.match(/^(\w+)\(([^)]+)\)(?:\s+as\s+(\w+))?$/i);if(!e)continue;const[,o,r,i]=e,s="*"===r.trim()?1:`$${r.trim()}`,a=i||`${o}_${r.replace(/\*/g,"all")}`;switch(o.toLowerCase()){case"count":t[a]={$sum:1};break;case"sum":t[a]={$sum:s};break;case"avg":t[a]={$avg:s};break;case"min":t[a]={$min:s};break;case"max":t[a]={$max:s}}}return t}compileInsert(e){const t=e.table,n=e.values;return Array.isArray(n)?`${t}:insertMany:${JSON.stringify(n)}`:`${t}:insertOne:${JSON.stringify(n)}`}compileUpdate(e){const t=e.table,n=this.compileWheres(e.wheres),o={$set:e.values};return`${t}:updateMany:${JSON.stringify({filter:n,update:o})}`}compileDelete(e){const t=e.table,n=this.compileWheres(e.wheres);return`${t}:deleteMany:${JSON.stringify({filter:n})}`}compileWheres(e){if(!e||!e.length)return{};const t={};for(const n of e)switch(n.type){case"basic":this.addBasicWhere(t,n);break;case"in":t[n.column]={$in:n.values};break;case"notIn":t[n.column]={$nin:n.values};break;case"between":t[n.column]={$gte:n.values[0],$lte:n.values[1]};break;case"null":t[n.column]=null;break;case"notNull":t[n.column]={$ne:null}}return t}addBasicWhere(e,t){switch(t.operator.toLowerCase()){case"=":e[t.column]=t.value;break;case"!=":case"<>":e[t.column]={$ne:t.value};break;case">":e[t.column]={$gt:t.value};break;case">=":e[t.column]={$gte:t.value};break;case"<":e[t.column]={$lt:t.value};break;case"<=":e[t.column]={$lte:t.value};break;case"like":e[t.column]={$regex:t.value.replace(/%/g,".*"),$options:"i"}}}compileOptions(e){const t={};if(e.columns&&!e.columns.includes("*")){t.projection={};for(const n of e.columns)t.projection[n]=1}if(e.orders){t.sort={};for(const n of e.orders)t.sort[n.column]="desc"===n.direction?-1:1}return e.limit&&(t.limit=e.limit),e.offset&&(t.skip=e.offset),t}wrapTable(e){return e}wrapColumn(e){return e}parameter(e){return JSON.stringify(e)}mapType(e,t){switch(e){case"int":case"integer":return"int";case"float":case"double":case"decimal":return"double";case"string":default:return"string";case"bool":case"boolean":return"bool";case"date":case"datetime":return"date";case"array":return"array";case"object":case"json":return"object";case"uuid":return"binData"}}compileCreateTable(e){const t=e.name,n={$jsonSchema:{bsonType:"object",required:e.columns.filter(e=>e.required).map(e=>e.name),properties:{}}};for(const t of e.columns){const e={bsonType:this.mapType(t.type,t.elementType)};t.maxLength&&(e.maxLength=t.maxLength),t.minLength&&(e.minLength=t.minLength),t.minimum&&(e.minimum=t.minimum),t.maximum&&(e.maximum=t.maximum),t.allowed&&(e.enum=t.allowed),!1===t.nullable&&(e.nullable=!1),t.default&&(e.default=t.default),t.pattern&&(e.default=t.pattern),t.format&&(e.default=t.format),t.comment&&(e.description=t.comment),n.$jsonSchema.properties[t.name]=e}const o={validator:n,validationLevel:"strict",validationAction:"error",...e.tableOptions};return`${t}:createCollection:${JSON.stringify(o)}`}compileAlterTable(e){const t=e.name,n={$jsonSchema:{bsonType:"object",required:e.columns.filter(e=>e.required).map(e=>e.name),properties:{}}};for(const t of e.columns){const e={bsonType:this.mapType(t.type,t.elementType)};t.maxLength&&(e.maxLength=t.maxLength),t.minLength&&(e.minLength=t.minLength),t.minimum&&(e.minimum=t.minimum),t.maximum&&(e.maximum=t.maximum),t.allowed&&(e.enum=t.allowed),!1===t.nullable&&(e.nullable=!1),t.default&&(e.default=t.default),t.pattern&&(e.default=t.pattern),t.format&&(e.default=t.format),t.comment&&(e.description=t.comment),n.$jsonSchema.properties[t.name]=e}const o={validator:n,validationLevel:"strict",validationAction:"error",...e.tableOptions};return`${t}:collMod:${JSON.stringify(o)}`}compileTableExists(e){return`${e}:listCollections:{}`}compileColumnExists(e,t){return`${e}:existsField:${JSON.stringify({field:t})}`}async rename(e,t){throw new Error(`Driver must execute: ${e}:renameCollection:${t}`)}}class o extends t{mongoModule;client;db;grammar;constructor(e){super(e),this.grammar=new n}async connect(){this.mongoModule=await import("mongodb");const{MongoClient:e}=this.mongoModule,t=this.buildConnectionUri();this.client=new e(t,{maxPoolSize:this.config.maxPoolSize||10,serverSelectionTimeoutMS:this.config.serverSelectionTimeoutMS||5e3,socketTimeoutMS:this.config.socketTimeoutMS||45e3}),await this.client.connect(),this.db=this.client.db(this.config.database),this.connection=this.db}async disconnect(){this.client&&(await this.client.close(),this.connection=null)}async query(e,t,n){try{const o=e.indexOf(":"),r=e.indexOf(":",o+1),i=e.substring(0,o),s=e.substring(o+1,r),a=e.substring(r+1),c=this.db.collection(i);let l,u;if(!0===n)l=t;else try{l=a?JSON.parse(a):{}}catch(e){throw new Error(`Invalid JSON payload in directive: ${a}`)}switch(console.log("operation",e),console.log("📁 Collection:",i),console.log("⚙️ Method:",s),console.log("📦 Payload:",JSON.stringify(l,null,2)),s){case"find":return u=await c.find(l.filter||{},l.options||{}).toArray(),{rows:u,rowCount:u.length};case"findOne":return u=await c.findOne(l.filter||{},l.options||{}),{rows:u?[u]:[],rowCount:u?1:0};case"insertOne":return u=await c.insertOne(l),{rows:[],rowCount:1,insertId:u.insertedId,affectedRows:1};case"insertMany":return u=await c.insertMany(l),{rows:[],rowCount:u.insertedCount,affectedRows:u.insertedCount};case"updateOne":return u=await c.updateOne(l.filter,l.update,l.options||{}),{rows:[],rowCount:u.modifiedCount,affectedRows:u.modifiedCount};case"updateMany":return u=await c.updateMany(l.filter,l.update,l.options||{}),{rows:[],rowCount:u.modifiedCount,affectedRows:u.modifiedCount};case"deleteOne":return u=await c.deleteOne(l.filter),{rows:[],rowCount:u.deletedCount,affectedRows:u.deletedCount};case"deleteMany":return u=await c.deleteMany(l.filter),{rows:[],rowCount:u.deletedCount,affectedRows:u.deletedCount};case"countDocuments":return u=await c.countDocuments(l.filter||{}),{rows:[{count:u}],rowCount:1};case"aggregate":return u=await c.aggregate(l.pipeline,l.options||{}).toArray(),{rows:u,rowCount:u.length};case"createCollection":return u=await this.db.createCollection(i,l),{rows:[],rowCount:1};case"collMod":return u=await this.db.command({collMod:i,...l}),{rows:[],rowCount:1};default:throw new Error(`Unsupported MongoDB operation: ${s}`)}}catch(e){throw new Error(`MongoDB query failed: ${e.message}`)}}async prepare(e){return new r(this,e)}async beginTransaction(){this.inTransaction=!0}async commit(){this.inTransaction=!1}async rollback(){this.inTransaction=!1}async getLastInsertId(){return""}escape(e){return JSON.stringify(e)}getGrammar(){return this.grammar}supportsFeature(e){return["transactions","indexes","aggregation","full_text_search","geospatial","json","arrays","embedded_documents"].includes(e)}buildConnectionUri(){const{host:e="localhost",port:t=27017,username:n,password:o,database:r}=this.config;let i="mongodb://";return n&&o&&(i+=`${encodeURIComponent(n)}:${encodeURIComponent(o)}@`),i+=`${e}:${t}`,r&&(i+=`/${r}`),i}getCollection(e){return this.db.collection(e)}async createIndex(e,t,n){await this.db.collection(e).createIndex(t,n)}async dropIndex(e,t){await this.db.collection(e).dropIndex(t)}}class r{driver;operation;constructor(e,t){this.driver=e,this.operation=t}async execute(e){return this.driver.query(this.operation,e)}async close(){}}export{o as MongoDBDriver};