├── src ├── WhereObj.ts ├── Order.ts ├── JoinClause.ts ├── handles │ ├── group.ts │ ├── order.ts │ ├── field.ts │ ├── join.ts │ ├── set.ts │ ├── returning.ts │ ├── left-join.ts │ ├── cross-join.ts │ ├── outer-join.ts │ ├── right-join.ts │ ├── index.ts │ └── where.ts ├── Resource.ts └── index.ts ├── media └── sqlify.png ├── accessories ├── real-build-log.ts ├── test-log.ts ├── building-log.ts ├── formatting-log.ts ├── linting-log.ts ├── pre-commit-log.ts ├── prepublish-log.ts ├── test-watch-log.ts └── lint-noFix-log.ts ├── .prettierrc ├── .prettierignore ├── typings ├── typings.d.ts └── lme.d.ts ├── .vscode ├── settings.json └── launch.json ├── .editorconfig ├── .yo-rc.json ├── .npmignore ├── gulpfile.ts ├── tsconfig.json ├── .github └── workflows │ ├── Build.yml │ └── Deploy.yml ├── .gitignore ├── LICENSE ├── tslint.json ├── package.json ├── tests └── index.spec.ts └── README.md /src/WhereObj.ts: -------------------------------------------------------------------------------- 1 | export class WhereObj { 2 | [key: string]: any; 3 | } 4 | -------------------------------------------------------------------------------- /media/sqlify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vajahath/sqlify/HEAD/media/sqlify.png -------------------------------------------------------------------------------- /accessories/real-build-log.ts: -------------------------------------------------------------------------------- 1 | import * as lme from 'lme'; 2 | 3 | lme.w('\nCompiling ...\n'); 4 | -------------------------------------------------------------------------------- /accessories/test-log.ts: -------------------------------------------------------------------------------- 1 | import * as lme from 'lme'; 2 | 3 | lme.i('\nExecuting tests ...\n'); 4 | -------------------------------------------------------------------------------- /accessories/building-log.ts: -------------------------------------------------------------------------------- 1 | import * as lme from 'lme'; 2 | 3 | lme.i('\nBuilding package ...\n'); 4 | -------------------------------------------------------------------------------- /accessories/formatting-log.ts: -------------------------------------------------------------------------------- 1 | import * as lme from 'lme'; 2 | 3 | lme.i('\nFormatting codebase ...\n'); 4 | -------------------------------------------------------------------------------- /accessories/linting-log.ts: -------------------------------------------------------------------------------- 1 | import * as lme from 'lme'; 2 | 3 | lme.i('\nPiping through Linter ...\n'); 4 | -------------------------------------------------------------------------------- /accessories/pre-commit-log.ts: -------------------------------------------------------------------------------- 1 | import * as lme from 'lme'; 2 | 3 | lme.i('\nExecuting Pre-commit checks ...\n'); 4 | -------------------------------------------------------------------------------- /accessories/prepublish-log.ts: -------------------------------------------------------------------------------- 1 | import * as lme from 'lme'; 2 | 3 | lme.w('\nExecuting Pre-publish stuffs ...\n'); 4 | -------------------------------------------------------------------------------- /accessories/test-watch-log.ts: -------------------------------------------------------------------------------- 1 | import * as lme from 'lme'; 2 | 3 | lme.i('\nExecuting tests in WATCH mode ...\n'); 4 | -------------------------------------------------------------------------------- /accessories/lint-noFix-log.ts: -------------------------------------------------------------------------------- 1 | import * as lme from 'lme'; 2 | 3 | lme.i('\nChecking for Formatting and Lint errors ...\n'); 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "useTabs": true, 4 | "singleQuote": true, 5 | "tabWidth": 4, 6 | "semi": true 7 | } 8 | -------------------------------------------------------------------------------- /src/Order.ts: -------------------------------------------------------------------------------- 1 | export class Order { 2 | /** order by field */ 3 | public field: string; 4 | /** ascending ? */ 5 | public asc: boolean; 6 | } 7 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | package.json 2 | dist 3 | src/views 4 | src/public 5 | node_modules 6 | *.yaml 7 | *.yml 8 | *.sh 9 | *.html 10 | *.lock 11 | *.ejs 12 | *.*- 13 | *.sql 14 | *.md -------------------------------------------------------------------------------- /typings/typings.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * For including *.json file as 3 | * `import * as from './stuffs.json';` 4 | */ 5 | 6 | declare module '*.json' { 7 | const value: any; 8 | export = value; 9 | } 10 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "tslint.exclude": ["**/node_modules/**", "**/.roughs/**"], 3 | "prettier.eslintIntegration": false, 4 | "cSpell.words": [ 5 | "sqlify", 6 | "squel" 7 | ], 8 | "cSpell.language": "en" 9 | } 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | insert_final_newline = true 5 | tab_width = 4 6 | 7 | [*.js] 8 | indent_style = tab 9 | indent_size = tab 10 | 11 | [*.ts] 12 | indent_style = tab 13 | indent_size = tab 14 | -------------------------------------------------------------------------------- /.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-ts-np": { 3 | "promptValues": { 4 | "githubUsername": "vajahath", 5 | "email": "vajuoff.1@gmail.com", 6 | "twitterUsername": "vajahath7", 7 | "fullName": "Vajahath Ahmed" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/JoinClause.ts: -------------------------------------------------------------------------------- 1 | export class JoinClause extends Array { 2 | [index: number]: string | null; 3 | /** table to join */ 4 | public 0: string; 5 | /** as clause */ 6 | public 1: null | string; 7 | /** condition */ 8 | public 2: string; 9 | } 10 | -------------------------------------------------------------------------------- /src/handles/group.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * implementation of: 3 | * https://hiddentao.com/squel/api.html#select_group 4 | */ 5 | import { Resource } from '../Resource'; 6 | 7 | export const group = (chain: any, resource: Resource['group']) => { 8 | resource.forEach(item => { 9 | chain = chain.group(item); 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /src/handles/order.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * implementation of: 3 | * https://hiddentao.com/squel/api.html#select_order 4 | */ 5 | import { Order } from '../Order'; 6 | 7 | export const order = (chain: any, resource: Order[]) => { 8 | resource.forEach(item => { 9 | chain = chain.order(item.field, item.asc); 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /src/handles/field.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * implementation of: 3 | * https://hiddentao.com/squel/api.html#select_field 4 | */ 5 | 6 | import { Resource } from '../Resource'; 7 | 8 | export const field = (chain: any, resource: Resource['field']) => { 9 | resource.forEach(item => { 10 | chain = chain.field(item); 11 | }); 12 | }; 13 | -------------------------------------------------------------------------------- /src/handles/join.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * implementing JOIN 3 | * https://hiddentao.com/squel/api.html#select_join 4 | */ 5 | import { JoinClause } from '../JoinClause'; 6 | 7 | export const join = (chain: any, resource: JoinClause[]) => { 8 | resource.forEach(item => { 9 | chain = chain.join(item[0], item[1], item[2]); 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /src/handles/set.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * implementing SET (INSERT) 3 | * https://hiddentao.com/squel/api.html#insert_set 4 | */ 5 | import { WhereObj } from '../WhereObj'; 6 | 7 | export const set = (chain: any, resource: WhereObj) => { 8 | Object.keys(resource).forEach(item => { 9 | chain = chain.set(item, resource[item]); 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /src/handles/returning.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * implementing RETURN (INSERT) 3 | * https://hiddentao.com/squel/api.html#insert_return 4 | */ 5 | import { Resource } from '../Resource'; 6 | 7 | export const returning = (chain: any, resource: Resource['returning']) => { 8 | resource.forEach(item => { 9 | chain = chain.returning(item); 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | accessories/ 3 | *.map 4 | mocha-insights/ 5 | credentials/ 6 | media/ 7 | node_modules/ 8 | src/ 9 | tests/ 10 | ./typings/ 11 | .editorconfig 12 | .gitignore 13 | .eslintignore 14 | .eslintrc.yml 15 | .npmignore 16 | .prettierignore 17 | .prettierrc 18 | .travis.yml 19 | .yo-rc.json 20 | tsconfig.json 21 | tslint.json 22 | gulpfile.ts -------------------------------------------------------------------------------- /src/handles/left-join.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * implementing LEFT JOIN 3 | * https://hiddentao.com/squel/api.html#select_left_join 4 | */ 5 | import { JoinClause } from '../JoinClause'; 6 | 7 | export const left_join = (chain: any, resource: JoinClause[]) => { 8 | resource.forEach(item => { 9 | chain = chain.left_join(item[0], item[1], item[2]); 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /src/handles/cross-join.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * implementing CROSS JOIN 3 | * https://hiddentao.com/squel/api.html#select_cross_join 4 | */ 5 | import { JoinClause } from '../JoinClause'; 6 | 7 | export const cross_join = (chain: any, resource: JoinClause[]) => { 8 | resource.forEach(item => { 9 | chain = chain.cross_join(item[0], item[1], item[2]); 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /src/handles/outer-join.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * implementing OUTER JOIN 3 | * https://hiddentao.com/squel/api.html#select_outer_join 4 | */ 5 | import { JoinClause } from '../JoinClause'; 6 | 7 | export const outer_join = (chain: any, resource: JoinClause[]) => { 8 | resource.forEach(item => { 9 | chain = chain.outer_join(item[0], item[1], item[2]); 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /src/handles/right-join.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * implementing RIGHT JOIN 3 | * https://hiddentao.com/squel/api.html#select_left_join 4 | */ 5 | import { JoinClause } from '../JoinClause'; 6 | 7 | export const right_join = (chain: any, resource: JoinClause[]) => { 8 | resource.forEach(item => { 9 | chain = chain.right_join(item[0], item[1], item[2]); 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /gulpfile.ts: -------------------------------------------------------------------------------- 1 | import * as del from 'del'; 2 | import * as gulp from 'gulp'; 3 | 4 | async function cleanBuild() { 5 | return await del(['dist/**/*', 'dist/**/.*']); 6 | } 7 | 8 | function copyAssets() { 9 | return gulp.src(['src/**/*', '!src/**/*.ts']).pipe(gulp.dest('dist/')); 10 | } 11 | 12 | exports['clean-build'] = cleanBuild; 13 | exports['copy-assets'] = copyAssets; 14 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es5", 5 | "noImplicitAny": true, 6 | "moduleResolution": "node", 7 | "sourceMap": true, 8 | "outDir": "dist", 9 | "baseUrl": ".", 10 | "declaration": true, 11 | "declarationDir": "./dist/typings", 12 | "paths": { 13 | "*": ["node_modules/*", "typings/*"] 14 | } 15 | }, 16 | "include": ["src/**/*", "typings/*"] 17 | } 18 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible Node.js debug attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [{ 7 | "type": "node", 8 | "request": "launch", 9 | "name": "Debug", 10 | "program": "${workspaceRoot}/dist/index.js", 11 | "smartStep": true, 12 | "outFiles": [ 13 | "../dist/**/*.js" 14 | ], 15 | "protocol": "inspector" 16 | }] 17 | } 18 | -------------------------------------------------------------------------------- /src/Resource.ts: -------------------------------------------------------------------------------- 1 | // tslint:disable:variable-name 2 | 3 | import { JoinClause } from './JoinClause'; 4 | import { Order } from './Order'; 5 | import { WhereObj } from './WhereObj'; 6 | 7 | export class Resource { 8 | public field?: string[]; 9 | public where?: WhereObj; 10 | public set?: WhereObj; 11 | public join?: JoinClause[]; 12 | public left_join?: JoinClause[]; 13 | public right_join?: JoinClause[]; 14 | public outer_join?: JoinClause[]; 15 | public cross_join?: JoinClause[]; 16 | public returning?: string[]; 17 | public group?: string[]; 18 | public order?: Order[]; 19 | } 20 | -------------------------------------------------------------------------------- /.github/workflows/Build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | Build: 7 | strategy: 8 | matrix: 9 | os: [ubuntu-latest] 10 | node: ['8', '10', '12', '13'] 11 | runs-on: ${{ matrix.os }} 12 | name: build and test (${{ matrix.os }}|node-${{ matrix.node }}) 13 | 14 | steps: 15 | - uses: actions/checkout@v1 16 | - uses: actions/setup-node@v1.2.0 17 | with: 18 | node-version: ${{ matrix.node }} 19 | - run: node --version 20 | - run: npm ci 21 | - run: npm run lint 22 | - run: npm run build 23 | - run: npm test 24 | -------------------------------------------------------------------------------- /src/handles/index.ts: -------------------------------------------------------------------------------- 1 | import { cross_join } from './cross-join'; 2 | import { field } from './field'; 3 | import { group } from './group'; 4 | import { join } from './join'; 5 | import { left_join } from './left-join'; 6 | import { order } from './order'; 7 | import { outer_join } from './outer-join'; 8 | import { returning } from './returning'; 9 | import { right_join } from './right-join'; 10 | import { set } from './set'; 11 | import { where } from './where'; 12 | 13 | export { 14 | group, 15 | field, 16 | where, 17 | set, 18 | join, 19 | left_join, 20 | right_join, 21 | outer_join, 22 | cross_join, 23 | returning, 24 | order, 25 | }; 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | mocha-insights/ 2 | credentials/ 3 | dist/ 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | 15 | # Directory for instrumented libs generated by jscoverage/JSCover 16 | lib-cov 17 | 18 | # Coverage directory used by tools like istanbul 19 | coverage 20 | 21 | # nyc test coverage 22 | .nyc_output 23 | 24 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 25 | .grunt 26 | 27 | # node-waf configuration 28 | .lock-wscript 29 | 30 | # Compiled binary addons (http://nodejs.org/api/addons.html) 31 | build/Release 32 | 33 | # Dependency directories 34 | node_modules 35 | jspm_packages 36 | 37 | # Optional npm cache directory 38 | .npm 39 | 40 | # Optional REPL history 41 | .node_repl_history -------------------------------------------------------------------------------- /src/handles/where.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * implementing: WHERE 3 | * https://hiddentao.com/squel/api.html#select_where 4 | */ 5 | 6 | import { WhereObj } from '../WhereObj'; 7 | 8 | let appendingValue = ''; 9 | 10 | export const where = (chain: any, resource: WhereObj) => { 11 | Object.keys(resource).forEach(item => { 12 | appendingValue = resource[item]; 13 | // modify appendingValue to include 's if necessary 14 | switch (typeof resource[item]) { 15 | case 'number': 16 | case 'boolean': 17 | break; 18 | case 'string': 19 | appendingValue = `'${appendingValue}'`; 20 | break; 21 | default: 22 | throw new Error( 23 | 'SQLIFY ERR: a type other than "string", "number", "boolean" encountered', 24 | ); 25 | } 26 | chain = chain.where(item + '=' + appendingValue); 27 | }); 28 | }; 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Vajahath Ahmed 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/Deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy 2 | 3 | on: 4 | release: 5 | types: published 6 | 7 | jobs: 8 | Deploy-To-NPM: 9 | runs-on: ubuntu-latest 10 | name: Deploy to NPM 11 | 12 | steps: 13 | - uses: actions/checkout@v1 14 | - uses: actions/setup-node@v1.2.0 15 | with: 16 | node-version: '12' 17 | registry-url: 'https://registry.npmjs.org' 18 | - run: node --version 19 | - run: npm ci 20 | - run: npm run lint 21 | - run: ls && npm publish --access=public 22 | env: 23 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 24 | 25 | Deploy-To-GitHub-Package-Registry: 26 | runs-on: ubuntu-latest 27 | name: Deploy to GPR 28 | steps: 29 | - uses: actions/checkout@v1 30 | - uses: actions/setup-node@v1.2.0 31 | with: 32 | node-version: '12' 33 | registry-url: 'https://npm.pkg.github.com' 34 | - run: node --version 35 | - run: npm ci 36 | - run: npm run lint 37 | - run: npm run rescope vajahath 38 | - run: ls && npm publish 39 | env: 40 | NODE_AUTH_TOKEN: ${{ secrets.GH_TOKEN }} 41 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": ["tslint:recommended"], 4 | "jsRules": {}, 5 | "linterOptions": { 6 | "exclude": [] 7 | }, 8 | "rules": { 9 | "arrow-parens": false, 10 | "class-name": true, 11 | "comment-format": [true, "check-space"], 12 | "eofline": true, 13 | "forin": true, 14 | "indent": [true, "tabs"], 15 | "jsdoc-format": true, 16 | "label-position": true, 17 | "no-arg": true, 18 | "no-conditional-assignment": true, 19 | "no-construct": true, 20 | "no-debugger": true, 21 | "no-duplicate-variable": true, 22 | "no-empty": true, 23 | "no-inferrable-types": true, 24 | "no-internal-module": true, 25 | "no-shadowed-variable": true, 26 | "no-switch-case-fall-through": true, 27 | "no-trailing-whitespace": true, 28 | "no-unused-expression": true, 29 | "no-unused-variable": true, 30 | "no-use-before-declare": true, 31 | "no-var-keyword": true, 32 | "quotemark": [true, "single"], 33 | "radix": true, 34 | "semicolon": [true, "always"], 35 | "switch-default": true, 36 | "triple-equals": [true, "allow-null-check"], 37 | "variable-name": [ 38 | true, 39 | "check-format", 40 | "ban-keywords", 41 | "allow-snake-case" 42 | ], 43 | "prefer-const": true, 44 | "object-literal-sort-keys": false 45 | }, 46 | "rulesDirectory": [] 47 | } 48 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * `chain` is the instance of npm squel module 3 | * `resource` includes the data to build the query 4 | */ 5 | 6 | import * as squelLib from 'squel'; 7 | 8 | import * as handles from './handles'; 9 | import { Resource } from './Resource'; 10 | 11 | const squel = squelLib.useFlavour('postgres'); 12 | 13 | export const sqlify = (chain: any, resource: Resource) => { 14 | // iterate through each properties of `resource` 15 | Object.keys(resource).forEach(key => { 16 | switch (key) { 17 | case 'field': 18 | handles.field(chain, resource[key]); 19 | break; 20 | 21 | case 'where': 22 | handles.where(chain, resource[key]); 23 | break; 24 | 25 | case 'set': 26 | handles.set(chain, resource[key]); 27 | break; 28 | 29 | case 'join': 30 | handles.join(chain, resource[key]); 31 | break; 32 | 33 | case 'left_join': 34 | handles.left_join(chain, resource[key]); 35 | break; 36 | 37 | case 'right_join': 38 | handles.right_join(chain, resource[key]); 39 | break; 40 | 41 | case 'outer_join': 42 | handles.outer_join(chain, resource[key]); 43 | break; 44 | 45 | case 'cross_join': 46 | handles.cross_join(chain, resource[key]); 47 | break; 48 | 49 | case 'returning': 50 | handles.returning(chain, resource[key]); 51 | break; 52 | 53 | case 'group': 54 | handles.group(chain, resource[key]); 55 | break; 56 | 57 | case 'order': 58 | handles.order(chain, resource[key]); 59 | break; 60 | 61 | default: 62 | throw new Error( 63 | 'SQLIFY ERR: method ' + 64 | key + 65 | ' is not implemented > please contribute this method > its simple :)', 66 | ); 67 | // break; 68 | } 69 | }); 70 | }; 71 | 72 | export { squel, Resource }; 73 | -------------------------------------------------------------------------------- /typings/lme.d.ts: -------------------------------------------------------------------------------- 1 | /** Declaration file generated by dts-gen */ 2 | 3 | export function d(...args: any[]): void; 4 | 5 | export function dline(char?: any, length?: any): void; 6 | 7 | export function e(...args: any[]): void; 8 | 9 | export function eline(char?: any, length?: any): void; 10 | 11 | export function h(...args: any[]): void; 12 | 13 | export function hline(char?: any, length?: any): void; 14 | 15 | export function i(...args: any[]): void; 16 | 17 | export function iline(char?: any, length?: any): void; 18 | 19 | export function line(char?: any, length?: any): void; 20 | 21 | export function s(...args: any[]): void; 22 | 23 | export function sline(char: any, length: any): void; 24 | 25 | export function t(...args: any[]): void; 26 | 27 | export function tline(char?: any, length?: any): void; 28 | 29 | export function w(...args: any[]): void; 30 | 31 | export function wline(char?: any, length?: any): void; 32 | 33 | export namespace d { 34 | const prototype: {}; 35 | } 36 | 37 | export namespace dline { 38 | const prototype: {}; 39 | } 40 | 41 | export namespace e { 42 | const prototype: {}; 43 | } 44 | 45 | export namespace eline { 46 | const prototype: {}; 47 | } 48 | 49 | export namespace h { 50 | const prototype: {}; 51 | } 52 | 53 | export namespace hline { 54 | const prototype: {}; 55 | } 56 | 57 | export namespace i { 58 | const prototype: {}; 59 | } 60 | 61 | export namespace iline { 62 | const prototype: {}; 63 | } 64 | 65 | export namespace line { 66 | const prototype: {}; 67 | } 68 | 69 | export namespace s { 70 | const prototype: {}; 71 | } 72 | 73 | export namespace sline { 74 | const prototype: {}; 75 | } 76 | 77 | export namespace t { 78 | const prototype: {}; 79 | } 80 | 81 | export namespace tline { 82 | const prototype: {}; 83 | } 84 | 85 | export namespace w { 86 | const prototype: {}; 87 | } 88 | 89 | export namespace wline { 90 | const prototype: {}; 91 | } 92 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sqlify", 3 | "version": "2.5.2", 4 | "description": "Yet another SQL query builder for Node.js", 5 | "main": "dist/index.js", 6 | "typings": "dist/typings/index.d.ts", 7 | "scripts": { 8 | "prepublishOnly": "ts-node accessories/prepublish-log.ts && npm run build", 9 | "test": "ts-node accessories/test-log.ts && cross-env NODE_ENV=test mocha tests/*.ts --require ts-node/register --recursive --reporter spec", 10 | "test-watch": "ts-node accessories/test-watch-log.ts && cross-env NODE_ENV=test mocha tests/ --compilers ts:ts-node/register,tsx:ts-node/register --recursive --reporter spec --watch", 11 | "build": "ts-node accessories/building-log.ts && npm run clean-build && npm run lint && ts-node accessories/real-build-log.ts && npm run compile && npm run copy-assets", 12 | "lint-noFix": "ts-node accessories/lint-noFix-log.ts && npm run prettier-noFix && npm run tslint-noFix", 13 | "lint": "ts-node accessories/formatting-log.ts && npm run prettier && ts-node accessories/linting-log.ts && npm run tslint", 14 | "test-in-gitlab-runner": "ts-node accessories/test-log.ts && cross-env NODE_APP_INSTANCE=test cross-env NODE_CONFIG_DIR=./src/config jest --forceExit", 15 | "preCommit-msg": "ts-node accessories/pre-commit-log.ts", 16 | "copy-assets": "gulp copy-assets", 17 | "clean-build": "gulp clean-build", 18 | "prettier-noFix": "prettier \"{src/**/*.*,typings/**/*.*,tests/**/*.*}\"", 19 | "prettier": "prettier \"{src/**/*.*,typings/**/*.*,tests/**/*.*}\" --write", 20 | "tslint-noFix": "tslint -c tslint.json -p tsconfig.json -t stylish 'src/**/*.ts'", 21 | "tslint": "tslint -c tslint.json -p tsconfig.json -t stylish --fix 'src/**/*.ts'", 22 | "compile": "tsc", 23 | "rescope": "npm-scope-prefixer -s" 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "git+https://github.com/vajahath/sqlify.git" 28 | }, 29 | "author": "Vajahath Ahmed (http://twitter.com/vajahath7)", 30 | "license": "MIT", 31 | "bugs": { 32 | "url": "https://github.com/vajahath/sqlify/issues" 33 | }, 34 | "homepage": "https://github.com/vajahath/sqlify#readme", 35 | "dependencies": { 36 | "squel": "^5.12.0" 37 | }, 38 | "contributors": [ 39 | "Lakshmipriya Mukundan (https://github.com/lakshmipriyamukundan)" 40 | ], 41 | "devDependencies": { 42 | "@types/chai": "^4.2.7", 43 | "@types/del": "^3.0.0", 44 | "@types/gulp": "^4.0.4", 45 | "@types/mocha": "^2.2.41", 46 | "@types/node": "^8.0.5", 47 | "@vaju/npm-scope-prefixer": "^1.2.0", 48 | "chai": "^4.1.0", 49 | "concurrently": "^3.5.0", 50 | "cross-env": "^5.0.1", 51 | "del": "^3.0.0", 52 | "gulp": "^4.0.2", 53 | "gulp-cli": "^2.2.0", 54 | "lme": "^1.5.3", 55 | "mocha": "^7.0.0", 56 | "pre-commit": "^1.2.2", 57 | "prettier": "^1.5.3", 58 | "ts-node": "^3.3.0", 59 | "tslint": "^5.5.0", 60 | "typescript": "^3.7.5" 61 | }, 62 | "pre-commit": [ 63 | "preCommit-msg", 64 | "lint-noFix" 65 | ], 66 | "keywords": [ 67 | "sql", 68 | "squel", 69 | "postgres", 70 | "mysql", 71 | "database", 72 | "query" 73 | ], 74 | "greenkeeper": { 75 | "ignore": [ 76 | "@types/chai", 77 | "@types/del", 78 | "@types/gulp", 79 | "@types/mocha", 80 | "@types/node", 81 | "chai", 82 | "concurrently", 83 | "cross-env", 84 | "del", 85 | "gulp", 86 | "gulp-cli", 87 | "lme", 88 | "mocha", 89 | "pre-commit", 90 | "prettier", 91 | "ts-node", 92 | "tslint", 93 | "typescript" 94 | ] 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /tests/index.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable: no-unused-expression arrow-parens */ 2 | 3 | import { expect } from 'chai'; 4 | import { Resource, sqlify as makeQuery, squel as sql } from './../src'; 5 | 6 | describe('Testing sqlify For TS', () => { 7 | it('should make good query (type 2: INSERT)', done => { 8 | const resource: Resource = { 9 | set: { 10 | age: 44, 11 | girl: true, 12 | name: 'Divya', 13 | }, 14 | }; 15 | const chain = sql.insert().into('users'); 16 | makeQuery(chain, resource); 17 | 18 | const query = chain.toString(); 19 | expect(query).to.equal( 20 | `INSERT INTO users (age, girl, name) VALUES (44, TRUE, 'Divya')`, 21 | ); 22 | done(); 23 | }); 24 | 25 | describe('testing some actual scenarios >', () => { 26 | it('case 1 (SELECT field FROM table JOIN JOIN JOIN WHERE cond.)', done => { 27 | const resource: Resource = { 28 | field: [ 29 | 'service_types.service_title', 30 | 'service_pricing.service_pricing_title', 31 | 'service_pricing_sub.service_pricing_sub_title', 32 | 'service_pricing_cost.service_pricing_cost', 33 | 'service_pricing_cost.service_pricing_currency', 34 | ], 35 | join: [ 36 | [ 37 | 'service_pricing', 38 | null, 39 | 'service_types.service_id = service_pricing.service_type', 40 | ], 41 | [ 42 | 'service_pricing_sub', 43 | null, 44 | 'service_pricing.service_pricing_id = service_pricing_sub.service_pricing_id', 45 | ], 46 | [ 47 | 'service_pricing_cost', 48 | null, 49 | 'service_pricing_sub.service_pricing_sub_id = service_pricing_cost.service_pricing_sub_id', 50 | ], 51 | ], 52 | where: { 53 | 'service_types.service_id': 'something', 54 | 'service_pricing_cost.service_pricing_currency': 55 | 'something else', 56 | }, 57 | }; 58 | const chain = sql.select().from('users'); 59 | makeQuery(chain, resource); 60 | 61 | const query = chain.toString(); 62 | expect(query).to.equal( 63 | // tslint:disable-next-line 64 | `SELECT service_types.service_title, service_pricing.service_pricing_title, service_pricing_sub.service_pricing_sub_title, service_pricing_cost.service_pricing_cost, service_pricing_cost.service_pricing_currency FROM users INNER JOIN service_pricing ON (service_types.service_id = service_pricing.service_type) INNER JOIN service_pricing_sub ON (service_pricing.service_pricing_id = service_pricing_sub.service_pricing_id) INNER JOIN service_pricing_cost ON (service_pricing_sub.service_pricing_sub_id = service_pricing_cost.service_pricing_sub_id) WHERE (service_types.service_id='something') AND (service_pricing_cost.service_pricing_currency='something else')`, 65 | ); 66 | done(); 67 | }); 68 | it('case 2 (SELECT field FROM table WHERE cond.)', done => { 69 | const resource: Resource = { 70 | field: ['fabric_id', 'fabric_title'], 71 | where: { 72 | 'fabrics.fabric_type': 'something', 73 | }, 74 | }; 75 | const chain = sql.select().from('fabrics'); 76 | makeQuery(chain, resource); 77 | 78 | const query = chain.toString(); 79 | expect(query).to.equal( 80 | `SELECT fabric_id, fabric_title FROM fabrics WHERE (fabrics.fabric_type='something')`, 81 | ); 82 | done(); 83 | }); 84 | // tslint:disable-next-line 85 | it(`case 3 (INSERT INTO embroidery_formats (format_title,format_ext,service_type VALUES('1','2','3') RETURNING format_id)`, done => { 86 | const resource: Resource = { 87 | set: { 88 | format_title: 'abc', 89 | format_ext: 'aa', 90 | service_type: 1, 91 | }, 92 | returning: ['format_id'], 93 | }; 94 | const chain = sql.insert().into('embroidery_formats'); 95 | makeQuery(chain, resource); 96 | 97 | const query = chain.toString(); 98 | expect(query).to.equal( 99 | // tslint:disable-next-line 100 | `INSERT INTO embroidery_formats (format_title, format_ext, service_type) VALUES ('abc', 'aa', 1) RETURNING format_id`, 101 | ); 102 | done(); 103 | }); 104 | 105 | it('case 4 GROUP BY: (SELECT fabric_id, fabric_title FROM fabrics GROUP BY fabric_id)', done => { 106 | const resource: Resource = { 107 | field: ['fabric_id', 'fabric_title'], 108 | group: ['fabric_id'], 109 | }; 110 | const chain = sql.select().from('fabrics'); 111 | makeQuery(chain, resource); 112 | 113 | const query = chain.toString(); 114 | // lme.w(query); 115 | expect(query).to.equal( 116 | 'SELECT fabric_id, fabric_title FROM fabrics GROUP BY fabric_id', 117 | ); 118 | done(); 119 | }); 120 | 121 | // tslint:disable-next-line 122 | it(`case 5 GROUP BY: (INSERT INTO embroidery_formats (format_title,format_ext,service_type VALUES('1','2','3') RETURNING format_id)`, done => { 123 | const resource: Resource = { 124 | field: ['name', 'age'], 125 | group: ['name', 'age'], 126 | }; 127 | const chain = sql.select().from('fabrics'); 128 | makeQuery(chain, resource); 129 | 130 | const query = chain.toString(); 131 | // lme.w(query); 132 | expect(query).to.equal( 133 | 'SELECT name, age FROM fabrics GROUP BY name, age', 134 | ); 135 | done(); 136 | }); 137 | 138 | it('case 6 ORDER BY: (SELECT id FROM students ORDER BY id ASC, name ASC, age ASC)', done => { 139 | const resource: Resource = { 140 | field: ['id'], 141 | order: [ 142 | { 143 | field: 'id', 144 | asc: true, 145 | }, 146 | { 147 | field: 'name', 148 | asc: false, 149 | }, 150 | { 151 | field: 'age', 152 | asc: true, 153 | }, 154 | ], 155 | }; 156 | const chain = sql.select().from('students'); 157 | makeQuery(chain, resource); 158 | 159 | const query = chain.toString(); 160 | // lme.w(query); 161 | expect(query).to.equal( 162 | 'SELECT id FROM students ORDER BY id ASC, name DESC, age ASC', 163 | ); 164 | done(); 165 | }); 166 | 167 | it('case 7 ERR handling', done => { 168 | const resource = { 169 | field: ['id'], 170 | order: [ 171 | { 172 | asc: true, 173 | field: 'id', 174 | }, 175 | { 176 | field: 'name', 177 | asc: false, 178 | }, 179 | { 180 | field: 'age', 181 | asc: true, 182 | }, 183 | ], 184 | blabla: ['he', 'he'], 185 | }; 186 | const chain = sql.select().from('students'); 187 | // makeQuery(chain, resource); 188 | // lme.w(query); 189 | expect(() => { 190 | makeQuery(chain, resource); 191 | }).to.throw(Error); 192 | done(); 193 | }); 194 | }); 195 | }); 196 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sqlify 2 | 3 | Yet another SQL query builder. 4 | 5 | [![npm](https://img.shields.io/npm/v/sqlify.svg)](https://www.npmjs.com/package/sqlify) 6 | ![Build Status](https://github.com/vajahath/sqlify/workflows/Build/badge.svg) 7 | [![T](https://img.shields.io/badge/TypeScript%20Ready-.d.ts%20included-blue.svg)]() 8 | [![npm](https://img.shields.io/npm/dt/sqlify.svg)](https://www.npmjs.com/package/sqlify) 9 | [![Greenkeeper badge](https://badges.greenkeeper.io/vajahath/sqlify.svg)](https://greenkeeper.io/) 10 | 11 | > There are many sql query builders out there. But this one makes more sense to me :wink:. 12 | 13 | ![](media/sqlify.png) 14 | 15 | ## Install 16 | 17 | ```bash 18 | npm install --save sqlify 19 | ``` 20 | 21 | ## Why 22 | 23 | * This package is a wrapper around [squel](https://hiddentao.com/squel) module to make it more friendly. (Check that package to know its maintenance status) 24 | * Helps you to build dynamic sql queries. 25 | * **Example use case:** suppose, you are getting a POST request to insert some data to your SQL database. 26 | You'll get the data in `req.body` as `{name: "Swat", age: 22, address: "ND"}`. 27 | Now make the query like: 28 | 29 | ```js 30 | const resource = { 31 | set: req.body 32 | where: { 33 | id: 5 34 | } 35 | } 36 | 37 | sqlify(chain, resource); // done! 38 | ``` 39 | 40 | > Warning ⚠️: Do not ever pass queries generated on the client side to your web server for execution. The above example is only a use case. Do NOT copy paste as such. 41 | 42 | ## Examples 43 | 44 | #### SELECT 45 | 46 | ```js 47 | const { squel, sqlify } = require('sqlify'); 48 | 49 | const resource = { 50 | field: ['name', 'age', 'address'], 51 | where: { 52 | name: 'Swat', 53 | age: 22, 54 | }, 55 | }; 56 | 57 | const chain = squel.select().from('users'); 58 | 59 | sqlify(chain, resource); 60 | 61 | chain.toString(); 62 | // => SELECT name, age, address FROM users WHERE (name=Swat) AND (age=22) 63 | ``` 64 | 65 | ##### Starter Guide For TypeScript 66 | 67 | ```ts 68 | import { squel, sqlify, Resource } from 'sqlify' 69 | 70 | // `Resource` is type. 71 | const resource :Resource = { 72 | field: ['name', 'age', 'address'], 73 | where: { 74 | name: 'Swat', 75 | age: 22, 76 | }, 77 | }; 78 | 79 | // ... 80 | ``` 81 | 82 | #### SELECT with a simple JOIN 83 | 84 | ```js 85 | // ... 86 | 87 | const resource = { 88 | field: ['user.*', 'hobbies.hobby', 'colors.favorite'], 89 | where: { 90 | name: 'Swat', 91 | age: 22, 92 | }, 93 | join: [ 94 | ['hobbies', null, 'hobbies.id = user.id'], 95 | ['colors', null, 'colors.user_id = user.id'], 96 | ]; 97 | } 98 | const chain = squel.select().from('Hero'); 99 | 100 | sqlify(chain, resource); 101 | 102 | chain.toString(); 103 | 104 | /* 105 | SELECT 106 | user.*, 107 | hobbies.hobby, 108 | colors.favorite 109 | FROM Hero 110 | INNER JOIN hobbies 111 | ON (hobbies.id = user.id) 112 | INNER JOIN colors 113 | ON (colors.user_id = user.id) 114 | WHERE (name='Swat') AND (age=22) 115 | */ 116 | ``` 117 | 118 | Read the JOIN section of [squel docs](https://hiddentao.com/squel/#select) for more. 119 | 120 | #### INSERT 121 | 122 | ```js 123 | const { squel, sqlify } = require('sqlify'); 124 | 125 | const resource = { 126 | set: { 127 | name: 'Swat', 128 | age: 22, 129 | }, 130 | }; 131 | 132 | const chain = sql.insert().into('users'); 133 | sqlify(chain, resource); 134 | 135 | chain.toString(); 136 | // => INSERT INTO users (name, age) VALUES ('Swat', 22) 137 | ``` 138 | 139 | ## How? 140 | 141 | `sqlify` exposes a **function**, **module** ([squel](https://www.npmjs.com/package/squel)) and a `Resource` type (for using with TypeScript). 142 | 143 | The function receives 2 arguments. They are: 144 | 145 | * `chain` 146 | * `resource` 147 | 148 | #### Step 1: Require the package 149 | 150 | ```js 151 | const { squel, sqlify } = require('sqlify'); 152 | ``` 153 | 154 | #### Step 2: Initialize `chain` and `resource` 155 | 156 | `chain` is an instance of [squel](https://www.npmjs.com/package/squel). 157 | For example, 158 | 159 | ```js 160 | // ... 161 | 162 | const chain = squel.select().from('users'); 163 | 164 | // ... 165 | ``` 166 | 167 | `resource` is an object which contains the data to build the query. 168 | 169 | Example: 170 | 171 | ```js 172 | // ... 173 | 174 | const resource = { 175 | field: ['name', 'age', 'address'], 176 | where: { 177 | name: 'Swa', 178 | age: 22 179 | } 180 | }; 181 | 182 | // ... 183 | ``` 184 | 185 | Where, the properties of `resource` object (in the above case, `field` and `where`) are taken from the chain function names of the [squel](https://www.npmjs.com/package/squel). There are more. Refer their docs and use them accordingly. 186 | 187 | > When used with TypeScript, you should mark type of `resource` with the `import`ed `Resource` class. 188 | > Like `const resource:Resource = {...}`. 189 | 190 | #### Step 3: Sqlify 191 | 192 | ```js 193 | // ... 194 | 195 | sqlify(chain, resource); 196 | 197 | // ... 198 | ``` 199 | 200 | `sqlify` function wont return anything. It simply do things in in-place. 201 | 202 | #### Step 4: Watch stuff 203 | 204 | ```js 205 | // ... 206 | 207 | // parse query 208 | const query = chain.toString(); 209 | // see it 210 | console.log(query); 211 | // => SELECT name, age, address FROM users WHERE (name='Swa') AND (age=22) 212 | 213 | // ... 214 | ``` 215 | 216 | _Unclear about something here? Feel free to rise an issue.._ 217 | 218 | ## Also, 219 | 220 | Since `sqlify` takes in and out chain functions, you can modify it **even after** `sqlify`ing it. 221 | 222 | Example: 223 | 224 | ```js 225 | // ... 226 | 227 | const chain = squel.select().from('users'); 228 | 229 | sqlify(chain, resource); 230 | 231 | chain.limit(10); 232 | 233 | chain.toString(); // Voila! 234 | ``` 235 | 236 | ### Supported Squel Functions 237 | 238 | The following fields can be used inside the `resource` object. Logic behind the usage of these functions can be found at [squel docs](https://hiddentao.com/squel). 239 | 240 | | | | | | | 241 | | ---------- | ---------- | ---- | --------- | ---------- | 242 | | `cross_join` | `field` | `join` | `left_join` | `outer_join` | 243 | | `returning` | `right_join` | `set` | `where` | `group` | 244 | | `order` | | | | | 245 | | | | | | | 246 | 247 | ## Contributors 248 | 249 | * [Lakshmipriya](https://github.com/lakshmipriyamukundan) 250 | 251 | ## v1 to v2 migration guide 252 | 253 | * **change the way you `require` the package:** 254 | * in v1, you required `sqlify` along with `squel` as: 255 | ```js 256 | const sqlify = require('sqlify'); 257 | const squel = require('squel'); 258 | // ... 259 | ``` 260 | * in v2 you've to change that code into: 261 | ```js 262 | const { sqlify, squel } = require('sqlify'); 263 | // ... 264 | ``` 265 | 266 | * **change in function name:** change `fields:[]` to `field:[]` in the `resource` object. 267 |

*Oh yes! it's that simple.* 268 |

269 | 270 | ## Change log 271 | 272 | * v2.5.0, v2.5.1, v2.5.2 273 | * Security Update 274 | * v2.4.0 275 | * TypeScript support and definitions 276 | * Better docs 277 | * v2.3.1 278 | * enabling Greeenkeeper, better docs 279 | * v2.3.0 280 | * adds better error handling: (if an unsupported method is used, sqlify throws an err) 281 | * v2.2.0 282 | * adds `order` function from [squel-order](https://hiddentao.com/squel/api.html#select_order) 283 | * better docs 284 | * v2.1.1 285 | * adds `group` function from [squel-group](https://hiddentao.com/squel/api.html#select_group) 286 | * better docs 287 | * v2.0.0 288 | * fixing [#5](https://github.com/vajahath/sqlify/issues/5) and [#2](https://github.com/vajahath/sqlify/issues/2). 289 | * more squel functions 290 | * v1.0.4 291 | * bug fix with 's in select queries 292 | * v1.0.1, 1.0.2, 1.0.3 293 | * bug fix (in `package.json`) 294 | * better docs 295 | * v1.0.0 296 | * initial release 297 | 298 | ## Licence 299 | 300 | MIT © [Vajahath Ahmed](https://twitter.com/vajahath7) 301 | 302 | [badge_paypal_donate]: https://cdn.rawgit.com/vajahath/cloud-codes/a01f087f/badges/paypal_donate.svg 303 | [paypal-donations]: https://paypal.me/vajahath 304 | --------------------------------------------------------------------------------