diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..5008ddfc Binary files /dev/null and b/.DS_Store differ diff --git a/.github/semantic.yml b/.github/semantic.yml new file mode 100644 index 00000000..fd160e51 --- /dev/null +++ b/.github/semantic.yml @@ -0,0 +1 @@ +titleOnly: true diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml new file mode 100644 index 00000000..057fc7a8 --- /dev/null +++ b/.github/workflows/nodejs.yml @@ -0,0 +1,26 @@ +name: CI/CD + +on: [push, pull_request] + +jobs: + build: + name: 'Build & Test' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: '20' + - name: npm install --global rollup + run: npm install --global rollup + env: + CI: true + - name: npm install + run: npm install + env: + CI: true + - name: npm run test + run: npm run test + env: + CI: true diff --git a/.gitignore b/.gitignore index 9cf6fffa..bd8b926e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ node_modules/ +dist/ +spec/ .idea diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index a8e1e5f9..00000000 --- a/.jshintrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "node": true, - "globals": { - "describe" : true, - "it" : true, - "Node" : true, - "suite" : true, - "test" : true - } -} diff --git a/.npmignore b/.npmignore new file mode 100644 index 00000000..7d28380f --- /dev/null +++ b/.npmignore @@ -0,0 +1,15 @@ +.github/ +.vscode/ +@types/ +lib/ +node_modules/ +spec/ +test/ +.eslintrc.json +.gitignore +.prettierrc +.travis.yml +runtests.js +rollup.config.js +tsconfig.build.json +tsconfig.json \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..cc96c5a8 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,8 @@ +{ + "$schema": "http://json.schemastore.org/prettierrc", + "singleQuote": true, + "arrowParens": "always", + "bracketSpacing": true, + "tabWidth": 4, + "printWidth": 140 +} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f04dabe6..00000000 --- a/.travis.yml +++ /dev/null @@ -1,6 +0,0 @@ -language: node_js -node_js: - - "5.0" - - "4.2" - - "0.10" - - "0.11" diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..55712c19 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "typescript.tsdk": "node_modules/typescript/lib" +} \ No newline at end of file diff --git a/@types/sliced/index.d.ts b/@types/sliced/index.d.ts new file mode 100644 index 00000000..d7668402 --- /dev/null +++ b/@types/sliced/index.d.ts @@ -0,0 +1,12 @@ +declare module 'sliced' { + /** + * Returns a section of an array. + * @param args something with a length. + * @param start The beginning of the specified portion of the array. + * @param end The end of the specified portion of the array. + */ + function sliced(args: T[], start?: number, end?: number): T[]; + function sliced(args: IArguments, start?: number, end?: number): any[]; + + export = sliced; +} diff --git a/LICENSE b/LICENSE index 722cf041..aee57264 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,5 @@ Copyright (C) 2011 Brian Carlson +Copyright (C) 2019 Stefan Charsley Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/Makefile b/Makefile deleted file mode 100644 index 4d56d98a..00000000 --- a/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -.PHONY: jshint test publish-patch test - -test: - npm test - -patch: test - npm version patch -m "Bump version" - git push origin master --tags - npm publish - -minor: test - npm version minor -m "Bump version" - git push origin master --tags - npm publish - -jshint: - ./node_modules/.bin/jshint lib diff --git a/README.md b/README.md index e1a3af8c..0ca25b87 100644 --- a/README.md +++ b/README.md @@ -1,54 +1,56 @@ -# node-sql +# sql-ts + _sql string builder for node_ - supports PostgreSQL, mysql, Microsoft SQL Server, Oracle and sqlite dialects. Building SQL statements by hand is no fun, especially in a language which has clumsy support for multi-line strings. -So let's build it with JavaScript. +So let's build it with TypeScript (JavaScript also supported). Maybe it's still not fun, but at least it's _less not fun_. -[![Build Status](https://secure.travis-ci.org/brianc/node-sql.png)](http://travis-ci.org/brianc/node-sql) +![CI/CD](https://github.com/charsleysa/node-sql-ts/workflows/CI/CD/badge.svg) ## install ```sh -$ npm install sql +$ npm install sql-ts ``` ## use -```js +```ts //require the module -var sql = require('sql'); +import { Sql } from 'sql-ts'; //(optionally) set the SQL dialect -sql.setDialect('postgres'); +const sql = new Sql('postgres'); //possible dialects: mssql, mysql, postgres (default), sqlite //first we define our tables -var user = sql.define({ - name: 'user', - columns: ['id', 'name', 'email', 'lastLogin'] +const user = sql.define<{ id: number; name: string; email: string; lastLogin: Date }>({ + name: 'user', + columns: ['id', 'name', 'email', 'lastLogin'] }); -var post = sql.define({ - name: 'post', - columns: ['id', 'userId', 'date', 'title', 'body'] +const post = sql.define<{ id: number; userId: number; date: Date; title: string; body: string }>({ + name: 'post', + columns: ['id', 'userId', 'date', 'title', 'body'] }); //now let's make a simple query -var query = user.select(user.star()).from(user).toQuery(); +const query = user + .select(user.star()) + .from(user) + .toQuery(); console.log(query.text); //SELECT "user".* FROM "user" //something more interesting -var query = user +const query = user .select(user.id) .from(user) - .where( - user.name.equals('boom').and(user.id.equals(1)) - ).or( - user.name.equals('bang').and(user.id.equals(2)) - ).toQuery(); + .where(user.name.equals('boom').and(user.id.equals(1))) + .or(user.name.equals('bang').and(user.id.equals(2))) + .toQuery(); //query is parameterized by default console.log(query.text); //SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) AND ("user"."id" = $2)) OR (("user"."name" = $3) AND ("user"."id" = $4))) @@ -56,35 +58,42 @@ console.log(query.text); //SELECT "user"."id" FROM "user" WHERE ((("user"."name" console.log(query.values); //['boom', 1, 'bang', 2] //queries can be named -var query = user.select(user.star()).from(user).toNamedQuery('user.all'); +const query = user + .select(user.star()) + .from(user) + .toNamedQuery('user.all'); console.log(query.name); //'user.all' //how about a join? -var query = user.select(user.name, post.body) - .from(user.join(post).on(user.id.equals(post.userId))).toQuery(); +const query = user + .select(user.name, post.body) + .from(user.join(post).on(user.id.equals(post.userId))) + .toQuery(); console.log(query.text); //'SELECT "user"."name", "post"."body" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' //this also makes parts of your queries composable, which is handy -var friendship = sql.define({ - name: 'friendship', - columns: ['userId', 'friendId'] +const friendship = sql.define<{ userId: number; friendId: number }>({ + name: 'friendship', + columns: ['userId', 'friendId'] }); -var friends = user.as('friends'); -var userToFriends = user - .leftJoin(friendship).on(user.id.equals(friendship.userId)) - .leftJoin(friends).on(friendship.friendId.equals(friends.id)); +const friends = user.as('friends'); +const userToFriends = user + .leftJoin(friendship) + .on(user.id.equals(friendship.userId)) + .leftJoin(friends) + .on(friendship.friendId.equals(friends.id)); //and now...compose... -var friendsWhoHaveLoggedInQuery = user.from(userToFriends).where(friends.lastLogin.isNotNull()); +const friendsWhoHaveLoggedInQuery = user.from(userToFriends).where(friends.lastLogin.isNotNull()); //SELECT * FROM "user" //LEFT JOIN "friendship" ON ("user"."id" = "friendship"."userId") //LEFT JOIN "user" AS "friends" ON ("friendship"."friendId" = "friends"."id") //WHERE "friends"."lastLogin" IS NOT NULL -var friendsWhoUseGmailQuery = user.from(userToFriends).where(friends.email.like('%@gmail.com')); +const friendsWhoUseGmailQuery = user.from(userToFriends).where(friends.email.like('%@gmail.com')); //SELECT * FROM "user" //LEFT JOIN "friendship" ON ("user"."id" = "friendship"."userId") //LEFT JOIN "user" AS "friends" ON ("friendship"."friendId" = "friends"."id") @@ -92,89 +101,51 @@ var friendsWhoUseGmailQuery = user.from(userToFriends).where(friends.email.like( //Using different property names for columns //helpful if your column name is long or not camelCase -var user = sql.define({ - name: 'user', - columns: [{ - name: 'id' - }, { - name: 'state_or_province', - property: 'state' - } - ] -}); - -//now, instead of user.state_or_province, you can just use user.state -console.log(user.select().where(user.state.equals('WA')).toQuery().text); -// "SELECT "user".* FROM "user" WHERE ("user"."state_or_province" = $1)" -``` - -There are a __lot__ more examples included in the [test/dialects](https://github.com/brianc/node-sql/tree/master/test/dialects) folder. We encourage you to read through them if you have any questions on usage! - -## from the command line -You can use the [sql-generate module](https://github.com/tmont/node-sql-generate) -to automatically generate definition files from a database instance. For example, -running `node-sql-generate --dsn "mysql://user:password@host/database"` will generate -something similar to: - -```javascript -// autogenerated by node-sql-generate v0.0.1 on Tue May 21 2013 01:04:12 GMT-0700 (PDT) -var sql = require('sql'); - -/** - * SQL definition for database.bar - */ -exports.bar = sql.define({ - name: 'bar', - columns: [ - 'id', - 'foo_id' - ] -}); - -/** - * SQL definition for database.foo - */ -exports.foo = sql.define({ - name: 'foo', +const user = sql.define<{ id: number; state: string }>({ + name: 'user', columns: [ - 'id', - 'field_1', - 'foo_bar_baz' + { + name: 'id' + }, + { + name: 'state_or_province', + property: 'state' + } ] }); -/** - * Adding a column to an existing table: - */ -var model = sql.define({ name: 'foo', columns: [] }); -model.addColumn('id'); - -// If you try to add another column "id", node-sql will throw an error. -// You can suppress that error via: -model.addColumn('id', { noisy: false }); +//now, instead of user.state_or_province, you can just use user.state +console.log( + user + .select() + .where(user.state.equals('WA')) + .toQuery().text +); +// "SELECT "user".* FROM "user" WHERE ("user"."state_or_province" = $1)" ``` -Read the module's documentation for more details. +There are a **lot** more examples included in the [test/dialects](https://github.com/charsleysa/node-sql-ts/tree/master/test/dialects) folder. We encourage you to read through them if you have any questions on usage! ## contributing -We __love__ contributions. +We **love** contributions. -node-sql wouldn't be anything without all the contributors and collaborators who've worked on it. +node-sql-ts wouldn't be anything without all the contributors and collaborators who've worked on it. If you'd like to become a collaborator here's how it's done: 1. fork the repo -2. `git pull https://github.com/(your_username)/node-sql` -3. `cd node-sql` -4. `npm install` -5. `npm test` +2. `git pull https://github.com/(your_username)/node-sql-ts` +3. `cd node-sql-ts` +4. `npm install --global rollup` +5. `npm install` +6. `npm test` -At this point the tests should pass for you. If they don't pass please open an issue with the output or you can even send me an email directly. +At this point the tests should pass for you. If they don't pass please open an issue with the output or you can even send me an email directly. My email address is on my github profile and also on every commit I contributed in the repo. -Once the tests are passing, modify as you see fit. _Please_ make sure you write tests to cover your modifications. Once you're ready, commit your changes and submit a pull request. +Once the tests are passing, modify as you see fit. _Please_ make sure you write tests to cover your modifications. Once you're ready, commit your changes and submit a pull request. -__As long as your pull request doesn't have completely off-the-wall changes and it does have tests we will almost always merge it and push it to npm__ +**As long as your pull request doesn't have completely off-the-wall changes and it does have tests we will almost always merge it and push it to npm** If you think your changes are too off-the-wall, open an issue or a pull-request without code so we can discuss them before you begin. @@ -182,6 +153,6 @@ Usually after a few high-quality pull requests and friendly interactions we will After all, open source belongs to everyone. - ## license + MIT diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 00000000..146a5dd9 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,192 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +import { defineConfig, globalIgnores } from '@eslint/config-helpers'; +import TypescriptEslint from '@typescript-eslint/eslint-plugin'; +import typescriptParser from '@typescript-eslint/parser'; +import EslintPluginImport from 'eslint-plugin-import'; +import EslintPluginJsdoc from 'eslint-plugin-jsdoc'; +import EslintPluginPreferArrow from 'eslint-plugin-prefer-arrow'; +import EslintPluginUnicorn from 'eslint-plugin-unicorn'; +import eslintConfigPrettier from 'eslint-config-prettier'; +// eslint-disable-next-line import/no-extraneous-dependencies +import globals from 'globals'; + +export default defineConfig([ + globalIgnores(['node_modules/', 'dist/', 'spec/', '.idea']), + { + extends: [eslintConfigPrettier], + plugins: { + 'import': EslintPluginImport, + 'jsdoc': EslintPluginJsdoc, + 'prefer-arrow': EslintPluginPreferArrow, + 'unicorn': EslintPluginUnicorn, + '@typescript-eslint': TypescriptEslint, + }, + languageOptions: { + globals: { + ...globals.es2024, + }, + sourceType: 'module', + parser: typescriptParser, + parserOptions: { + project: ['tsconfig.json'], + }, + }, + rules: { + '@typescript-eslint/adjacent-overload-signatures': 'error', + '@typescript-eslint/array-type': [ + 'error', + { + default: 'array', + }, + ], + '@typescript-eslint/consistent-type-assertions': 'error', + '@typescript-eslint/dot-notation': 'error', + '@typescript-eslint/indent': 'off', + '@typescript-eslint/member-delimiter-style': [ + 'off', + { + multiline: { + delimiter: 'none', + requireLast: true, + }, + singleline: { + delimiter: 'semi', + requireLast: false, + }, + }, + ], + '@typescript-eslint/naming-convention': 'off', + '@typescript-eslint/no-empty-function': 'error', + '@typescript-eslint/no-empty-interface': 'error', + '@typescript-eslint/no-empty-object-type': 'error', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-misused-new': 'error', + '@typescript-eslint/no-namespace': 'error', + '@typescript-eslint/no-parameter-properties': 'off', + '@typescript-eslint/no-shadow': [ + 'error', + { + hoist: 'all', + }, + ], + '@typescript-eslint/no-this-alias': 'error', + '@typescript-eslint/no-unsafe-function-type': 'error', + '@typescript-eslint/no-unused-expressions': 'error', + '@typescript-eslint/no-use-before-define': 'off', + '@typescript-eslint/no-var-requires': 'error', + '@typescript-eslint/no-wrapper-object-types': 'error', + '@typescript-eslint/prefer-for-of': 'error', + '@typescript-eslint/prefer-function-type': 'error', + '@typescript-eslint/prefer-namespace-keyword': 'error', + '@typescript-eslint/quotes': 'off', + '@typescript-eslint/semi': ['off', null], + '@typescript-eslint/triple-slash-reference': [ + 'error', + { + path: 'always', + types: 'prefer-import', + lib: 'always', + }, + ], + '@typescript-eslint/type-annotation-spacing': 'off', + '@typescript-eslint/unified-signatures': 'error', + 'arrow-parens': ['off', 'always'], + 'brace-style': ['off', 'off'], + 'comma-dangle': 'off', + complexity: 'off', + 'constructor-super': 'error', + 'dot-notation': 'error', + 'eol-last': 'off', + eqeqeq: ['error', 'smart'], + 'guard-for-in': 'error', + 'id-blacklist': ['error', 'any', 'Number', 'number', 'String', 'string', 'Boolean', 'boolean', 'Undefined', 'undefined'], + 'id-match': 'error', + 'import/no-extraneous-dependencies': 'error', + 'import/no-internal-modules': [ + 'error', + { + allow: ['lodash/*'], + }, + ], + indent: 'off', + 'jsdoc/check-alignment': 'error', + 'jsdoc/check-indentation': 'error', + 'linebreak-style': 'off', + 'max-classes-per-file': ['error', 1], + 'max-len': 'off', + 'new-parens': 'off', + 'newline-per-chained-call': 'off', + 'no-bitwise': 'error', + 'no-caller': 'error', + 'no-cond-assign': 'error', + 'no-console': 'error', + 'no-debugger': 'error', + 'no-duplicate-case': 'error', + 'no-duplicate-imports': 'error', + 'no-empty': 'error', + 'no-empty-function': 'error', + 'no-eval': 'error', + 'no-extra-bind': 'error', + 'no-extra-semi': 'off', + 'no-fallthrough': 'off', + 'no-invalid-this': 'off', + 'no-irregular-whitespace': 'off', + 'no-multiple-empty-lines': 'off', + 'no-new-func': 'error', + 'no-new-wrappers': 'error', + 'no-redeclare': 'error', + 'no-return-await': 'error', + 'no-shadow': 'error', + 'no-sparse-arrays': 'error', + 'no-template-curly-in-string': 'error', + 'no-throw-literal': 'error', + 'no-trailing-spaces': 'off', + 'no-undef-init': 'error', + 'no-underscore-dangle': 'off', + 'no-unsafe-finally': 'error', + 'no-unused-expressions': 'error', + 'no-unused-labels': 'error', + 'no-use-before-define': 'off', + 'no-var': 'error', + 'object-shorthand': 'error', + 'one-var': ['error', 'never'], + 'padded-blocks': [ + 'off', + { + blocks: 'never', + }, + { + allowSingleLineBlocks: true, + }, + ], + 'prefer-arrow/prefer-arrow-functions': 'error', + 'prefer-const': 'error', + 'prefer-object-spread': 'error', + 'quote-props': 'off', + quotes: 'off', + radix: 'error', + semi: 'off', + 'space-before-function-paren': 'off', + 'space-in-parens': ['off', 'never'], + 'spaced-comment': [ + 'error', + 'always', + { + markers: ['/'], + }, + ], + 'unicorn/prefer-ternary': 'error', + 'use-isnan': 'error', + 'valid-typeof': 'off', + 'no-sequences': ['error'], + }, + }, + { + files: ['test/**/*.ts'], + rules: { + "prefer-arrow/prefer-arrow-functions": "off", + "id-blacklist": "off", + "import/no-internal-modules": "off" + } + }, +]); diff --git a/lib/column.js b/lib/column.js deleted file mode 100644 index 55a3da18..00000000 --- a/lib/column.js +++ /dev/null @@ -1,102 +0,0 @@ -'use strict'; - -var _ = require('lodash'); -var ColumnNode = require('./node/column'); -var OrderByValueNode = require('./node/orderByValue'); -var TextNode = require('./node/text'); -var valueExpressionMixin = require('./node/valueExpression'); - -var Column = function(config) { - this.table = config.table; - for (var name in config) { - if (config.hasOwnProperty(name)) { - this[name] = config[name]; - } - } - this.asc = this.ascending = this; - this.alias = null; - this.desc = this.descending = new OrderByValueNode({ - value : this.toNode(), - direction : new TextNode('DESC') - }); - this.dataType = config.dataType; - this.defaultValue = config.defaultValue; -}; - -// mix in value expression -_.extend(Column.prototype, valueExpressionMixin()); - -var contextify = function(base) { - var context = Object.create(Column.prototype); - Object.keys(base).forEach(function (key) { - context[key] = base[key]; - }); - return context; -}; - -Column.prototype.value = function(value) { - var context = contextify(this); - context._value = value; - return context; -}; - -Column.prototype.getValue = function() { - return this._value; -}; - -Column.prototype.toNode = function() { - // creates a query node from this column - return new ColumnNode(contextify(this)); -}; - -Column.prototype.as = function(alias) { - var context = contextify(this); - context.alias = alias; - return new ColumnNode(context); -}; - -Column.prototype.arrayAgg = function(alias) { - var context = contextify(this); - context.asArray = true; - context.alias = alias || context.name + 's'; - return new ColumnNode(context); -}; - -Column.prototype.aggregate = function(alias, aggregator) { - var context = contextify(this); - context.aggregator = aggregator.toUpperCase(); - context.alias = alias || context.name + '_' + context.aggregator.toLowerCase(); - return new ColumnNode(context); -}; - -Column.prototype.count = function(alias) { - return this.aggregate(alias, 'count'); -}; - -Column.prototype.min = function(alias) { - return this.aggregate(alias, 'min'); -}; - -Column.prototype.max = function(alias) { - return this.aggregate(alias, 'max'); -}; - -Column.prototype.sum = function(alias) { - return this.aggregate(alias, 'sum'); -}; - -Column.prototype.avg = function(alias) { - return this.aggregate(alias, 'avg'); -}; - -Column.prototype.distinct = function() { - var context = contextify(this); - context.distinct = true; - return new ColumnNode(context); -}; - -Column.prototype.toQuery = function() { - return this.toNode().toQuery(); -}; - -module.exports = Column; diff --git a/lib/column.ts b/lib/column.ts new file mode 100644 index 00000000..69990629 --- /dev/null +++ b/lib/column.ts @@ -0,0 +1,159 @@ +/* eslint-disable max-classes-per-file */ +import { ColumnNode } from './node/column.js'; +import { Node } from './node/node.js'; +import { OrderByValueNode } from './node/orderByValue.js'; +import { ValueExpressionMixin } from './node/_internal.js'; +import { TextNode } from './node/text.js'; +import { INodeable } from './nodeable.js'; +import { Table } from './table.js'; + +interface ColumnConfig { + name?: string; + property?: string; + autoGenerated?: boolean; + jsType?: any; + dataType?: string; + primaryKey?: boolean; + references?: + | string + | { + table?: string; + column?: string; + constraint?: string; + onDelete?: 'restrict' | 'cascade' | 'no action' | 'set null' | 'set default'; + onUpdate?: 'restrict' | 'cascade' | 'no action' | 'set null' | 'set default'; + }; + notNull?: boolean; + unique?: boolean; + defaultValue?: any; + subfields?: string[]; + table?: Table; + star?: boolean; + subfieldContainer?: Column; + isConstant?: boolean; + constantValue?: any; +} + +abstract class ColumnBase implements INodeable { + public abstract toNode(): Node; +} + +export class Column extends ValueExpressionMixin(ColumnBase) implements INodeable { + public name: string; + public property?: string; + public table?: Table; + public alias?: string; + public dataType?: string; + public _value: any; + public star?: boolean; + public subfields: { [key: string]: Column } = {}; + public asArray?: boolean = false; + public aggregator?: string; + public isConstant?: boolean; + public constantValue?: any; + public primaryKey?: boolean; + public notNull?: boolean; + public defaultValue?: any; + public references?: + | string + | { + table?: string; + column?: string; + constraint?: string; + onDelete?: 'restrict' | 'cascade' | 'no action' | 'set null' | 'set default'; + onUpdate?: 'restrict' | 'cascade' | 'no action' | 'set null' | 'set default'; + }; + public subfieldContainer?: Column; + public autoGenerated?: boolean; + public unique?: boolean; + public isDistinct?: boolean; + constructor(config: ColumnConfig) { + super(); + this.name = config.name as string; + this.property = config.property; + this.star = config.star; + this.table = config.table; + this.alias = undefined; + this.isConstant = config.isConstant; + this.constantValue = config.constantValue; + this.dataType = config.dataType; + this.primaryKey = config.primaryKey; + this.notNull = config.notNull; + this.defaultValue = config.defaultValue; + this.references = config.references; + this.subfieldContainer = config.subfieldContainer; + this.autoGenerated = config.autoGenerated; + this.unique = config.unique; + } + public value(value: any): Column { + const context = contextify(this); + context._value = value; + return context; + } + public getValue() { + return this._value; + } + public toNode(): ColumnNode { + // creates a query node from this column + return new ColumnNode(contextify(this)); + } + public as(alias: string): ColumnNode { + const context = contextify(this); + context.alias = alias; + return new ColumnNode(context); + } + public asc(): OrderByValueNode { + return new OrderByValueNode({ + value: this.toNode() + }) + } + public desc(): OrderByValueNode { + return new OrderByValueNode({ + direction: new TextNode('DESC'), + value: this.toNode() + }) + } + public arrayAgg(alias?: string): ColumnNode { + const context = contextify(this); + context.asArray = true; + context.alias = alias || context.name + 's'; + return new ColumnNode(context); + } + public aggregate(alias: string | undefined, aggregator: string): ColumnNode { + const context = contextify(this); + context.aggregator = aggregator.toUpperCase(); + context.alias = alias || context.name + '_' + context.aggregator.toLowerCase(); + return new ColumnNode(context); + } + public count(alias?: string) { + return this.aggregate(alias, 'count'); + } + public min(alias?: string) { + return this.aggregate(alias, 'min'); + } + public max(alias?: string) { + return this.aggregate(alias, 'max'); + } + public sum(alias?: string) { + return this.aggregate(alias, 'sum'); + } + public avg(alias?: string) { + return this.aggregate(alias, 'avg'); + } + public distinct(): ColumnNode { + const context = contextify(this); + context.isDistinct = true; + return new ColumnNode(context); + } + public toQuery() { + return this.toNode().toQuery(); + } +} + +const contextify = (base: Column): Column => { + const context = Object.create(Column.prototype); + Object.keys(base).forEach((key) => { + context[key] = base[key as keyof Column]; + }); + return context; +}; diff --git a/lib/configTypes.ts b/lib/configTypes.ts new file mode 100644 index 00000000..ed776d7e --- /dev/null +++ b/lib/configTypes.ts @@ -0,0 +1,53 @@ +import { Sql } from './sql.js'; + +export type SQLDialects = 'mssql' | 'mysql' | 'oracle' | 'postgres' | 'sqlite'; + +export interface ColumnDefinitionBase { + property?: string; + autoGenerated?: boolean; + dataType?: string; + primaryKey?: boolean; + references?: + | string + | { + table?: string; + column?: string; + constraint?: string; + onDelete?: 'restrict' | 'cascade' | 'no action' | 'set null' | 'set default'; + onUpdate?: 'restrict' | 'cascade' | 'no action' | 'set null' | 'set default'; + }; + notNull?: boolean; + unique?: boolean; + defaultValue?: any; + subfields?: string[]; +} + +export interface ColumnDefinition extends ColumnDefinitionBase { + name: string; +} + +export interface ColumnDefinitionObject { + [name: string]: ColumnDefinitionBase; +} + +export interface ForeignKeyDefinition { + name?: string; + table: string; + columns: string[]; + refColumns?: string[]; + onDelete?: 'restrict' | 'cascade' | 'no action' | 'set null' | 'set default'; + onUpdate?: 'restrict' | 'cascade' | 'no action' | 'set null' | 'set default'; +} + +export interface TableDefinition { + name: string; + schema?: string; + columns: (ColumnDefinition | string)[] | ColumnDefinitionObject; + isTemporary?: boolean; + foreignKeys?: ForeignKeyDefinition | ForeignKeyDefinition[]; + sql?: Sql; + engine?: string; + charset?: string; + snakeToCamel?: boolean; + columnWhiteList?: boolean; +} diff --git a/lib/dialect/dialect.ts b/lib/dialect/dialect.ts new file mode 100644 index 00000000..ff830e81 --- /dev/null +++ b/lib/dialect/dialect.ts @@ -0,0 +1,1240 @@ +import assert from 'assert'; +import isNumber from 'lodash/isNumber.js'; +import map from 'lodash/map.js'; + +import { AddColumnNode } from '../node/addColumn.js'; +import { AliasNode } from '../node/alias.js'; +import { AlterNode } from '../node/alter.js'; +import { ArrayCallNode } from '../node/arrayCall.js'; +import { AsOfNode } from '../node/asOf.js'; +import { AtNode } from '../node/at.js'; +import { BinaryNode } from '../node/binary.js'; +import { CascadeNode } from '../node/cascade.js'; +import { CaseNode } from '../node/case.js'; +import { CastNode } from '../node/cast.js'; +import { ColumnNode } from '../node/column.js'; +import { CreateNode } from '../node/create.js'; +import { CreateIndexNode } from '../node/createIndex.js'; +import { CreateViewNode } from '../node/createView.js'; +import { DefaultNode } from '../node/default.js'; +import { DeleteNode } from '../node/delete.js'; +import { DistinctNode } from '../node/distinct.js'; +import { DistinctOnNode } from '../node/distinctOn.js'; +import { DropNode } from '../node/drop.js'; +import { DropColumnNode } from '../node/dropColumn.js'; +import { DropIndexNode } from '../node/dropIndex.js'; +import { ForeignKeyNode } from '../node/foreignKey.js'; +import { ForShareNode } from '../node/forShare.js'; +import { ForUpdateNode } from '../node/forUpdate.js'; +import { FunctionCallNode } from '../node/functionCall.js'; +import { FromNode } from '../node/from.js'; +import { GroupByNode } from '../node/groupBy.js'; +import { HavingNode } from '../node/having.js'; +import { IfExistsNode } from '../node/ifExists.js'; +import { IfNotExistsNode } from '../node/ifNotExists.js'; +import { InNode } from '../node/in.js'; +import { IndexesNode } from '../node/indexes.js'; +import { InsertNode } from '../node/insert.js'; +import { IntervalNode } from '../node/interval.js'; +import { JoinNode } from '../node/join.js'; +import { LiteralNode } from '../node/literal.js'; +import { ModifierNode } from '../node/modifier.js'; +import { Node } from '../node/node.js'; +import { NotInNode } from '../node/notIn.js'; +import { OnConflictNode } from '../node/onConflict.js'; +import { OnDuplicateNode } from '../node/onDuplicate.js'; +import { OrderByNode } from '../node/orderBy.js'; +import { OrderByValueNode } from '../node/orderByValue.js'; +import { OrIgnoreNode } from '../node/orIgnore.js'; +import { ParameterNode } from '../node/parameter.js'; +import { PrefixUnaryNode } from '../node/prefixUnary.js'; +import { PostfixUnaryNode } from '../node/postfixUnary.js'; +import { Query } from '../node/query.js'; +import { RenameNode } from '../node/rename.js'; +import { RenameColumnNode } from '../node/renameColumn.js'; +import { ReplaceNode } from '../node/replace.js'; +import { RestrictNode } from '../node/restrict.js'; +import { ReturningNode } from '../node/returning.js'; +import { RowCallNode } from '../node/rowCall.js'; +import { SelectNode } from '../node/select.js'; +import { SliceNode } from '../node/slice.js'; +import { TableNode } from '../node/table.js'; +import { TernaryNode } from '../node/ternary.js'; +import { TextNode } from '../node/text.js'; +import { TruncateNode } from '../node/truncate.js'; +import { UpdateNode } from '../node/update.js'; +import { WhereNode } from '../node/where.js'; +import { Table } from '../table.js'; + +export abstract class Dialect { + protected output: string[]; + protected params: string[]; + protected queryNode?: Query; + protected arrayAggFunctionName: string = 'array_agg'; + protected aliasText: string = ' AS '; + protected quoteCharacter: string = '"'; + protected disableParameterPlaceholders: boolean = false; + protected selectOrDeleteEndIndex: number = 0; + protected visitedInsert: boolean = false; + protected visitingUpdateTargetColumn: boolean = false; + protected visitingCreate: boolean = false; + protected visitCreateCompoundPrimaryKey: boolean = false; + protected visitingAlter: boolean = false; + protected visitingCast: boolean = false; + protected visitingWhere: boolean = false; + protected visitingCase: boolean = false; + protected visitedReplace: boolean = false; + protected visitingAddColumn: boolean = false; + protected visitingReturning: boolean = false; + protected visitingJoin: boolean = false; + protected visitingFunctionCall: boolean = false; + protected visitingDistinctOn: boolean = false; + constructor(protected config: ConfigType) { + this.output = []; + this.params = []; + } + + protected abstract createSubInstance(): Dialect; + + public _getParameterText(index: number, value: any): string { + return this.disableParameterPlaceholders ? this._getParameterValue(value).toString() : this._getParameterPlaceholder(index, value); + } + + public _getParameterValue( + value: null | boolean | number | string | any[] | Date | Buffer | Record, + quoteChar?: string + ): string | number { + // handle primitives + if (null === value) { + value = 'NULL'; + } else if ('boolean' === typeof value) { + value = value ? 'TRUE' : 'FALSE'; + } else if ('number' === typeof value) { + // number is just number + value = value; + } else if ('string' === typeof value) { + // string uses single quote by default + value = this.quote(value, quoteChar || "'"); + } else if ('object' === typeof value) { + if (Array.isArray(value)) { + value = map(value, (val) => this._getParameterValue(val, quoteChar)); + value = `(${(value as any[]).join(', ')})`; + } else if (value instanceof Date) { + // Date object's default toString format does not get parsed well + // Handle dates using custom dateToString method for postgres and toISOString for others + value = this._getParameterValue(value.toISOString(), quoteChar); + } else if (Buffer.isBuffer(value)) { + value = this._getParameterValue('\\x' + value.toString('hex'), quoteChar); + } else { + // rich object represent with string + const strValue = value.toString(); + value = strValue === '[object Object]' ? this._getParameterValue(JSON.stringify(value), quoteChar) : this._getParameterValue(strValue, quoteChar); + } + } else { + throw new Error(`Unable to use ${value} in query`); + } + // value has been converted at this point + return value; + } + public _getParameterPlaceholder(index: string | number, value: unknown): string { + return '$' + index; + } + public getQuery(queryNode: Query | Table): { text: string, values: string[] } { + // passed in a table, not a query + if (queryNode instanceof Table) { + queryNode = queryNode.select(queryNode.star()); + } + this.output = this.visit(queryNode); + // if is a create view, must replace paramaters with values + if (this.output.indexOf('CREATE VIEW') > -1) { + const previousFlagStatus = this.disableParameterPlaceholders; + this.disableParameterPlaceholders = true; + this.output = []; + this.output = this.visit(queryNode); + this.params = []; + this.disableParameterPlaceholders = previousFlagStatus; + } + // create the query object + const query = { text: this.output.join(' '), values: this.params }; + // reset the internal state of this builder + this.output = []; + this.params = []; + return query; + } + public getString(queryNode: Query) { + // switch off parameter placeholders + const previousFlagStatus = this.disableParameterPlaceholders; + this.disableParameterPlaceholders = true; + let query; + try { + // use the same code path for query building + query = this.getQuery(queryNode); + } finally { + // always restore the flag afterwards + this.disableParameterPlaceholders = previousFlagStatus; + } + return query.text; + } + public visit(node: Node): string[] { + switch (node.type) { + case 'QUERY': + return this.visitQuery(node as Query); + case 'SUBQUERY': + return this.visitSubquery(node as Query); + case 'SELECT': + return this.visitSelect(node as SelectNode); + case 'INSERT': + return this.visitInsert(node as InsertNode); + case 'REPLACE': + return this.visitReplace(node as ReplaceNode); + case 'UPDATE': + return this.visitUpdate(node as UpdateNode); + case 'DELETE': + return this.visitDelete(node as DeleteNode); + case 'CREATE': + return this.visitCreate(node as CreateNode); + case 'DROP': + return this.visitDrop(node as DropNode); + case 'TRUNCATE': + return this.visitTruncate(node as TruncateNode); + case 'DISTINCT': + return this.visitDistinct(node as DistinctNode); + case 'DISTINCT ON': + return this.visitDistinctOn(node as DistinctOnNode); + case 'ALIAS': + return this.visitAlias(node as AliasNode); + case 'ALTER': + return this.visitAlter(node as AlterNode); + case 'CAST': + return this.visitCast(node as CastNode); + case 'FROM': + return this.visitFrom(node as FromNode); + case 'AS OF': + return this.visitAsOf(node as AsOfNode); + case 'WHERE': + return this.visitWhere(node as WhereNode); + case 'ORDER BY': + return this.visitOrderBy(node as OrderByNode); + case 'ORDER BY VALUE': + return this.visitOrderByValue(node as OrderByValueNode); + case 'GROUP BY': + return this.visitGroupBy(node as GroupByNode); + case 'HAVING': + return this.visitHaving(node as HavingNode); + case 'RETURNING': + return this.visitReturning(node as ReturningNode); + case 'ONDUPLICATE': + return this.visitOnDuplicate(node as OnDuplicateNode); + case 'ONCONFLICT': + return this.visitOnConflict(node as OnConflictNode); + case 'FOR UPDATE': + return this.visitForUpdate(node as ForUpdateNode); + case 'FOR SHARE': + return this.visitForShare(node as ForShareNode); + case 'TABLE': + return this.visitTable(node as TableNode); + case 'COLUMN': + return this.visitColumn(node as ColumnNode); + case 'FOREIGN KEY': + return this.visitForeignKey(node as ForeignKeyNode); + case 'JOIN': + return this.visitJoin(node as JoinNode); + case 'LITERAL': + return this.visitLiteral(node as LiteralNode); + case 'TEXT': + return this.visitText(node as TextNode); + case 'PARAMETER': + return this.visitParameter(node as ParameterNode); + case 'DEFAULT': + return this.visitDefault(node as DefaultNode); + case 'IF EXISTS': + return this.visitIfExists(node as IfExistsNode); + case 'IF NOT EXISTS': + return this.visitIfNotExists(node as IfNotExistsNode); + case 'OR IGNORE': + return this.visitOrIgnore(node as OrIgnoreNode); + case 'CASCADE': + return this.visitCascade(node as CascadeNode); + case 'RESTRICT': + return this.visitRestrict(node as RestrictNode); + case 'RENAME': + return this.visitRename(node as RenameNode); + case 'ADD COLUMN': + return this.visitAddColumn(node as AddColumnNode); + case 'DROP COLUMN': + return this.visitDropColumn(node as DropColumnNode); + case 'RENAME COLUMN': + return this.visitRenameColumn(node as RenameColumnNode); + case 'INDEXES': + return this.visitIndexes(node as IndexesNode); + case 'CREATE INDEX': + return this.visitCreateIndex(node as CreateIndexNode); + case 'DROP INDEX': + return this.visitDropIndex(node as DropIndexNode); + case 'FUNCTION CALL': + return this.visitFunctionCall(node as FunctionCallNode); + case 'ARRAY CALL': + return this.visitArrayCall(node as ArrayCallNode); + case 'ROW CALL': + return this.visitRowCall(node as RowCallNode); + case 'CREATE VIEW': + return this.visitCreateView(node as CreateViewNode); + case 'INTERVAL': + return this.visitInterval(node as IntervalNode); + case 'POSTFIX UNARY': + return this.visitPostfixUnary(node as PostfixUnaryNode); + case 'PREFIX UNARY': + return this.visitPrefixUnary(node as PrefixUnaryNode); + case 'BINARY': + return this.visitBinary(node as BinaryNode); + case 'TERNARY': + return this.visitTernary(node as TernaryNode); + case 'IN': + return this.visitIn(node as InNode); + case 'NOT IN': + return this.visitNotIn(node as NotInNode); + case 'CASE': + return this.visitCase(node as CaseNode); + case 'AT': + return this.visitAt(node as AtNode); + case 'SLICE': + return this.visitSlice(node as SliceNode); + case 'LIMIT': + case 'OFFSET': + return this.visitModifier(node as ModifierNode); + default: + throw new Error(`Unrecognized node type ${node.type}`); + } + } + public quote(word: string, quoteCharacter?: string) { + const q = quoteCharacter != null ? quoteCharacter : this.quoteCharacter; + // handle square brackets specially + return q === '[' ? '[' + word + ']' : q + word.replace(new RegExp(q, 'g'), q + q) + q; + } + public visitSelect(selectNode: SelectNode): string[] { + const result = ['SELECT']; + if (selectNode.isDistinct) { + result.push('DISTINCT'); + } + const distinctOnNode = selectNode.nodes.filter((node) => node.type === 'DISTINCT ON').shift(); + const nonDistinctOnNodes = selectNode.nodes.filter((node) => node.type !== 'DISTINCT ON'); + if (distinctOnNode) { + result.push(this.visit(distinctOnNode).join()); + } + result.push(nonDistinctOnNodes.map(this.visit.bind(this)).join(', ')); + this.selectOrDeleteEndIndex = this.output.length + result.length; + return result; + } + public visitInsert(insertNode: InsertNode): string[] { + // don't use table.column for inserts + this.visitedInsert = true; + const result = ['INSERT', ...insertNode.nodes.map((n) => this.visit(n).join())]; + result.push(`INTO ${this.visit(this.queryNode!.table.toNode()).join()}`); + result.push(`(${insertNode.columns.map(this.visit.bind(this)).join(', ')})`); + const paramNodes = insertNode.getParameters(); + if (paramNodes.length > 0) { + const paramText = paramNodes + .map((paramSet) => { + return paramSet.map((param) => this.visit(param)).join(', '); + }) + .map((param) => `(${param})`) + .join(', '); + result.push('VALUES', paramText); + if (result.slice(2, 5).join(' ') === '() VALUES ()') { + result.splice(2, 3, 'DEFAULT VALUES'); + } + } + this.visitedInsert = false; + return result; + } + public visitReplace(replaceNode: ReplaceNode): string[] { + throw new Error('Postgres does not support REPLACE.'); + } + public visitUpdate(updateNode: UpdateNode): string[] { + // don't auto-generate from clause + const params: string[] = []; + /* jshint boss: true */ + for (const node of updateNode.nodes as ColumnNode[]) { + this.visitingUpdateTargetColumn = true; + const targetCol = this.visit(node); + this.visitingUpdateTargetColumn = false; + params.push(`${targetCol} = ${this.visit(node.value)}`); + } + const result = ['UPDATE', this.visit(this.queryNode!.table.toNode()).join(), 'SET', params.join(', ')]; + return result; + } + public visitDelete(deleteNode: DeleteNode): string[] { + const result = ['DELETE']; + if (deleteNode.nodes.length) { + result.push(deleteNode.nodes.map(this.visit.bind(this)).join(', ')); + } + this.selectOrDeleteEndIndex = result.length; + return result; + } + public visitCreate(createNode: CreateNode): string[] { + this.visitingCreate = true; + // don't auto-generate from clause + const table = this.queryNode!.table; + const colNodes = table.columns.map((col) => col.toNode()); + const foreignKeyNodes = table.foreignKeys; + let result = ['CREATE TABLE']; + if (createNode.options.isTemporary) { + result = ['CREATE TEMPORARY TABLE']; + } + result = result.concat(createNode.nodes.map((n) => this.visit(n).join())); + result.push(this.visit(table.toNode()).join()); + const primaryColNodes = colNodes.filter((n) => n.primaryKey); + this.visitCreateCompoundPrimaryKey = primaryColNodes.length > 1; + let colspec = `(${colNodes.map((n) => this.visit(n).join()).join(', ')}`; + if (this.visitCreateCompoundPrimaryKey) { + colspec += `, PRIMARY KEY (${primaryColNodes.map((node) => this.quote(node.name)).join(', ')})`; + } + if (foreignKeyNodes.length > 0) { + colspec += `, ${foreignKeyNodes.map((n) => this.visit(n).join()).join(', ')}`; + } + colspec += ')'; + result.push(colspec); + this.visitCreateCompoundPrimaryKey = false; + this.visitingCreate = false; + return result; + } + public visitDrop(dropNode: DropNode): string[] { + // don't auto-generate from clause + let result = ['DROP TABLE']; + result = result.concat(dropNode.nodes.map((n) => this.visit(n).join())); + return result; + } + public visitTruncate(truncateNode: TruncateNode): string[] { + let result = ['TRUNCATE TABLE']; + result = result.concat(truncateNode.nodes.map((n) => this.visit(n).join())); + return result; + } + public visitDistinct(distinctNode: DistinctNode): string[] { + // Nothing to do here since it's handled in the SELECT clause + return []; + } + public visitDistinctOn(distinctOnNode: DistinctOnNode): string[] { + this.visitingDistinctOn = true; + const result: string[] = [`DISTINCT ON(${distinctOnNode.nodes.map((n) => this.visit(n).join()).join(', ')})`]; + this.visitingDistinctOn = false; + return result; + } + public visitAlias(aliasNode: AliasNode): string[] { + const result = [this.visit(aliasNode.value) + this.aliasText + this.quote(aliasNode.alias)]; + return result; + } + public visitAlter(alterNode: AlterNode): string[] { + this.visitingAlter = true; + // don't auto-generate from clause + const table = this.queryNode!.table; + const result: string[] = ['ALTER TABLE', ...this.visit(table.toNode()), alterNode.nodes.map(this.visit.bind(this)).join(', ')]; + this.visitingAlter = false; + return result; + } + public visitCast(castNode: CastNode): string[] { + this.visitingCast = true; + const result: string[] = ['CAST(' + this.visit(castNode.value) + ' AS ' + castNode.dataType + ')']; + this.visitingCast = false; + return result; + } + public visitFrom(fromNode: FromNode): string[] { + let result = []; + if (fromNode.skipFromStatement) { + result.push(','); + } else { + result.push('FROM'); + } + for (const node of fromNode.nodes) { + result = result.concat(this.visit(node)); + } + return result; + } + public visitAsOf(asOfNode: AsOfNode): string[] { + const result = ['AS OF SYSTEM TIME', ...asOfNode.nodes.flatMap(this.visit.bind(this))]; + return result; + } + public visitWhere(whereNode: WhereNode): string[] { + this.visitingWhere = true; + const result = ['WHERE', whereNode.nodes.map(this.visit.bind(this)).join(', ')]; + this.visitingWhere = false; + return result; + } + public visitOrderBy(orderByNode: OrderByNode): string[] { + const result = ['ORDER BY', orderByNode.nodes.map(this.visit.bind(this)).join(', ')]; + return result; + } + public visitOrderByValue(orderByValueNode: OrderByValueNode): string[] { + let text = this.visit(orderByValueNode.value).join(); + if (orderByValueNode.direction) { + text += ' ' + this.visit(orderByValueNode.direction).join(); + } + return [text]; + } + public visitGroupBy(groupByNode: GroupByNode): string[] { + const result = ['GROUP BY', groupByNode.nodes.map(this.visit.bind(this)).join(', ')]; + return result; + } + public visitHaving(havingNode: HavingNode): string[] { + const result = ['HAVING', havingNode.nodes.map(this.visit.bind(this)).join(' AND ')]; + return result; + } + public visitPrefixUnary(prefixUnaryNode: PrefixUnaryNode): string[] { + const text = '(' + prefixUnaryNode.operator + ' ' + this.visit(prefixUnaryNode.left) + ')'; + return [text]; + } + public visitPostfixUnary(postfixUnaryNode: PostfixUnaryNode): string[] { + const text = '(' + this.visit(postfixUnaryNode.left) + ' ' + postfixUnaryNode.operator + ')'; + return [text]; + } + public visitBinary(binaryNode: BinaryNode): string[] { + (binaryNode.left as any).property = (binaryNode.left as any).name; + (binaryNode.right as any).property = (binaryNode.right as any).name; + let text = `(${this.visit(binaryNode.left)} ${binaryNode.operator} `; + text += Array.isArray(binaryNode.right) ? `(${binaryNode.right.map((node) => this.visit(node)).join(', ')})` : this.visit(binaryNode.right).join(); + text += ')'; + return [text]; + } + public visitTernary(ternaryNode: TernaryNode): string[] { + const visitPart = (value: Node) => { + return Array.isArray(value) ? `(${value.map((node) => this.visit(node)).join(', ')})` : this.visit(value).join(); + }; + const text = `(${this.visit(ternaryNode.left)} ${ternaryNode.operator} ${visitPart(ternaryNode.middle)} ${ + ternaryNode.separator + } ${visitPart(ternaryNode.right)})`; + return [text]; + } + public visitIn(inNode: InNode): string[] { + let text = '('; + if (Array.isArray(inNode.right)) { + if (inNode.right.length) { + const params: string[] = []; + let hasNull = false; + inNode.right.forEach((node) => { + if (node.type === 'PARAMETER' && (node as ParameterNode).value() === null) { + hasNull = true; + } else { + params.push(this.visit(node).join()); + } + }); + if (params.length) { + text += `${this.visit(inNode.left)} IN (${params.join(', ')})`; + if (hasNull) { + text += ` OR ${this.visit(inNode.left)} IS NULL`; + } + } else { + // implicitely has null + text += `${this.visit(inNode.left)} IS NULL`; + } + } else { + text += '1=0'; + } + } else { + text += `${this.visit(inNode.left)} IN ${this.visit(inNode.right)}`; + } + text += ')'; + return [text]; + } + public visitNotIn(notInNode: NotInNode): string[] { + let text = '('; + if (Array.isArray(notInNode.right)) { + if (notInNode.right.length) { + const params: string[] = []; + let hasNull = false; + notInNode.right.forEach((node) => { + if (node.type === 'PARAMETER' && (node as ParameterNode).value() === null) { + hasNull = true; + } else { + params.push(this.visit(node).join()); + } + }); + if (params.length && hasNull) { + text += `NOT (${this.visit(notInNode.left)} IN (${params.join(', ')}) OR ${this.visit(notInNode.left)} IS NULL)`; + } else if (params.length) { + text += `${this.visit(notInNode.left)} NOT IN (${params.join(', ')})`; + } else { + // implicitely has null + text += `${this.visit(notInNode.left)} IS NOT NULL`; + } + } else { + text += '1=1'; + } + } else { + text += `${this.visit(notInNode.left)} NOT IN ${this.visit(notInNode.right)}`; + } + text += ')'; + return [text]; + } + public visitCase(caseNode: CaseNode): string[] { + assert(caseNode.whenList.length === caseNode.thenList.length); + let text = '(CASE'; + this.visitingCase = true; + for (let i = 0; i < caseNode.whenList.length; i++) { + text += ` WHEN ${this.visit(caseNode.whenList[i])} THEN ${this.visit(caseNode.thenList[i])}`; + } + if (caseNode.else != null) { + text += ` ELSE ${this.visit(caseNode.else)}`; + } + this.visitingCase = false; + text += ' END)'; + return [text]; + } + public visitAt(atNode: AtNode): string[] { + const text = `(${this.visit(atNode.value)})[${this.visit(atNode.index)}]`; + return [text]; + } + public visitSlice(sliceNode: SliceNode): string[] { + const text = `(${this.visit(sliceNode.value)})[${this.visit(sliceNode.start)}:${this.visit(sliceNode.end)}]`; + return [text]; + } + public visitQuery(queryNode: Query): string[] { + if (this.queryNode) { + return this.visitSubquery(queryNode, dontParenthesizeSubQuery(this.queryNode)); + } + this.queryNode = queryNode; + // need to sort the top level query nodes on visitation priority + // so select/insert/update/delete comes before from comes before where + let missingFrom = true; + let hasFrom = false; + let createView; + let isSelect = false; + const actions = []; + const targets = []; + const filters = []; + for (const node of queryNode.nodes) { + switch (node.type) { + case 'SELECT': + isSelect = true; + case 'DELETE': + actions.push(node); + break; + case 'INDEXES': + case 'INSERT': + case 'REPLACE': + case 'UPDATE': + case 'CREATE': + case 'DROP': + case 'TRUNCATE': + case 'ALTER': + actions.push(node); + missingFrom = false; + break; + case 'FROM': + (node as FromNode).skipFromStatement = hasFrom; + hasFrom = true; + missingFrom = false; + targets.push(node); + break; + case 'CREATE VIEW': + createView = node; + break; + default: + filters.push(node); + break; + } + } + if (!actions.length) { + // if no actions are given, guess it's a select + actions.push(new SelectNode().add(new TextNode('*'))); + isSelect = true; + } + if (missingFrom && queryNode.table instanceof Table) { + // the instanceof handles the situation where a sql.select(some expression) is used and there should be no FROM clause + targets.push(new FromNode().add(queryNode.table)); + } + if (createView) { + if (isSelect) { + actions.unshift(createView); + } else { + throw new Error('Create View requires a Select.'); + } + } + return this.visitQueryHelper(actions, targets, filters); + } + /** + * We separate out this part of query building so it can be overridden by other implementations. + * + * @param {Node[]} actions + * @param {Node[]} targets + * @param {Node[]} filters + * @returns {String[]} + */ + public visitQueryHelper(actions: Node[], targets: Node[], filters: Node[]): string[] { + this.handleDistinct(actions, filters); + // lazy-man sorting + const sortedNodes = actions.concat(targets).concat(filters); + for (const node of sortedNodes) { + const res = this.visit(node); + this.output = this.output.concat(res); + } + // implicit 'from' + return this.output; + } + public visitSubquery(queryNode: Query, dontParenthesize?: boolean): string[] { + // create another query builder of the current class to build the subquery + const subQuery = this.createSubInstance(); + // let the subquery modify this instance's params array + subQuery.params = this.params; + // pass on the disable parameter placeholder flag + const previousFlagStatus = subQuery.disableParameterPlaceholders; + subQuery.disableParameterPlaceholders = this.disableParameterPlaceholders; + try { + subQuery.visitQuery(queryNode); + } finally { + // restore the flag + subQuery.disableParameterPlaceholders = previousFlagStatus; + } + const alias = queryNode.alias; + if (dontParenthesize) { + return [subQuery.output.join(' ') + (alias ? ' ' + this.quote(alias) : '')]; + } + return ['(' + subQuery.output.join(' ') + ')' + (alias ? ' ' + this.quote(alias) : '')]; + } + public visitTable(tableNode: TableNode): string[] { + const table = tableNode.table; + let txt = ''; + if (table.getSchema()) { + txt = this.quote(table.getSchema()!); + txt += '.'; + } + txt += this.quote(table.getName()); + if (typeof table.alias === 'string') { + txt += this.aliasText + this.quote(table.alias); + } + return [txt]; + } + public visitColumn(columnNode: ColumnNode): string[] { + const table = columnNode.table; + const inInsertUpdateClause = this.visitedInsert || this.visitedReplace || this.visitingUpdateTargetColumn; + const inDdlClause = this.visitingAddColumn || this.visitingAlter || this.visitingCreate; + const inSelectClause = + this.visitingReturning || + (!this.selectOrDeleteEndIndex && + !this.visitingWhere && + !inInsertUpdateClause && + !inDdlClause && + !this.visitingCase && + !this.visitingJoin); + const inFunctionCall = this.visitingFunctionCall; + const inCast = this.visitingCast; + const inDistinctOn = this.visitingDistinctOn; + const txt = []; + let closeParen = 0; + if (inSelectClause && ((table && !table.alias) || !!columnNode.alias)) { + if (columnNode.asArray) { + closeParen++; + txt.push(`${this.arrayAggFunctionName}(`); + } + if (!!columnNode.aggregator) { + closeParen++; + txt.push(`${columnNode.aggregator}(`); + } + if (columnNode.isDistinct === true) { + closeParen++; + txt.push('DISTINCT('); + } + } + if ( + !inInsertUpdateClause && + !this.visitingReturning && + !this.visitingCreate && + !this.visitingAlter && + !columnNode.subfieldContainer + ) { + if (table) { + if (typeof table.alias === 'string') { + txt.push(this.quote(table.alias)); + } else { + if (table.getSchema()) { + txt.push(this.quote(table.getSchema()!)); + txt.push('.'); + } + txt.push(this.quote(table.getName())); + } + txt.push('.'); + } + } + if (columnNode.star) { + const allCols = []; + let hasAliases = false; + if (columnNode.aggregator !== 'COUNT') { + const tableName = txt.join(''); + for (const col of table!.columns) { + const aliased = col.name !== (col.alias || col.property!); + hasAliases = hasAliases || aliased; + allCols.push( + tableName + this.quote(col.name) + (aliased ? this.aliasText + this.quote(col.alias || col.property!) : '') + ); + } + } + if (hasAliases) { + txt.length = 0; + txt.push(allCols.join(', ')); + } else { + txt.push('*'); + } + } else if (columnNode.isConstant) { + // this injects directly into SELECT statement rather than creating a parameter + // txt.push(this._getParameterValue(columnNode.literalValue)) + // currently thinking it is better to generate a parameter + const value = columnNode.constantValue; + this.params.push(value); + txt.push(this._getParameterText(this.params.length, value)); + } else { + if (columnNode.subfieldContainer) { + txt.push('(' + this.visitColumn(columnNode.subfieldContainer.toNode()) + ').'); + } + txt.push(this.quote(columnNode.name)); + } + if (closeParen) { + for (let j = 0; j < closeParen; j++) { + txt.push(')'); + } + } + if (inSelectClause && !inFunctionCall && !inCast && !inDistinctOn && (columnNode.alias || columnNode.property !== columnNode.name)) { + txt.push(this.aliasText + this.quote(columnNode.alias || columnNode.property)); + } + if (this.visitingCreate || this.visitingAddColumn) { + assert( + columnNode.dataType, + `dataType missing for column ${columnNode.name} (CREATE TABLE and ADD COLUMN statements require a dataType)` + ); + txt.push(` ${columnNode.dataType}`); + if (this.visitingCreate) { + if (columnNode.primaryKey && !this.visitCreateCompoundPrimaryKey) { + // creating a column as a primary key + txt.push(' PRIMARY KEY'); + } else if (columnNode.notNull) { + txt.push(' NOT NULL'); + } + if (!columnNode.primaryKey && columnNode.unique) { + txt.push(' UNIQUE'); + } + if (columnNode.defaultValue !== undefined) { + txt.push(` DEFAULT ${this._getParameterValue(columnNode.defaultValue)}`); + } + } + if (!!columnNode.references) { + assert.strictEqual( + typeof columnNode.references, + 'object', + 'references is not a object for column ' + + columnNode.name + + ' (REFERENCES statements within CREATE TABLE and ADD COLUMN statements' + + ' require refrences to be expressed as an object)' + ); + // Empty refrence objects are ok + if (Object.keys(columnNode.references).length > 0) { + const references = columnNode.references! as Exclude, string>; + assert( + references.table, + 'reference.table missing for column ' + + columnNode.name + + ' (REFERENCES statements within CREATE TABLE and ADD COLUMN statements' + + ' require a table and column)' + ); + assert( + references.column, + 'reference.column missing for column ' + + columnNode.name + + ' (REFERENCES statements within CREATE TABLE and ADD COLUMN statements' + + ' require a table and column)' + ); + txt.push(' REFERENCES '); + // TODO: if this is used need to put back in + // if (references.schema) { + // txt.push(this.quote(references.schema) + '.'); + // } + txt.push(this.quote(references.table!) + '(' + this.quote(references.column!) + ')'); + let onDelete: string | undefined = references.onDelete; + if (onDelete) { + onDelete = onDelete.toUpperCase(); + } + if ( + onDelete === 'CASCADE' || + onDelete === 'RESTRICT' || + onDelete === 'SET NULL' || + onDelete === 'SET DEFAULT' || + onDelete === 'NO ACTION' + ) { + txt.push(` ON DELETE ${onDelete}`); + } + let onUpdate: string | undefined = references.onUpdate; + if (onUpdate) { + onUpdate = onUpdate.toUpperCase(); + } + if ( + onUpdate === 'CASCADE' || + onUpdate === 'RESTRICT' || + onUpdate === 'SET NULL' || + onUpdate === 'SET DEFAULT' || + onUpdate === 'NO ACTION' + ) { + txt.push(` ON UPDATE ${onUpdate}`); + } + const constraint: string | undefined = references.constraint; + if (constraint) { + txt.push(` ${constraint.toUpperCase()}`); + } + } + } + } + return [txt.join('')]; + } + public visitForeignKey(foreignKeyNode: ForeignKeyNode): string[] { + const txt = []; + if (this.visitingCreate) { + assert(foreignKeyNode.table, 'Foreign table missing for table reference'); + assert(foreignKeyNode.columns, 'Columns missing for table reference'); + if (foreignKeyNode.refColumns !== undefined) { + assert.strictEqual( + foreignKeyNode.columns.length, + foreignKeyNode.refColumns.length, + 'Number of local columns and foreign columns differ in table reference' + ); + } + if (foreignKeyNode.name !== undefined) { + txt.push('CONSTRAINT ' + this.quote(foreignKeyNode.name) + ' '); + } + txt.push('FOREIGN KEY ( '); + for (let i = 0; i < foreignKeyNode.columns.length; i++) { + if (i > 0) { + txt.push(', '); + } + txt.push(this.quote(foreignKeyNode.columns[i])); + } + txt.push(' ) REFERENCES '); + if (foreignKeyNode.schema !== undefined) { + txt.push(this.quote(foreignKeyNode.schema) + '.'); + } + txt.push(this.quote(foreignKeyNode.table)); + if (foreignKeyNode.refColumns !== undefined) { + txt.push(' ( '); + for (let i = 0; i < foreignKeyNode.refColumns.length; i++) { + if (i > 0) { + txt.push(', '); + } + txt.push(this.quote(foreignKeyNode.refColumns[i])); + } + txt.push(' )'); + } + let onDelete = foreignKeyNode.onDelete; + if (onDelete) { + onDelete = onDelete.toUpperCase(); + if ( + onDelete === 'CASCADE' || + onDelete === 'RESTRICT' || + onDelete === 'SET NULL' || + onDelete === 'SET DEFAULT' || + onDelete === 'NO ACTION' + ) { + txt.push(` ON DELETE ${onDelete}`); + } + } + let onUpdate = foreignKeyNode.onUpdate; + if (onUpdate) { + onUpdate = onUpdate.toUpperCase(); + if ( + onUpdate === 'CASCADE' || + onUpdate === 'RESTRICT' || + onUpdate === 'SET NULL' || + onUpdate === 'SET DEFAULT' || + onUpdate === 'NO ACTION' + ) { + txt.push(` ON UPDATE ${onUpdate}`); + } + } + if (foreignKeyNode.constraint) { + txt.push(` ${foreignKeyNode.constraint.toUpperCase()}`); + } + } + return [txt.join('')]; + } + public visitFunctionCall(functionCallNode: FunctionCallNode): string[] { + this.visitingFunctionCall = true; + const extract = () => { + const nodes = functionCallNode.nodes.map(this.visit.bind(this)); + if (nodes.length !== 1) { + throw new Error(`Not enough parameters passed to ${functionCallNode.name} function`); + } + return `EXTRACT(${functionCallNode.name} FROM ${nodes[0] + ''})`; + }; + let txt = ''; + // Override date functions since postgres (and others) uses extract + if (['YEAR', 'MONTH', 'DAY', 'HOUR'].indexOf(functionCallNode.name) >= 0) { + txt = extract(); + } + // Override CURRENT_TIMESTAMP function to remove parens + else if ('CURRENT_TIMESTAMP' === functionCallNode.name) { + txt = functionCallNode.name; + } else { + txt = `${functionCallNode.name}(${functionCallNode.nodes.map(this.visit.bind(this)).join(', ')})`; + } + this.visitingFunctionCall = false; + return [txt]; + } + public visitArrayCall(arrayCallNode: ArrayCallNode): string[] { + const txt = `ARRAY[${arrayCallNode.nodes.map(this.visit.bind(this)).join(', ')}]`; + return [txt]; + } + public visitRowCall(rowCallNode: RowCallNode): string[] { + const txt = `(${rowCallNode.nodes.map(this.visit.bind(this)).join(', ')})`; + return [txt]; + } + public visitParameter(parameterNode: ParameterNode): string[] { + // save the value into the parameters array + const value = parameterNode.value(); + this.params.push(value); + return parameterNode.isExplicit ? [] : [this._getParameterText(this.params.length, value)]; + } + public visitDefault(defaultNode: DefaultNode): string[] { + /* jshint unused: false */ + return ['DEFAULT']; + } + public visitAddColumn(addColumnNode: AddColumnNode): string[] { + this.visitingAddColumn = true; + const result = [`ADD COLUMN ${this.visit(addColumnNode.nodes[0])}`]; + this.visitingAddColumn = false; + return result; + } + public visitDropColumn(dropColumnNode: DropColumnNode): string[] { + return [`DROP COLUMN ${this.visit(dropColumnNode.nodes[0])}`]; + } + public visitRenameColumn(renameColumnNode: RenameColumnNode): string[] { + return [`RENAME COLUMN ${this.visit(renameColumnNode.nodes[0])} TO ${this.visit(renameColumnNode.nodes[1])}`]; + } + public visitRename(renameNode: RenameNode): string[] { + return [`RENAME TO ${this.visit(renameNode.nodes[0])}`]; + } + public visitIfExists(ifExistsNode: IfExistsNode): string[] { + return ['IF EXISTS']; + } + public visitIfNotExists(ifNotExistsNode: IfNotExistsNode): string[] { + return ['IF NOT EXISTS']; + } + public visitOrIgnore(orIgnoreNode: OrIgnoreNode): string[] { + throw new Error('PostgreSQL does not allow orIgnore clause.'); + } + public visitCascade(cascadeNode: CascadeNode): string[] { + return ['CASCADE']; + } + public visitRestrict(restrictNode: RestrictNode): string[] { + return ['RESTRICT']; + } + public visitForUpdate(forUpdateNode: ForUpdateNode): string[] { + return ['FOR UPDATE']; + } + public visitForShare(forShareNode: ForShareNode): string[] { + return ['FOR SHARE']; + } + public visitJoin(joinNode: JoinNode): string[] { + this.visitingJoin = true; + return [...this.visit(joinNode.from), `${joinNode.subType} JOIN`, ...this.visit(joinNode.to), 'ON', ...this.visit(joinNode.onNode)]; + } + public visitLiteral(literalNode: LiteralNode): string[] { + const txt = [literalNode.literal]; + if (literalNode.alias) { + txt.push(this.aliasText + this.quote(literalNode.alias)); + } + return [txt.join('')]; + } + public visitText(textNode: TextNode): string[] { + return [textNode.text]; + } + public visitReturning(returningNode: ReturningNode): string[] { + this.visitingReturning = true; + const r = ['RETURNING', returningNode.nodes.map(this.visit.bind(this)).join(', ')]; + this.visitingReturning = false; + return r; + } + public visitOnDuplicate(onDuplicateNode: OnDuplicateNode): string[] { + throw new Error('PostgreSQL does not allow onDuplicate clause.'); + } + public visitOnConflict(onConflictNode: OnConflictNode): string[] { + const result = ['ON CONFLICT']; + const columns = []; + const updateClause = []; + let i; + let col; + const table = this.queryNode!.table; + if (onConflictNode.constraint) { + result.push(['ON CONSTRAINT', this.quote(onConflictNode.constraint)].join(' ')); + } else if (onConflictNode.columns) { + for (i = 0; i < onConflictNode.columns.length; i++) { + columns.push(this.quote(table.getColumn(onConflictNode.columns[i])!.name)); + } + result.push('(' + columns.join(', ') + ')'); + if (onConflictNode.where) { + result.push('WHERE', ...this.visit(onConflictNode.where)); + } + } + if (onConflictNode.update) { + updateClause.push('DO UPDATE SET'); + const update = onConflictNode.update; + const setClause = []; + for (i = 0; i < update.length; i++) { + col = this.quote(table.getColumn(update[i])!.name); + setClause.push(col + ' = EXCLUDED.' + col); + } + updateClause.push(setClause.join(', ')); + } else { + updateClause.push('DO NOTHING'); + } + result.push(updateClause.join(' ')); + return result; + } + public visitModifier(modifierNode: ModifierNode): string[] { + return [modifierNode.type, ...this.visit(modifierNode.count)]; + } + public visitIndexes(indexesNode: IndexesNode): string[] { + /* jshint unused: false */ + const tableName = this.queryNode!.table.getName(); + const schemaName = this.queryNode!.table.getSchema() || 'public'; + return [ + 'SELECT relname', + 'FROM pg_class', + 'WHERE oid IN (', + 'SELECT indexrelid', + `FROM pg_index, pg_class WHERE pg_class.relname='${tableName}'`, + `AND pg_class.relnamespace IN (SELECT pg_namespace.oid FROM pg_namespace WHERE nspname = '${schemaName}')`, + 'AND pg_class.oid=pg_index.indrelid)' + ]; + } + + protected notEmpty(t: T | undefined): t is T { + return t !== undefined + } + + protected _visitCreateIndex(createIndexNode: CreateIndexNode) { + if (!createIndexNode.options.columns || createIndexNode.options.columns.length === 0) { + throw new Error('No columns defined!'); + } + const tableName = this.visit(createIndexNode.table.toNode()); + const ifNotExists = createIndexNode.options?.ifNotExists ? this.visitIfNotExistsIndex() : []; + const indexType = createIndexNode.options?.type?.toUpperCase(); + const indexName = this.quote(createIndexNode.indexName()); + const algorithm = createIndexNode.options.algorithm ? 'USING ' + createIndexNode.options.algorithm.toUpperCase() : undefined; + const columns = '(' + createIndexNode.options.columns.reduce((res, col) => { + const column = col.name ? col.name : col.value.name; + const direction = col instanceof OrderByValueNode ? ` ${col.direction!.text}` : ''; + return res.concat(this.quote(column) + direction); + }, []) + ')'; + const parser = createIndexNode.options.parser ? 'WITH PARSER ' + createIndexNode.options.parser : undefined; + + return { indexType, ifNotExists, indexName, tableName, algorithm, columns, parser }; + } + + public visitCreateIndex(createIndexNode: CreateIndexNode): string[] { + const { indexType, ifNotExists, indexName, tableName, algorithm, columns, parser } = this._visitCreateIndex(createIndexNode); + + return [ + 'CREATE', + indexType, + 'INDEX', + ...ifNotExists, + indexName, + 'ON', + ...tableName, + algorithm, + columns, + parser + ].filter(this.notEmpty); + } + public visitIfNotExistsIndex(): string[] { + return ['IF NOT EXISTS'] + } + public visitDropIndex(dropIndexNode: DropIndexNode): string[] { + const ifExists = dropIndexNode.options.ifExists ? this.visitIfExistsIndex() : [] + return [ + 'DROP INDEX', + ...ifExists, + this.quote(dropIndexNode.table.getSchema() || 'public') + '.' + this.quote(dropIndexNode.options.indexName), + ] + } + public visitIfExistsIndex(): string[] { + return ['IF EXISTS'] + } + public visitCreateView(createViewNode: CreateViewNode): string[] { + const result = ['CREATE VIEW', this.quote(createViewNode.options.viewName), 'AS']; + return result; + } + public visitInterval(intervalNode: IntervalNode): string[] { + let parameter = ''; + const add = (n: number, unit: string) => { + if (!isNumber(n)) { + return; + } + if (parameter !== '') { + parameter += ' '; + } + parameter += `${n} ${unit}`; + }; + add(intervalNode.years, 'YEAR'); + add(intervalNode.months, 'MONTH'); + add(intervalNode.days, 'DAY'); + add(intervalNode.hours, 'HOUR'); + add(intervalNode.minutes, 'MINUTE'); + add(intervalNode.seconds, 'SECOND'); + if (parameter === '') { + parameter = '0 SECOND'; + } + return [`INTERVAL '${parameter}'`]; + } + /** + * Broken out as a separate function so that dialects that derive from this class can still use this functionality. + * + * @param {Node[]} list + * @param {String} type + * @returns {Object|undefined} {index:number, node:Node} + */ + public findNode(list: Node[], type: string) { + for (let i = 0, len = list.length; i < len; i++) { + const n = list[i]; + if (n.type === type) { + return { index: i, node: n }; + } + } + return undefined; + } + /** + * pulls the DISTINCT node out of the filters and flags the SELECT node that it should be distinct. + * Broken out as a separate function so that dialects that derive from this class can still use this functionality. + */ + public handleDistinct(actions: Node[], filters: Node[]) { + const distinctNode = this.findNode(filters, 'DISTINCT'); + // if (!distinctNode) distinctNode = _findNode(targets,"DISTINCT"); + // if (!distinctNode) distinctNode = _findNode(actions,"DISTINCT"); + if (!distinctNode) { + return; + } + const selectInfo = this.findNode(actions, 'SELECT'); + if (!selectInfo) { + return; + } // there should be one by now, I think + // mark the SELECT node that it's distinct + (selectInfo.node as SelectNode).isDistinct = true; + } +} + +/** + * If the parent of the subquery is an INSERT we don't want to parenthesize. + * This happens when you create the query like so: + * + * const query=post.insert(post.id) + * const select=user.select(user.id) + * query.add(select) + * + * @param parentQuery + * @returns {boolean} + */ +const dontParenthesizeSubQuery = (parentQuery: Query) => { + if (!parentQuery) { + return false; + } + if (parentQuery.nodes.length === 0) { + return false; + } + if (['INSERT', 'REPLACE'].indexOf(parentQuery.nodes[0].type) === -1) { + return false; + } + return true; +} diff --git a/lib/dialect/index.js b/lib/dialect/index.js deleted file mode 100644 index c26f15de..00000000 --- a/lib/dialect/index.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; - -// given a dialect name, return the class -var getDialect = function(dialect) { - switch (dialect.toLowerCase()) { - case 'postgres': - return require('./postgres'); - case 'mysql': - return require('./mysql'); - case 'sqlite': - return require('./sqlite'); - case 'mssql': - return require('./mssql'); - case 'oracle': - return require('./oracle'); - default: - throw new Error(dialect + ' is unsupported'); - } -}; - -module.exports = getDialect; diff --git a/lib/dialect/mapper.ts b/lib/dialect/mapper.ts new file mode 100644 index 00000000..30a09d8e --- /dev/null +++ b/lib/dialect/mapper.ts @@ -0,0 +1,20 @@ +import type { Dialect } from './dialect.js'; + +const dialects = new Map Dialect>(); + +export const registerDialect = (dialect: string, ctor: new (...args: any[]) => Dialect) => { + dialects.set(dialect, ctor); +} + +// given a dialect name, return the class +export const getDialect = (dialect: string): new (...args: any[]) => Dialect => { + const foundDialect = dialects.get(dialect.toLowerCase()); + if (foundDialect == null) { + throw new Error(dialect + ' is unsupported'); + } else { + return foundDialect; + } +}; + +// default dialect is postgres +export const DEFAULT_DIALECT = 'postgres'; \ No newline at end of file diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js deleted file mode 100644 index 488f7fa2..00000000 --- a/lib/dialect/mssql.js +++ /dev/null @@ -1,467 +0,0 @@ -// TODO: visitCreate needs to support schemas -// TODO: visitDrop needs to support schemas - -'use strict'; - -var util = require('util'); -var assert = require('assert'); - -/** - * Config can contain: - * - * questionMarkParameterPlaceholder:true which will use a "?" for the parameter placeholder instead of the @index. - * - * @param config - * @constructor - */ -var Mssql = function(config) { - this.output = []; - this.params = []; - this.config = config || {}; -}; - -var Postgres = require('./postgres'); - -util.inherits(Mssql, Postgres); - -Mssql.prototype._myClass = Mssql; - -Mssql.prototype._quoteCharacter = '['; - -Mssql.prototype._arrayAggFunctionName = ''; - -Mssql.prototype.visitReplace = function(replace) { - throw new Error('Mssql does not support REPLACE.'); -}; - -Mssql.prototype._getParameterPlaceholder = function(index, value) { - if (this.config.questionMarkParameterPlaceholder) return '?'; - return '@' + index; -}; - -Mssql.prototype.visitBinary = function(binary) { - if(binary.operator === '@@'){ - var self = this; - var text = '(CONTAINS (' + this.visit(binary.left) + ', '; - text += this.visit(binary.right); - text += '))'; - return [text]; - } - - if (!isRightSideArray(binary)){ - return Mssql.super_.prototype.visitBinary.call(this, binary); - } - if (binary.operator=='IN' || binary.operator=='NOT IN'){ - return Mssql.super_.prototype.visitBinary.call(this, binary); - } - throw new Error('SQL Sever does not support arrays in this type of expression.'); -}; - -Mssql.prototype.visitAlter = function(alter) { - var self=this; - var errMsg='ALTER TABLE cannot be used to perform multiple different operations in the same statement.'; - - // Implement our own add column: - // PostgreSQL: ALTER TABLE "name" ADD COLUMN "col1", ADD COLUMN "col2" - // Mssql: ALTER TABLE [name] ADD [col1], [col2] - function _addColumn(){ - self._visitingAlter = true; - var table = self._queryNode.table; - self._visitingAddColumn = true; - var result='ALTER TABLE '+self.visit(table.toNode())+' ADD '+self.visit(alter.nodes[0].nodes[0]); - for (var i= 1,len=alter.nodes.length; i= 0) txt = _extract(); - // Override CURRENT_TIMESTAMP function to remove parens - else if ('CURRENT_TIMESTAMP' == functionCall.name) txt = functionCall.name; - else { - var name = functionCall.name; - // override the LENGTH function since mssql calls it LEN - if (name == "LENGTH") name = "LEN"; - txt = name + '(' + functionCall.nodes.map(this.visit.bind(this)).join(', ') + ')'; - } - this._visitingFunctionCall = false; - return [txt]; -}; - -Mssql.prototype.visitOrderBy = function(orderBy) { - var result=Mssql.super_.prototype.visitOrderBy.call(this, orderBy); - var offsetNode=orderBy.msSQLOffsetNode; - var limitNode=orderBy.msSQLLimitNode; - if (!offsetNode && !limitNode) return result; - assert(offsetNode,"Something bad happened, should have had an msSQLOffsetNode here."); - result.push("OFFSET "+getModifierValue(this,offsetNode)+" ROWS"); - if (!limitNode) return result; - result.push("FETCH NEXT "+getModifierValue(this,limitNode)+" ROWS ONLY"); - return result; -}; - -/** - * We override this so that we can deal with the LIMIT and OFFSET clauses specially since they have to become - * part of the SELECT and ORDER BY clauses. - * - * Basically if there's an ORDER BY clause we attach OFFSET and LIMIT to it so that it can be processed by the - * ORDER BY handler later. - * - * If there's a LIMIT clause without OFFSET, we attach it to the SELECT clause so we can process it later. - * - * @param {Node[]} actions - * @param {Node[]} targets - * @param {Node[]} filters - * @returns {String[]} - */ -Mssql.prototype.visitQueryHelper=function(actions,targets,filters){ - function _handleLimitAndOffset(){ - var limitInfo=Mssql.super_.prototype.findNode.call(this, filters, "LIMIT"); // jshint ignore:line - var offsetInfo=Mssql.super_.prototype.findNode.call(this, filters, "OFFSET"); // jshint ignore:line - var orderByInfo=Mssql.super_.prototype.findNode.call(this, filters, "ORDER BY"); // jshint ignore:line - - // no OFFSET or LIMIT then there's nothing special to do - if (!offsetInfo && !limitInfo) return; - // ORDER BY with OFFSET we have work to do, may consume LIMIT as well - if (orderByInfo && offsetInfo) _processOrderByOffsetLimit(orderByInfo,offsetInfo,limitInfo); - else if (offsetInfo) throw new Error("MS SQL Server does not allow OFFSET without ORDER BY"); - else if (limitInfo) _processLimit(limitInfo); - } - - /** - * We need to turn LIMIT into a TOP clause on the SELECT STATEMENT - * - * @param limitInfo - * @private - */ - function _processLimit(limitInfo){ - var selectInfo=Mssql.super_.prototype.findNode.call(this, actions, "SELECT"); // jshint ignore:line - assert(selectInfo!==undefined,"MS SQL Server requires a SELECT clause when using LIMIT"); - // save the LIMIT node with the SELECT node - selectInfo.node.msSQLLimitNode=limitInfo.node; - // remove the LIMIT node from the filters so it doesn't get processed later. - filters.splice(limitInfo.index,1); - } - - /** - * We need to turn LIMIT into a TOP clause on the SELECT STATEMENT - * - * @param orderByInfo - * @param offsetInfo - * @param limitInfo - * @private - */ - function _processOrderByOffsetLimit(orderByInfo,offsetInfo,limitInfo){ - // save the OFFSET AND LIMIT nodes with the ORDER BY node - orderByInfo.node.msSQLOffsetNode=offsetInfo.node; - if (limitInfo) orderByInfo.node.msSQLLimitNode=limitInfo.node; - // remove the OFFSET and LIMIT nodes from the filters so they don't get processed later. - filters.splice(offsetInfo.index,1); - if (limitInfo) filters.splice(limitInfo.index,1); - } - - // MAIN - - Mssql.super_.prototype.handleDistinct.call(this, actions, filters); - _handleLimitAndOffset(); - - // lazy-man sorting - var sortedNodes = actions.concat(targets).concat(filters); - for(var i = 0; i < sortedNodes.length; i++) { - var res = this.visit(sortedNodes[i]); - this.output = this.output.concat(res); - } - return this.output; -}; - -//Mysql.prototype.visitRenameColumn = function(renameColumn) { -// var dataType = renameColumn.nodes[1].dataType || renameColumn.nodes[0].dataType; -// assert(dataType, 'dataType missing for column ' + (renameColumn.nodes[1].name || renameColumn.nodes[0].name || '') + -// ' (CHANGE COLUMN statements require a dataType)'); -// return ['CHANGE COLUMN ' + this.visit(renameColumn.nodes[0]) + ' ' + this.visit(renameColumn.nodes[1]) + ' ' + dataType]; -//}; -// -//Mysql.prototype.visitInsert = function(insert) { -// var result = Postgres.prototype.visitInsert.call(this, insert); -// if (result[2] === 'DEFAULT VALUES') { -// result[2] = '() VALUES ()'; -// } -// return result; -//}; -// -//Mysql.prototype.visitIndexes = function(node) { -// var tableName = this.visit(this._queryNode.table.toNode()); -// -// return "SHOW INDEX FROM " + tableName; -//}; - -Mssql.prototype.visitOnDuplicate = function(onDuplicate) { - throw new Error('MSSQL does not allow onDuplicate clause.'); -}; - -Mssql.prototype.visitOnConflict = function(onConflict) { - throw new Error('MSSQL does not allow onConflict clause.'); -}; - -Mssql.prototype.visitReturning = function() { - // TODO: need to add some code to the INSERT clause to support this since its the equivalent of the OUTPUT clause - // in MS SQL which appears before the values, not at the end of the statement. - throw new Error('Returning clause is not yet supported for MS SQL.'); -}; - -// We deal with SELECT specially so we can add the TOP clause if needed -Mssql.prototype.visitSelect = function(select) { - if (!select.msSQLLimitNode) return Mssql.super_.prototype.visitSelect.call(this, select); - var result=[ - 'SELECT', - 'TOP('+getModifierValue(this,select.msSQLLimitNode)+')', - select.nodes.map(this.visit.bind(this)).join(', ') - ]; - this._selectOrDeleteEndIndex = this.output.length + result.length; - return result; -}; - -// Node is either an OFFSET or LIMIT node -function getModifierValue(dialect,node){ - return node.count.type ? dialect.visit(node.count) : node.count; -} - -function isAlterAddColumn(alter){ - if (alter.nodes.length===0) return false; - if (alter.nodes[0].type!='ADD COLUMN') return false; - return true; -} - -function isAlterDropColumn(alter){ - if (alter.nodes.length===0) return false; - if (alter.nodes[0].type!='DROP COLUMN') return false; - return true; -} - -function isAlterRename(alter){ - if (alter.nodes.length===0) return false; - if (alter.nodes[0].type!='RENAME') return false; - return true; -} - -function isAlterRenameColumn(alter){ - if (alter.nodes.length===0) return false; - if (alter.nodes[0].type!='RENAME COLUMN') return false; - return true; -} - -function isCountStarExpression(columnNode){ - if (!columnNode.aggregator) return false; - if (columnNode.aggregator.toLowerCase()!='count') return false; - if (!columnNode.star) return false; - return true; -} - -function isCreateIfNotExists(create){ - if (create.nodes.length===0) return false; - if (create.nodes[0].type!='IF NOT EXISTS') return false; - return true; -} - -function isCreateTemporary(create){ - return create.options.isTemporary; -} - -function isDropIfExists(drop){ - if (drop.nodes.length===0) return false; - if (drop.nodes[0].type!='IF EXISTS') return false; - return true; -} - -// SQL Server does not support array expressions except in the IN clause. -function isRightSideArray(binary){ - return Array.isArray(binary.right); -} - -module.exports = Mssql; diff --git a/lib/dialect/mssql.ts b/lib/dialect/mssql.ts new file mode 100644 index 00000000..5e4cdf94 --- /dev/null +++ b/lib/dialect/mssql.ts @@ -0,0 +1,515 @@ +// TODO: visitCreate needs to support schemas +// TODO: visitDrop needs to support schemas + +import assert from 'assert'; + +import { AlterNode } from '../node/alter.js'; +import { AsOfNode } from '../node/asOf.js'; +import { BinaryNode } from '../node/binary.js'; +import { CaseNode } from '../node/case.js'; +import { ColumnNode } from '../node/column.js'; +import { CreateNode } from '../node/create.js'; +import { CreateIndexNode } from '../node/createIndex.js'; +import { DropNode } from '../node/drop.js'; +import { FunctionCallNode } from '../node/functionCall.js'; +import { ModifierNode } from '../node/modifier.js'; +import { Node } from '../node/node.js'; +import { OnConflictNode } from '../node/onConflict.js'; +import { OnDuplicateNode } from '../node/onDuplicate.js'; +import { OrderByNode } from '../node/orderBy.js'; +import { ParameterNode } from '../node/parameter.js'; +import { ReplaceNode } from '../node/replace.js'; +import { ReturningNode } from '../node/returning.js'; +import { SelectNode } from '../node/select.js'; +import { Dialect } from './dialect.js'; + +/** + * Config can contain: + * + * questionMarkParameterPlaceholder:true which will use a "?" for the parameter placeholder instead of the @index. + * + * @param config + * @constructor + */ +export class Mssql extends Dialect<{ questionMarkParameterPlaceholder?: boolean }> { + constructor(config: { questionMarkParameterPlaceholder?: boolean }) { + super(config); + this.quoteCharacter = '[' + this.arrayAggFunctionName = ''; + } + + protected createSubInstance() { + return new Mssql(this.config); + } + + public _getParameterPlaceholder(index: string | number, value: any): string { + if (this.config.questionMarkParameterPlaceholder) { + return '?'; + } + return `@${index}`; + } + public visitAsOf(asOfNode: AsOfNode): string[] { + throw new Error('Mssql does not support AS OF.'); + } + public visitReplace(replaceNode: ReplaceNode): string[] { + throw new Error('Mssql does not support REPLACE.'); + } + public visitBinary(binaryNode: BinaryNode): string[] { + if (binaryNode.operator === '@@' && !Array.isArray(binaryNode.right)) { + return [`(CONTAINS (${this.visit(binaryNode.left)}, ${this.visit(binaryNode.right as Node)}))`]; + } + if (!Array.isArray(binaryNode.right)) { + return super.visitBinary(binaryNode); + } + if (binaryNode.operator === 'IN' || binaryNode.operator === 'NOT IN') { + return super.visitBinary(binaryNode); + } + throw new Error('SQL Sever does not support arrays in this type of expression.'); + } + public visitAlter(alterNode: AlterNode): string[] { + const errMsg = 'ALTER TABLE cannot be used to perform multiple different operations in the same statement.'; + // Implement our own add column: + // PostgreSQL: ALTER TABLE "name" ADD COLUMN "col1", ADD COLUMN "col2" + // Mssql: ALTER TABLE [name] ADD [col1], [col2] + const addColumn = () => { + this.visitingAlter = true; + const table = this.queryNode!.table; + this.visitingAddColumn = true; + let result = `ALTER TABLE ${this.visit(table.toNode())} ADD ${this.visit(alterNode.nodes[0].nodes[0])}`; + for (let i = 1, len = alterNode.nodes.length; i < len; i++) { + const node = alterNode.nodes[i]; + assert(node.type === 'ADD COLUMN', errMsg); + result += `, ${this.visit(node.nodes[0])}`; + } + this.visitingAddColumn = false; + this.visitingAlter = false; + return [result]; + }; + // Implement our own drop column: + // PostgreSQL: ALTER TABLE "name" DROP COLUMN "col1", DROP COLUMN "col2" + // Mssql: ALTER TABLE [name] DROP COLUMN [col1], [col2] + const dropColumn = () => { + this.visitingAlter = true; + const table = this.queryNode!.table; + const result = ['ALTER TABLE', ...this.visit(table.toNode())]; + let columns = `DROP COLUMN ${this.visit(alterNode.nodes[0].nodes[0])}`; + for (let i = 1, len = alterNode.nodes.length; i < len; i++) { + const node = alterNode.nodes[i]; + assert(node.type === 'DROP COLUMN', errMsg); + columns += `, ${this.visit(node.nodes[0])}`; + } + result.push(columns); + this.visitingAlter = false; + return result; + }; + // Implement our own rename table: + // PostgreSQL: ALTER TABLE "post" RENAME TO "posts" + // Mssql: EXEC sp_rename [post], [posts] + const rename = () => { + this.visitingAlter = true; + const table = this.queryNode!.table; + const result = ['EXEC sp_rename ' + this.visit(table.toNode()) + ', ' + this.visit(alterNode.nodes[0].nodes[0])]; + this.visitingAlter = false; + return result; + }; + // Implement our own rename column: + // PostgreSQL: ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId" + // Mssql: EXEC sp_rename '[group].[userId]', [newUserId] + const renameColumn = () => { + this.visitingAlter = true; + const table = this.queryNode!.table; + const result = [ + `EXEC sp_rename '${this.visit(table.toNode())}.${this.visit(alterNode.nodes[0].nodes[0])}', ${this.visit( + alterNode.nodes[0].nodes[1] + )}, 'COLUMN'` + ]; + this.visitingAlter = false; + return result; + }; + if (isAlterAddColumn(alterNode)) { + return addColumn(); + } + if (isAlterDropColumn(alterNode)) { + return dropColumn(); + } + if (isAlterRename(alterNode)) { + return rename(); + } + if (isAlterRenameColumn(alterNode)) { + return renameColumn(); + } + return super.visitAlter(alterNode); + } + // Need to implement a special version of CASE since SQL doesn't support + // CASE WHEN true THEN xxx END + // the "true" has to be a boolean expression like 1=1 + public visitCase(caseNode: CaseNode): string[] { + const whenValue = (node: Node) => { + if (node.type !== 'PARAMETER') { + return this.visit(node); + } + // dealing with a true/false value + const val = (node as ParameterNode).value(); + return val === true ? '1=1' : '0=1'; + }; + assert(caseNode.whenList.length === caseNode.thenList.length); + let text = '(CASE'; + this.visitingCase = true; + for (let i = 0; i < caseNode.whenList.length; i++) { + text += ` WHEN ${whenValue(caseNode.whenList[i])} THEN ${this.visit(caseNode.thenList[i])}`; + } + if (caseNode.else != null) { + text += ` ELSE ${this.visit(caseNode.else)}`; + } + this.visitingCase = false; + text += ' END)'; + return [text]; + } + public visitColumn(columnNode: ColumnNode): string[] { + let inSelectClause: boolean = false; + const table = columnNode.table; + inSelectClause = !this.selectOrDeleteEndIndex; + const arrayAgg = () => { + throw new Error('SQL Server does not support array_agg.'); + }; + const countStar = () => { + // Implement our own since count(table.*) is invalid in Mssql + let result = 'COUNT(*)'; + if (inSelectClause && columnNode.alias) { + result += ` AS ${this.quote(columnNode.alias)}`; + } + return result; + }; + if (isCountStarExpression(columnNode)) { + return [countStar()]; + } + if (inSelectClause && table && !table.alias && columnNode.asArray) { + return arrayAgg(); + } + return super.visitColumn(columnNode); + } + public visitCreate(createNode: CreateNode): string[] { + const isNotExists = isCreateIfNotExists(createNode); + const isTemporary = isCreateTemporary(createNode); + if (!isNotExists && !isTemporary) { + return super.visitCreate(createNode); + } + // Implement our own create if not exists: + // PostgreSQL: CREATE TABLE IF NOT EXISTS "group" ("id" constchar(100)) + // Mssql: IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'group') BEGIN ... END + const table = this.queryNode!.table; + const colNodes = table.columns.map((col) => col.toNode()); + const tableResult = this.visit(table.toNode()); + this.visitingCreate = true; + const createResult = ['CREATE TABLE']; + createResult.push(...tableResult); + createResult.push(`(${colNodes.map(this.visit.bind(this)).join(', ')})`); + this.visitingCreate = false; + let tableStr = tableResult.join(' '); + tableStr = tableStr.replace(/'/g, "''"); + tableStr = `'${tableStr.substring(1, tableStr.length - 1)}'`; + const whereClause = `WHERE TABLE_NAME = ${tableStr}`; + // TODO: need to add schema check, sudo code: + // if (schema) { whereClause+=' AND TABLE_SCHEMA = schemaResult.join(' ')} + // Add some tests for this as well + if (!isNotExists) { + return createResult; + } + return [`IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES ${whereClause}) BEGIN ${createResult.join(' ')} END`]; + } + public visitDrop(dropNode: DropNode): string[] { + if (!isDropIfExists(dropNode)) { + return super.visitDrop(dropNode); + } + // Implement our own drop if exists: + // PostgreSQL: DROP TABLE IF EXISTS "group" + // Mssql: IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = [group]) BEGIN ... END + const table = this.queryNode!.table; + const tableResult = this.visit(table.toNode()); + const dropResult = ['DROP TABLE']; + dropResult.push(...tableResult); + const whereClause = `WHERE TABLE_NAME = ${tableResult.join(' ')}`; + // TODO: need to add schema check, sudo code: + // if (schema) { whereClause+=' AND TABLE_SCHEMA = schemaResult.join(' ')} + // Add some tests for this as well + return [`IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES ${whereClause}) BEGIN ${dropResult.join(' ')} END`]; + } + public visitFunctionCall(functionCallNode: FunctionCallNode): string[] { + this.visitingFunctionCall = true; + const extract = () => { + const nodes = functionCallNode.nodes.map(this.visit.bind(this)); + if (nodes.length !== 1) { + throw new Error(`Not enough parameters passed to ${functionCallNode.name} function`); + } + return `DATEPART(${functionCallNode.name.toLowerCase()}, ${nodes[0] + ''})`; + }; + let txt; + // Override date functions since mssql uses datepart + if (['YEAR', 'MONTH', 'DAY', 'HOUR'].indexOf(functionCallNode.name) >= 0) { + txt = extract(); + } + // Override CURRENT_TIMESTAMP function to remove parens + else if ('CURRENT_TIMESTAMP' === functionCallNode.name) { + txt = functionCallNode.name; + } else { + let name = functionCallNode.name; + // override the LENGTH function since mssql calls it LEN + if (name === 'LENGTH') { + name = 'LEN'; + } + txt = `${name}(${functionCallNode.nodes.map(this.visit.bind(this)).join(', ')})`; + } + this.visitingFunctionCall = false; + return [txt]; + } + public visitOrderBy(orderByNode: OrderByNode): string[] { + const result = super.visitOrderBy(orderByNode); + const offsetNode = orderByNode.msSQLOffsetNode; + const limitNode = orderByNode.msSQLLimitNode; + if (!offsetNode && !limitNode) { + return result; + } + assert(offsetNode, 'Something bad happened, should have had an msSQLOffsetNode here.'); + result.push('OFFSET ' + getModifierValue(this, offsetNode!) + ' ROWS'); + if (!limitNode) { + return result; + } + result.push('FETCH NEXT ' + getModifierValue(this, limitNode) + ' ROWS ONLY'); + return result; + } + /** + * We override this so that we can deal with the LIMIT and OFFSET clauses specially since they have to become + * part of the SELECT and ORDER BY clauses. + * + * Basically if there's an ORDER BY clause we attach OFFSET and LIMIT to it so that it can be processed by the + * ORDER BY handler later. + * + * If there's a LIMIT clause without OFFSET, we attach it to the SELECT clause so we can process it later. + * + * @param {Node[]} actions + * @param {Node[]} targets + * @param {Node[]} filters + * @returns {String[]} + */ + public visitQueryHelper(actions: Node[], targets: Node[], filters: Node[]): string[] { + const handleLimitAndOffset = () => { + const limitInfo = super.findNode(filters, 'LIMIT'); + const offsetInfo = super.findNode(filters, 'OFFSET'); + const orderByInfo = super.findNode(filters, 'ORDER BY'); + // no OFFSET or LIMIT then there's nothing special to do + if (!offsetInfo && !limitInfo) { + return; + } + // ORDER BY with OFFSET we have work to do, may consume LIMIT as well + if (orderByInfo && offsetInfo) { + processOrderByOffsetLimit(orderByInfo, offsetInfo, limitInfo); + } else if (offsetInfo) { + throw new Error('MS SQL Server does not allow OFFSET without ORDER BY'); + } else if (limitInfo) { + processLimit(limitInfo); + } + }; + /** + * We need to turn LIMIT into a TOP clause on the SELECT STATEMENT + * + * @param limitInfo + * @private + */ + const processLimit = (limitInfo: { index: number; node: Node }) => { + const selectInfo = super.findNode(actions, 'SELECT'); + assert(selectInfo !== undefined, 'MS SQL Server requires a SELECT clause when using LIMIT'); + // save the LIMIT node with the SELECT node + (selectInfo!.node as SelectNode).msSQLLimitNode = limitInfo.node as ModifierNode; + // remove the LIMIT node from the filters so it doesn't get processed later. + filters.splice(limitInfo.index, 1); + }; + /** + * We need to turn LIMIT into a TOP clause on the SELECT STATEMENT + * + * @param orderByInfo + * @param offsetInfo + * @param limitInfo + * @private + */ + const processOrderByOffsetLimit = ( + orderByInfo: { + index: number; + node: Node; + }, + offsetInfo: { + index: number; + node: Node; + }, + limitInfo?: { + index: number; + node: Node; + } + ) => { + // save the OFFSET AND LIMIT nodes with the ORDER BY node + (orderByInfo.node as OrderByNode).msSQLOffsetNode = offsetInfo.node as ModifierNode; + if (limitInfo) { + (orderByInfo.node as OrderByNode).msSQLLimitNode = limitInfo.node as ModifierNode; + } + // remove the OFFSET and LIMIT nodes from the filters so they don't get processed later. + filters.splice(offsetInfo.index, 1); + if (limitInfo) { + filters.splice(limitInfo.index, 1); + } + }; + // MAIN + super.handleDistinct(actions, filters); + handleLimitAndOffset(); + // lazy-man sorting + const sortedNodes = actions.concat(targets).concat(filters); + for (const node of sortedNodes) { + const res = this.visit(node); + this.output = this.output.concat(res); + } + return this.output; + } + // Mysql.prototype.visitRenameColumn = function(renameColumn) { + // const dataType = renameColumn.nodes[1].dataType || renameColumn.nodes[0].dataType; + // assert(dataType, 'dataType missing for column ' + (renameColumn.nodes[1].name || renameColumn.nodes[0].name || '') + + // ' (CHANGE COLUMN statements require a dataType)'); + // return ['CHANGE COLUMN ' + this.visit(renameColumn.nodes[0]) + ' ' + this.visit(renameColumn.nodes[1]) + ' ' + dataType]; + // }; + // + // Mysql.prototype.visitInsert = function(insert) { + // const result = Postgres.prototype.visitInsert.call(this, insert); + // if (result[2] === 'DEFAULT VALUES') { + // result[2] = '() VALUES ()'; + // } + // return result; + // }; + // + // Mysql.prototype.visitIndexes = function(node) { + // const tableName = this.visit(this._queryNode.table.toNode()); + // + // return "SHOW INDEX FROM " + tableName; + // }; + public visitCreateIndex(createIndexNode: CreateIndexNode): string[] { + const { indexType, ifNotExists, indexName, tableName, algorithm, columns, parser } = this._visitCreateIndex(createIndexNode); + + return [ + 'CREATE', + indexType, + 'INDEX', + ...ifNotExists, + indexName, + algorithm, + 'ON', + ...tableName, + columns, + parser + ].filter(this.notEmpty); + } + public visitIfNotExistsIndex(): string[] { + throw new Error('MSSQL does not allow ifNotExists clause on indexes.'); + } + public visitOnDuplicate(onDuplicateNode: OnDuplicateNode): string[] { + throw new Error('MSSQL does not allow onDuplicate clause.'); + } + public visitOnConflict(onConflictNode: OnConflictNode): string[] { + throw new Error('MSSQL does not allow onConflict clause.'); + } + public visitReturning(returningNode: ReturningNode): string[] { + // TODO: need to add some code to the INSERT clause to support this since its the equivalent of the OUTPUT clause + // in MS SQL which appears before the values, not at the end of the statement. + throw new Error('Returning clause is not yet supported for MS SQL.'); + } + // We deal with SELECT specially so we can add the TOP clause if needed + public visitSelect(selectNode: SelectNode): string[] { + if (!selectNode.msSQLLimitNode) { + return super.visitSelect(selectNode); + } + const result = [ + 'SELECT', + 'TOP(' + getModifierValue(this, selectNode.msSQLLimitNode) + ')', + selectNode.nodes.map(this.visit.bind(this)).join(', ') + ]; + this.selectOrDeleteEndIndex = this.output.length + result.length; + return result; + } +} + +// Node is either an OFFSET or LIMIT node +const getModifierValue = (dialect: Mssql, node: ModifierNode) => { + return node.count.type ? dialect.visit(node.count) : node.count; +} + +const isAlterAddColumn = (alterNode: AlterNode) => { + if (alterNode.nodes.length === 0) { + return false; + } + if (alterNode.nodes[0].type !== 'ADD COLUMN') { + return false; + } + return true; +} + +const isAlterDropColumn = (alterNode: AlterNode) => { + if (alterNode.nodes.length === 0) { + return false; + } + if (alterNode.nodes[0].type !== 'DROP COLUMN') { + return false; + } + return true; +} + +const isAlterRename = (alterNode: AlterNode) => { + if (alterNode.nodes.length === 0) { + return false; + } + if (alterNode.nodes[0].type !== 'RENAME') { + return false; + } + return true; +} + +const isAlterRenameColumn = (alterNode: AlterNode) => { + if (alterNode.nodes.length === 0) { + return false; + } + if (alterNode.nodes[0].type !== 'RENAME COLUMN') { + return false; + } + return true; +} + +const isCountStarExpression = (columnNode: ColumnNode) => { + if (!columnNode.aggregator) { + return false; + } + if (columnNode.aggregator.toLowerCase() !== 'count') { + return false; + } + if (!columnNode.star) { + return false; + } + return true; +} + +const isCreateIfNotExists = (createNode: CreateNode) => { + if (createNode.nodes.length === 0) { + return false; + } + if (createNode.nodes[0].type !== 'IF NOT EXISTS') { + return false; + } + return true; +} + +const isCreateTemporary = (createNode: CreateNode) => { + return createNode.options.isTemporary; +} + +const isDropIfExists = (dropNode: DropNode) => { + if (dropNode.nodes.length === 0) { + return false; + } + if (dropNode.nodes[0].type !== 'IF EXISTS') { + return false; + } + return true; +} diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js deleted file mode 100644 index 0a63f3be..00000000 --- a/lib/dialect/mysql.js +++ /dev/null @@ -1,221 +0,0 @@ -'use strict'; - -var util = require('util'); -var assert = require('assert'); -var _ = require('lodash'); - -var Mysql = function(config) { - this.output = []; - this.params = []; - this.config = config || {}; -}; - -var Postgres = require('./postgres'); - -util.inherits(Mysql, Postgres); - -Mysql.prototype._myClass = Mysql; - -Mysql.prototype._quoteCharacter = '`'; - -Mysql.prototype._arrayAggFunctionName = 'GROUP_CONCAT'; - -Mysql.prototype.visitReplace = function(replace) { - var self = this; - // don't use table.column for replaces - this._visitedReplace = true; - - var result = ['REPLACE']; - result = result.concat(replace.nodes.map(this.visit.bind(this))); - result.push('INTO ' + this.visit(this._queryNode.table.toNode())); - result.push('(' + replace.columns.map(this.visit.bind(this)).join(', ') + ')'); - - var paramNodes = replace.getParameters(); - - if (paramNodes.length > 0) { - var paramText = paramNodes.map(function (paramSet) { - return paramSet.map(function (param) { - return self.visit(param); - }).join(', '); - }).map(function (param) { - return '('+param+')'; - }).join(', '); - - result.push('VALUES', paramText); - - if (result.slice(2, 5).join(' ') === '() VALUES ()') { - result.splice(2, 3, 'DEFAULT VALUES'); - } - } - - this._visitedReplace = false; - - if (result[2] === 'DEFAULT VALUES') { - result[2] = '() VALUES ()'; - } - return result; -}; - -Mysql.prototype._getParameterPlaceholder = function() { - return '?'; -}; - -Mysql.prototype._getParameterValue = function(value) { - if (Buffer.isBuffer(value)) { - value = 'x' + this._getParameterValue(value.toString('hex')); - } else { - value = Postgres.prototype._getParameterValue.call(this, value); - } - return value; -}; - -Mysql.prototype.visitOnDuplicate = function(onDuplicate) { - var params = []; - /* jshint boss: true */ - for(var i = 0, node; node = onDuplicate.nodes[i]; i++) { - var target_col = this.visit(node); - params = params.concat(target_col + ' = ' + this.visit(node.value)); - } - var result = [ - 'ON DUPLICATE KEY UPDATE', - params.join(', ') - ]; - return result; -}; - -Mysql.prototype.visitOnConflict = function(onConflict) { - throw new Error('Mysql does not allow onConflict clause.'); -}; - -Mysql.prototype.visitReturning = function() { - throw new Error('MySQL does not allow returning clause.'); -}; - -Mysql.prototype.visitForShare = function() { - throw new Error('MySQL does not allow FOR SHARE clause.'); -}; - -Mysql.prototype.visitCreate = function(create) { - var result = Mysql.super_.prototype.visitCreate.call(this, create); - var engine = this._queryNode.table._initialConfig.engine; - var charset = this._queryNode.table._initialConfig.charset; - - if ( !! engine) { - result.push('ENGINE=' + engine); - } - - if ( !! charset) { - result.push('DEFAULT CHARSET=' + charset); - } - - return result; -}; - -Mysql.prototype.visitRenameColumn = function(renameColumn) { - var dataType = renameColumn.nodes[1].dataType || renameColumn.nodes[0].dataType; - assert(dataType, 'dataType missing for column ' + (renameColumn.nodes[1].name || renameColumn.nodes[0].name || '') + - ' (CHANGE COLUMN statements require a dataType)'); - return ['CHANGE COLUMN ' + this.visit(renameColumn.nodes[0]) + ' ' + this.visit(renameColumn.nodes[1]) + ' ' + dataType]; -}; - -Mysql.prototype.visitInsert = function(insert) { - var result = Postgres.prototype.visitInsert.call(this, insert); - if (result[2] === 'DEFAULT VALUES') { - result[2] = '() VALUES ()'; - } - return result; -}; - -Mysql.prototype.visitIndexes = function(node) { - var tableName = this.visit(this._queryNode.table.toNode())[0]; - - return "SHOW INDEX FROM " + tableName; -}; - -Mysql.prototype.visitBinary = function(binary) { - if (binary.operator === '@@') { - var self = this; - var text = '(MATCH ' + this.visit(binary.left) + ' AGAINST '; - text += this.visit(binary.right); - text += ')'; - return [text]; - } - return Mysql.super_.prototype.visitBinary.call(this, binary); -}; - -Mysql.prototype.visitFunctionCall = function(functionCall) { - var _this=this; - - this._visitingFunctionCall = true; - - function _extract() { - var nodes = functionCall.nodes.map(_this.visit.bind(_this)); - if (nodes.length != 1) throw new Error('Not enough parameters passed to ' + functionCall.name + ' function'); - var txt = functionCall.name + '(' + (nodes[0]+'') + ')'; - return txt; - } - - var txt=""; - var name = functionCall.name; - // Override date functions since mysql is different than postgres - if (['YEAR', 'MONTH', 'DAY', 'HOUR'].indexOf(functionCall.name) >= 0) txt = _extract(); - // Override CURRENT_TIMESTAMP function to remove parens - else if ('CURRENT_TIMESTAMP' == functionCall.name) txt = functionCall.name; - else txt = name + '(' + functionCall.nodes.map(this.visit.bind(this)).join(', ') + ')'; - - this._visitingFunctionCall = false; - return [txt]; -}; - -Mysql.prototype.visitColumn = function(columnNode) { - var self = this; - var inSelectClause; - - function isCountStarExpression(columnNode){ - if (!columnNode.aggregator) return false; - if (columnNode.aggregator.toLowerCase()!='count') return false; - if (!columnNode.star) return false; - return true; - } - - function _countStar(){ - // Implement our own since count(table.*) is invalid in Mysql - var result='COUNT(*)'; - if(inSelectClause && columnNode.alias) { - result += ' AS ' + self.quote(columnNode.alias); - } - return result; - } - - inSelectClause = !this._selectOrDeleteEndIndex; - if(isCountStarExpression(columnNode)) return _countStar(); - return Mysql.super_.prototype.visitColumn.call(this, columnNode); -}; - -Mysql.prototype.visitInterval = function(interval) { - var parameter; - if(_.isNumber(interval.years)) { - if(_.isNumber(interval.months)) { - parameter = "'" + interval.years + '-' + interval.months + "' YEAR_MONTH"; - } else { - parameter = interval.years + ' YEAR'; - } - } else if(_.isNumber(interval.months)) { - parameter = interval.months + ' MONTH'; - } else if(_.isNumber(interval.days)) { - parameter = "'" + interval.days + ' ' + - (_.isNumber(interval.hours)?interval.hours:0) + ':' + - (_.isNumber(interval.minutes)?interval.minutes:0) + ':' + - (_.isNumber(interval.seconds)?interval.seconds:0) + "' DAY_SECOND"; - } else { - parameter = "'" + (_.isNumber(interval.hours)?interval.hours:0) + ':' + - (_.isNumber(interval.minutes)?interval.minutes:0) + ':' + - (_.isNumber(interval.seconds)?interval.seconds:0) + "' HOUR_SECOND"; - } - var result = "INTERVAL " + parameter; - return result; -}; - - - -module.exports = Mysql; diff --git a/lib/dialect/mysql.ts b/lib/dialect/mysql.ts new file mode 100644 index 00000000..71ed2356 --- /dev/null +++ b/lib/dialect/mysql.ts @@ -0,0 +1,225 @@ +import assert from 'assert'; +import isNumber from 'lodash/isNumber.js'; + +import { AsOfNode } from '../node/asOf.js'; +import { BinaryNode } from '../node/binary.js'; +import { ColumnNode } from '../node/column.js'; +import { CreateNode } from '../node/create.js'; +import { CreateIndexNode } from '../node/createIndex.js'; +import { ForShareNode } from '../node/forShare.js'; +import { FunctionCallNode } from '../node/functionCall.js'; +import { IndexesNode } from '../node/indexes.js'; +import { InsertNode } from '../node/insert.js'; +import { IntervalNode } from '../node/interval.js'; +import { OnConflictNode } from '../node/onConflict.js'; +import { OnDuplicateNode } from '../node/onDuplicate.js'; +import { RenameColumnNode } from '../node/renameColumn.js'; +import { ReplaceNode } from '../node/replace.js'; +import { ReturningNode } from '../node/returning.js'; +import { Dialect } from './dialect.js'; + +export class Mysql extends Dialect { + constructor(config: any) { + super(config); + this.quoteCharacter = '`'; + this.arrayAggFunctionName = 'GROUP_CONCAT'; + } + + protected createSubInstance() { + return new Mysql(this.config); + } + + public _getParameterPlaceholder(index: string | number, value: any): string { + return '?'; + } + public _getParameterValue( + value: null | boolean | number | string | any[] | Date | Buffer | Record, + quoteChar?: string + ): string | number { + return Buffer.isBuffer(value) + ? 'x' + this._getParameterValue(value.toString('hex'), quoteChar) + : super._getParameterValue(value, quoteChar); + } + public visitReplace(replaceNode: ReplaceNode): string[] { + // don't use table.column for replaces + this.visitedReplace = true; + const result = [ + 'REPLACE', + ...replaceNode.nodes.map((n) => this.visit(n).join()), + `INTO ${this.visit(this.queryNode!.table.toNode())}`, + `(${replaceNode.columns.map((n) => this.visit(n).join()).join(', ')})` + ]; + const paramNodes = replaceNode.getParameters(); + if (paramNodes.length > 0) { + const paramText = paramNodes + .map((paramSet) => { + return paramSet.map((param) => this.visit(param).join()).join(', '); + }) + .map((param) => `(${param})`) + .join(', '); + result.push('VALUES', paramText); + if (result.slice(2, 5).join(' ') === '() VALUES ()') { + result.splice(2, 3, 'DEFAULT VALUES'); + } + } + this.visitedReplace = false; + if (result[2] === 'DEFAULT VALUES') { + result[2] = '() VALUES ()'; + } + return result; + } + public visitAsOf(asOfNode: AsOfNode): string[] { + throw new Error('Mysql does not support AS OF.'); + } + public visitOnDuplicate(onDuplicateNode: OnDuplicateNode): string[] { + const params: string[] = []; + /* jshint boss: true */ + for (const node of onDuplicateNode.nodes as ColumnNode[]) { + const targetCol = this.visit(node); + params.push(`${targetCol} = ${this.visit(node.value)}`); + } + const result = ['ON DUPLICATE KEY UPDATE', params.join(', ')]; + return result; + } + public visitOnConflict(onConflictNode: OnConflictNode): string[] { + throw new Error('Mysql does not allow onConflict clause.'); + } + public visitReturning(returningNode: ReturningNode): string[] { + throw new Error('MySQL does not allow returning clause.'); + } + public visitForShare(forShareNode: ForShareNode): string[] { + throw new Error('MySQL does not allow FOR SHARE clause.'); + } + public visitCreate(createNode: CreateNode): string[] { + const result = super.visitCreate(createNode); + const engine = this.queryNode!.table.initialConfig.engine; + const charset = this.queryNode!.table.initialConfig.charset; + if (!!engine) { + result.push('ENGINE=' + engine); + } + if (!!charset) { + result.push('DEFAULT CHARSET=' + charset); + } + return result; + } + public visitRenameColumn(renameColumnNode: RenameColumnNode): string[] { + const dataType = (renameColumnNode.nodes[1] as ColumnNode).dataType || (renameColumnNode.nodes[0] as ColumnNode).dataType; + assert( + dataType, + 'dataType missing for column ' + + ((renameColumnNode.nodes[1] as ColumnNode).name || (renameColumnNode.nodes[0] as ColumnNode).name || '') + + ' (CHANGE COLUMN statements require a dataType)' + ); + return [`CHANGE COLUMN ${this.visit(renameColumnNode.nodes[0])} ${this.visit(renameColumnNode.nodes[1])} ${dataType}`]; + } + public visitInsert(insertNode: InsertNode): string[] { + const result = super.visitInsert(insertNode); + if (result[2] === 'DEFAULT VALUES') { + result[2] = '() VALUES ()'; + } + return result; + } + public visitIndexes(indexesNode: IndexesNode): string[] { + const tableName = this.visit(this.queryNode!.table.toNode())[0]; + return [`SHOW INDEX FROM ${tableName}`]; + } + public visitCreateIndex(createIndexNode: CreateIndexNode): string[] { + const { indexType, ifNotExists, indexName, tableName, algorithm, columns, parser } = this._visitCreateIndex(createIndexNode); + + return [ + 'CREATE', + indexType, + 'INDEX', + ...ifNotExists, + indexName, + algorithm, + 'ON', + ...tableName, + columns, + parser + ].filter(this.notEmpty); + } + public visitIfNotExistsIndex(): string[] { + throw new Error('MySQL does not allow ifNotExists clause on indexes.'); + } + public visitIfExistsIndex(): string[] { + throw new Error('MySQL does not allow ifExists clause on indexes.'); + } + public visitBinary(binaryNode: BinaryNode): string[] { + if (binaryNode.operator === '@@' && !Array.isArray(binaryNode.right)) { + return [`(MATCH ${this.visit(binaryNode.left)} AGAINST ${this.visit(binaryNode.right)})`]; + } + return super.visitBinary(binaryNode); + } + public visitFunctionCall(functionCallNode: FunctionCallNode): string[] { + this.visitingFunctionCall = true; + const extract = () => { + const nodes = functionCallNode.nodes.map((n) => this.visit(n).join()); + if (nodes.length !== 1) { + throw new Error(`Not enough parameters passed to ${functionCallNode.name} function`); + } + return `${functionCallNode.name}(${nodes[0]})`; + }; + let txt = ''; + const name = functionCallNode.name; + // Override date functions since mysql is different than postgres + if (['YEAR', 'MONTH', 'DAY', 'HOUR'].indexOf(functionCallNode.name) >= 0) { + txt = extract(); + } + // Override CURRENT_TIMESTAMP function to remove parens + else if ('CURRENT_TIMESTAMP' === functionCallNode.name) { + txt = functionCallNode.name; + } else { + txt = `${name}(${functionCallNode.nodes.map((n) => this.visit(n).join()).join(', ')})`; + } + this.visitingFunctionCall = false; + return [txt]; + } + public visitColumn(columnNode: ColumnNode): string[] { + let inSelectClause: boolean = false; + inSelectClause = !this.selectOrDeleteEndIndex; + const isCountStarExpression = (node: ColumnNode) => { + if (!node.aggregator) { + return false; + } + if (node.aggregator.toLowerCase() !== 'count') { + return false; + } + if (!node.star) { + return false; + } + return true; + }; + const countStar = () => { + // Implement our own since count(table.*) is invalid in Mysql + let result = 'COUNT(*)'; + if (inSelectClause && columnNode.alias) { + result += ` AS ${this.quote(columnNode.alias)}`; + } + return result; + }; + if (isCountStarExpression(columnNode)) { + return [countStar()]; + } + return super.visitColumn(columnNode); + } + public visitInterval(intervalNode: IntervalNode): string[] { + let parameter; + if (isNumber(intervalNode.years)) { + parameter = isNumber(intervalNode.months) + ? `'${intervalNode.years}-${intervalNode.months}' YEAR_MONTH` + : `${intervalNode.years} YEAR`; + } else if (isNumber(intervalNode.months)) { + parameter = `${intervalNode.months} MONTH`; + } else if (isNumber(intervalNode.days)) { + parameter = `'${intervalNode.days} ${isNumber(intervalNode.hours) ? intervalNode.hours : 0}:${ + isNumber(intervalNode.minutes) ? intervalNode.minutes : 0 + }:${isNumber(intervalNode.seconds) ? intervalNode.seconds : 0}' DAY_SECOND`; + } else { + parameter = `'${isNumber(intervalNode.hours) ? intervalNode.hours : 0}:${ + isNumber(intervalNode.minutes) ? intervalNode.minutes : 0 + }:${isNumber(intervalNode.seconds) ? intervalNode.seconds : 0}' HOUR_SECOND`; + } + return [`INTERVAL ${parameter}`]; + } +} diff --git a/lib/dialect/oracle.js b/lib/dialect/oracle.js deleted file mode 100644 index 38267339..00000000 --- a/lib/dialect/oracle.js +++ /dev/null @@ -1,325 +0,0 @@ -'use strict'; - -var util = require('util'); -var assert = require('assert'); - -var Oracle = function(config) { - this.output = []; - this.params = []; - this.config = config || {}; -}; - -var Postgres = require('./postgres'); - -var Mssql = require('./mssql'); - -util.inherits(Oracle, Postgres); - -Oracle.prototype._myClass = Oracle; - -Oracle.prototype.visitReplace = function(replace) { - throw new Error('Oracle does not support REPLACE.'); -}; - -Oracle.prototype._aliasText = ' '; -Oracle.prototype._getParameterPlaceholder = function(index, value) { - /* jshint unused: false */ - return ':' + index; -}; - -Oracle.prototype.visitAlias = function(alias) { - var result = [this.visit(alias.value) + ' ' + this.quote(alias.alias)]; - return result; -}; - -Oracle.prototype.visitAlter = function(alter) { - var self=this; - var errMsg='ALTER TABLE cannot be used to perform multiple different operations in the same statement.'; - - // Implement our own add column: - // PostgreSQL: ALTER TABLE "name" ADD COLUMN "col1", ADD COLUMN "col2" - // Oracle: ALTER TABLE "name" ADD ("col1", "col2") - function _addColumn(){ - self._visitingAlter = true; - var table = self._queryNode.table; - self._visitingAddColumn = true; - var result='ALTER TABLE '+self.visit(table.toNode())+' ADD ('+self.visit(alter.nodes[0].nodes[0]); - for (var i= 1,len=alter.nodes.length; i= 0) { - ret.push('ROWS'); - } - if (ret.indexOf('LIMIT') >= 0) { - ret[0] = 'FETCH NEXT'; - ret.push('ROWS ONLY'); - } - return ret; -}; - -Oracle.prototype.visitQueryHelper=function(actions,targets,filters){ - var output = Oracle.super_.prototype.visitQueryHelper.call(this,actions,targets,filters); - - //In Oracle, OFFSET must come before FETCH NEXT (limit) - //Change positions, if both are present and not done already - var offset = output.indexOf('OFFSET'); - var limit = output.indexOf('FETCH NEXT'); - if (offset != -1 && limit != -1 && offset > limit){ - var temp = [output[offset], output[offset+1], output[offset+2]]; - output[offset] = output[limit]; - output[offset+1] = output[limit+1]; - output[offset+2] = output[limit+2]; - output[limit] = temp[0]; - output[limit+1] = temp[1]; - output[limit+2] = temp[2]; - } - - return this.output; -}; - -Oracle.prototype.visitColumn = function(columnNode) { - var self=this; - var table; - var inSelectClause; - - function _arrayAgg(){ - throw new Error("Oracle does not support array_agg."); - } - - function _countStar(){ - // Implement our own since count(table.*) is invalid in Oracle - var result='COUNT(*)'; - if(inSelectClause && columnNode.alias) { - result += self._aliasText + self.quote(columnNode.alias); - } - return result; - } - - table = columnNode.table; - inSelectClause = !this._selectOrDeleteEndIndex; - if (isCountStarExpression(columnNode)) return _countStar(); - if (inSelectClause && table && !table.alias && columnNode.asArray) return _arrayAgg(); - return Oracle.super_.prototype.visitColumn.call(this, columnNode); -}; - - -Oracle.prototype.visitReturning = function() { - // TODO: need to add some code to the INSERT clause to support this since its the equivalent of the OUTPUT clause - // in MS SQL which appears before the values, not at the end of the statement. - throw new Error('Returning clause is not yet supported for Oracle.'); -}; - - -Oracle.prototype._getParameterValue = function(value) { - if (Buffer.isBuffer(value)) { - value = "utl_raw.cast_to_varchar2(hextoraw('" + value.toString('hex') + "'))"; - } else { - value = Oracle.super_.prototype._getParameterValue.call(this, value); - //value = Postgres.prototype._getParameterValue.call(this, value); - } - return value; -}; - - -Oracle.prototype.visitIndexes = function(node) { - - var tableName = this._queryNode.table.getName(); - var schemaName = this._queryNode.table.getSchema(); - - var indexes = "SELECT * FROM USER_INDEXES WHERE TABLE_NAME = '" + tableName + "'"; - - if (schemaName) { - indexes += " AND TABLE_OWNER = '" + schemaName + "'"; - } - - return indexes; -}; - - -Oracle.prototype.visitDropIndex = function(node) { - var result = [ 'DROP INDEX' ]; - var schemaName = node.table.getSchema(); - if (schemaName) { - result.push(this.quote(schemaName) + "."); - } - - result.push(this.quote(node.options.indexName)); - - return result; -}; - -// Using same CASE implementation as MSSQL -Oracle.prototype.visitCase = function(caseExp) { - - return Mssql.prototype.visitCase.call(this, caseExp); -}; - -Oracle.prototype.visitOnConflict = function(onConflict) { - throw new Error('Oracle does not allow onConflict clause.'); -}; - -function isCreateIfNotExists(create){ - if (create.nodes.length===0) return false; - if (create.nodes[0].type!='IF NOT EXISTS') return false; - return true; -} - -function isCreateTemporary(create){ - return create.options.isTemporary; -} - -function isDropIfExists(drop){ - if (drop.nodes.length===0) return false; - if (drop.nodes[0].type!='IF EXISTS') return false; - return true; -} - -// SQL Server does not support array expressions except in the IN clause. -function isRightSideArray(binary){ - return Array.isArray(binary.right); -} - -function isCountStarExpression(columnNode){ - if (!columnNode.aggregator) return false; - if (columnNode.aggregator.toLowerCase()!='count') return false; - if (!columnNode.star) return false; - return true; -} - -function isAlterAddColumn(alter){ - if (alter.nodes.length===0) return false; - if (alter.nodes[0].type!='ADD COLUMN') return false; - return true; -} - -function isAlterDropColumn(alter){ - if (alter.nodes.length===0) return false; - if (alter.nodes[0].type!='DROP COLUMN') return false; - return true; -} - -module.exports = Oracle; diff --git a/lib/dialect/oracle.ts b/lib/dialect/oracle.ts new file mode 100644 index 00000000..cd3d6c5b --- /dev/null +++ b/lib/dialect/oracle.ts @@ -0,0 +1,364 @@ +import assert from 'assert'; + +import { AliasNode } from '../node/alias.js'; +import { AlterNode } from '../node/alter.js'; +import { AsOfNode } from '../node/asOf.js'; +import { BinaryNode } from '../node/binary.js'; +import { CascadeNode } from '../node/cascade.js'; +import { CaseNode } from '../node/case.js'; +import { ColumnNode } from '../node/column.js'; +import { CreateNode } from '../node/create.js'; +import { CreateIndexNode } from '../node/createIndex.js'; +import { DropNode } from '../node/drop.js'; +import { DropIndexNode } from '../node/dropIndex.js'; +import { IndexesNode } from '../node/indexes.js'; +import { ModifierNode } from '../node/modifier.js'; +import { Node } from '../node/node.js'; +import { OnConflictNode } from '../node/onConflict.js'; +import { ParameterNode } from '../node/parameter.js'; +import { ReplaceNode } from '../node/replace.js'; +import { RestrictNode } from '../node/restrict.js'; +import { ReturningNode } from '../node/returning.js'; +import { TableNode } from '../node/table.js'; +import { Dialect } from './dialect.js'; + +export class Oracle extends Dialect { + constructor(config: any) { + super(config); + this.aliasText = ' '; + } + + protected createSubInstance() { + return new Oracle(this.config); + } + + public _getParameterValue( + value: null | boolean | number | string | any[] | Date | Buffer | Record, + quoteChar?: string + ): string | number { + return Buffer.isBuffer(value) + ? "utl_raw.cast_to_varchar2(hextoraw('" + value.toString('hex') + "'))" + : super._getParameterValue(value, quoteChar); + } + public _getParameterPlaceholder(index: string | number, value: any): string { + return `:${index}`; + } + public visitReplace(replaceNode: ReplaceNode): string[] { + throw new Error('Oracle does not support REPLACE.'); + } + public visitAlias(aliasNode: AliasNode): string[] { + const result = [this.visit(aliasNode.value) + ' ' + this.quote(aliasNode.alias)]; + return result; + } + public visitAlter(alterNode: AlterNode): string[] { + const errMsg = 'ALTER TABLE cannot be used to perform multiple different operations in the same statement.'; + // Implement our own add column: + // PostgreSQL: ALTER TABLE "name" ADD COLUMN "col1", ADD COLUMN "col2" + // Oracle: ALTER TABLE "name" ADD ("col1", "col2") + const addColumn = () => { + this.visitingAlter = true; + const table = this.queryNode!.table; + this.visitingAddColumn = true; + let result = 'ALTER TABLE ' + this.visit(table.toNode()) + ' ADD (' + this.visit(alterNode.nodes[0].nodes[0]); + for (let i = 1, len = alterNode.nodes.length; i < len; i++) { + const node = alterNode.nodes[i]; + assert(node.type === 'ADD COLUMN', errMsg); + result += ', ' + this.visit(node.nodes[0]); + } + result += ')'; + this.visitingAddColumn = false; + this.visitingAlter = false; + return [result]; + }; + // Implement our own drop column: + // PostgreSQL: ALTER TABLE "name" DROP COLUMN "col1", DROP COLUMN "col2" + // Oracle: ALTER TABLE "name" DROP ("col1", "col2") + const dropColumn = () => { + this.visitingAlter = true; + const table = this.queryNode!.table; + const result = ['ALTER TABLE', ...this.visit(table.toNode())]; + let columns = 'DROP (' + this.visit(alterNode.nodes[0].nodes[0]); + for (let i = 1, len = alterNode.nodes.length; i < len; i++) { + const node = alterNode.nodes[i]; + assert(node.type === 'DROP COLUMN', errMsg); + columns += ', ' + this.visit(node.nodes[0]); + } + columns += ')'; + result.push(columns); + this.visitingAlter = false; + return result; + }; + if (isAlterAddColumn(alterNode)) { + return addColumn(); + } + if (isAlterDropColumn(alterNode)) { + return dropColumn(); + } + return super.visitAlter(alterNode); + } + public visitAsOf(asOfNode: AsOfNode): string[] { + const result = ['AS OF TIMESTAMP', ...asOfNode.nodes.flatMap(this.visit.bind(this))]; + return result; + } + public visitTable(tableNode: TableNode): string[] { + const table = tableNode.table; + let txt = ''; + if (table.getSchema()) { + txt = this.quote(table.getSchema()!); + txt += '.'; + } + txt += this.quote(table.getName()); + if (table.alias) { + txt += ' ' + this.quote(table.alias); + } + return [txt]; + } + public visitCascade(cascadeNode: CascadeNode): string[] { + return ['CASCADE CONSTRAINTS']; + } + public visitRestrict(restrictNode: RestrictNode): string[] { + throw new Error('Oracle do not support RESTRICT in DROP TABLE'); + } + public visitDrop(dropNode: DropNode): string[] { + if (!isDropIfExists(dropNode)) { + return super.visitDrop(dropNode); + } + // Implement our own drop if exists: + // PostgreSQL: DROP TABLE IF EXISTS "group" + // Oracle: + // BEGIN + // EXECUTE IMMEDIATE 'DROP TABLE POST'; + // EXCEPTION + // WHEN OTHERS THEN + // IF SQLCODE != -942 THEN + // RAISE; + // END IF; + // END; + const table = this.queryNode!.table; + const tableResult = this.visit(table.toNode()); + const dropResult = ['DROP TABLE']; + dropResult.push(...tableResult); + return [ + "BEGIN EXECUTE IMMEDIATE '" + dropResult.join(' ') + "'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;" + ]; + } + public visitCreate(createNode: CreateNode): string[] { + const isNotExists = isCreateIfNotExists(createNode); + // const isTemporary=isCreateTemporary(create) + let createText = super.visitCreate(createNode); + if (isNotExists) { + // Implement our own create if not exists: + // PostgreSQL: CREATE TABLE IF NOT EXISTS "group" ("id" constchar(100)) + // Oracle: + // BEGIN + // EXECUTE IMMEDIATE 'CREATE TABLE ...'; + // EXCEPTION + // WHEN OTHERS THEN + // IF SQLCODE != -955 THEN + // RAISE; + // END IF; + // END; + createText = [ + "BEGIN EXECUTE IMMEDIATE '" + + createText.join(' ').replace(' IF NOT EXISTS', '') + + "'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -955 THEN RAISE; END IF; END;" + ]; + } + return createText; + } + public visitBinary(binaryNode: BinaryNode): string[] { + if (binaryNode.operator === '@@' && !Array.isArray(binaryNode.right)) { + let text = '(INSTR (' + this.visit(binaryNode.left) + ', '; + text += this.visit(binaryNode.right); + text += ') > 0)'; + return [text]; + } + if (!Array.isArray(binaryNode.right)) { + return super.visitBinary(binaryNode); + } + if (binaryNode.operator === 'IN' || binaryNode.operator === 'NOT IN') { + return super.visitBinary(binaryNode); + } + throw new Error('Oracle does not support arrays in this type of expression.'); + } + public visitModifier(modifierNode: ModifierNode): string[] { + const ret = super.visitModifier(modifierNode); + if (ret.indexOf('OFFSET') >= 0) { + ret.push('ROWS'); + } + if (ret.indexOf('LIMIT') >= 0) { + ret[0] = 'FETCH NEXT'; + ret.push('ROWS ONLY'); + } + return ret; + } + public visitQueryHelper(actions: Node[], targets: Node[], filters: Node[]): string[] { + const output = super.visitQueryHelper(actions, targets, filters); + // In Oracle, OFFSET must come before FETCH NEXT (limit) + // Change positions, if both are present and not done already + const offset = output.indexOf('OFFSET'); + const limit = output.indexOf('FETCH NEXT'); + if (offset !== -1 && limit !== -1 && offset > limit) { + const temp = [output[offset], output[offset + 1], output[offset + 2]]; + output[offset] = output[limit]; + output[offset + 1] = output[limit + 1]; + output[offset + 2] = output[limit + 2]; + output[limit] = temp[0]; + output[limit + 1] = temp[1]; + output[limit + 2] = temp[2]; + } + return this.output; + } + public visitColumn(columnNode: ColumnNode): string[] { + const table = columnNode.table; + const inSelectClause = !this.selectOrDeleteEndIndex; + const arrayAgg = () => { + throw new Error('Oracle does not support array_agg.'); + }; + const countStar = () => { + // Implement our own since count(table.*) is invalid in Oracle + let result = 'COUNT(*)'; + if (inSelectClause && columnNode.alias) { + result += this.aliasText + this.quote(columnNode.alias); + } + return [result]; + }; + if (isCountStarExpression(columnNode)) { + return countStar(); + } + if (inSelectClause && table && !table.alias && columnNode.asArray) { + return arrayAgg(); + } + return super.visitColumn(columnNode); + } + public visitReturning(returningNode: ReturningNode): string[] { + // TODO: need to add some code to the INSERT clause to support this since its the equivalent of the OUTPUT clause + // in MS SQL which appears before the values, not at the end of the statement. + throw new Error('Returning clause is not yet supported for Oracle.'); + } + public visitIndexes(indexesNode: IndexesNode): string[] { + const tableName = this.queryNode!.table.getName(); + const schemaName = this.queryNode!.table.getSchema(); + let indexes = "SELECT * FROM USER_INDEXES WHERE TABLE_NAME = '" + tableName + "'"; + if (schemaName) { + indexes += " AND TABLE_OWNER = '" + schemaName + "'"; + } + return [indexes]; + } + public visitCreateIndex(createIndexNode: CreateIndexNode): string[] { + const { indexType, ifNotExists, indexName, tableName, algorithm, columns, parser } = this._visitCreateIndex(createIndexNode); + + return [ + 'CREATE', + indexType, + 'INDEX', + ...ifNotExists, + indexName, + algorithm, + 'ON', + ...tableName, + columns, + parser + ].filter(this.notEmpty); + } + public visitDropIndex(dropIndexNode: DropIndexNode): string[] { + if (dropIndexNode.options.ifExists) { + throw new Error('Oracle does not allow ifExists clause on indexes.'); + } + const result = ['DROP INDEX']; + const schemaName = dropIndexNode.table.getSchema(); + if (schemaName) { + result.push(this.quote(schemaName) + '.'); + } + result.push(this.quote(dropIndexNode.options.indexName)); + return result; + } + public visitIfNotExistsIndex(): string[] { + throw new Error('Oracle does not allow ifNotExists clause on indexes.'); + } + // Need to implement a special version of CASE since Oracle doesn't support + // CASE WHEN true THEN xxx END + // the "true" has to be a boolean expression like 1=1 + public visitCase(caseNode: CaseNode): string[] { + const whenValue = (node: Node) => { + if (node.type !== 'PARAMETER') { + return this.visit(node); + } + // dealing with a true/false value + const val = (node as ParameterNode).value(); + return val === true ? '1=1' : '0=1'; + }; + assert(caseNode.whenList.length === caseNode.thenList.length); + let text = '(CASE'; + this.visitingCase = true; + for (let i = 0; i < caseNode.whenList.length; i++) { + text += ` WHEN ${whenValue(caseNode.whenList[i])} THEN ${this.visit(caseNode.thenList[i])}`; + } + if (caseNode.else != null) { + text += ` ELSE ${this.visit(caseNode.else)}`; + } + this.visitingCase = false; + text += ' END)'; + return [text]; + } + public visitOnConflict(onConflictNode: OnConflictNode): string[] { + throw new Error('Oracle does not allow onConflict clause.'); + } +} + +const isCreateIfNotExists = (createNode: CreateNode) => { + if (createNode.nodes.length === 0) { + return false; + } + if (createNode.nodes[0].type !== 'IF NOT EXISTS') { + return false; + } + return true; +} + +const isCreateTemporary = (createNode: CreateNode) => { + return createNode.options.isTemporary; +} + +const isDropIfExists = (dropNode: DropNode) => { + if (dropNode.nodes.length === 0) { + return false; + } + if (dropNode.nodes[0].type !== 'IF EXISTS') { + return false; + } + return true; +} + +const isCountStarExpression = (columnNode: ColumnNode) => { + if (!columnNode.aggregator) { + return false; + } + if (columnNode.aggregator.toLowerCase() !== 'count') { + return false; + } + if (!columnNode.star) { + return false; + } + return true; +} + +const isAlterAddColumn = (alterNode: AlterNode) => { + if (alterNode.nodes.length === 0) { + return false; + } + if (alterNode.nodes[0].type !== 'ADD COLUMN') { + return false; + } + return true; +} + +const isAlterDropColumn = (alterNode: AlterNode) => { + if (alterNode.nodes.length === 0) { + return false; + } + if (alterNode.nodes[0].type !== 'DROP COLUMN') { + return false; + } + return true; +} diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js deleted file mode 100644 index 2816c901..00000000 --- a/lib/dialect/postgres.js +++ /dev/null @@ -1,1224 +0,0 @@ -'use strict'; - -var _ = require('lodash'); -var assert = require('assert'); -var From = require('../node/from'); -var Select = require('../node/select'); -var Table = require('../table'); - -var Postgres = function(config) { - this.output = []; - this.params = []; - this.config = config || {}; -}; - -Postgres.prototype._myClass = Postgres; - -Postgres.prototype._arrayAggFunctionName = 'array_agg'; - -Postgres.prototype._getParameterText = function(index, value) { - if (this._disableParameterPlaceholders) { - // do not use placeholder - return this._getParameterValue(value); - } else { - // use placeholder - return this._getParameterPlaceholder(index, value); - } -}; - -Postgres.prototype._getParameterValue = function(value, quoteChar) { - // handle primitives - if (null === value) { - value = 'NULL'; - } else if ('boolean' === typeof value) { - value = value ? 'TRUE' : 'FALSE'; - } else if ('number' === typeof value) { - // number is just number - value = value; - } else if ('string' === typeof value) { - // string uses single quote by default - value = this.quote(value, quoteChar || "'"); - } else if ('object' === typeof value) { - if (Array.isArray(value)) { - if (this._myClass === Postgres) { - // naive check to see if this is an array of objects, which - // is handled differently than an array of primitives - if (value.length && 'object' === typeof value[0] && - !_.isFunction(value[0].toISOString) && - !Array.isArray(value[0])) { - value = "'" + JSON.stringify(value) + "'"; - } else { - var self = this; - value = value.map(function (item) { - // In a Postgres array, strings must be double-quoted - return self._getParameterValue(item, '"'); - }); - value = '\'{' + value.join(',') + '}\''; - } - } else { - value = _.map(value, this._getParameterValue.bind(this)); - value = '(' + value.join(', ') + ')'; - } - } else if (value instanceof Date) { - // Date object's default toString format does not get parsed well - // Handle dates using toISOString - value = this._getParameterValue(value.toISOString()); - } else if (Buffer.isBuffer(value)) { - value = this._getParameterValue('\\x' + value.toString('hex')); - } else { - // rich object represent with string - var strValue = value.toString(); - value = strValue === '[object Object]' ? this._getParameterValue(JSON.stringify(value)) : this._getParameterValue(strValue); - } - } else { - throw new Error('Unable to use ' + value + ' in query'); - } - - // value has been converted at this point - return value; -}; - -Postgres.prototype._getParameterPlaceholder = function(index, value) { - /* jshint unused: false */ - return '$' + index; -}; - -Postgres.prototype.getQuery = function(queryNode) { - // passed in a table, not a query - if (queryNode instanceof Table) { - queryNode = queryNode.select(queryNode.star()); - } - this.output = this.visit(queryNode); - - //if is a create view, must replace paramaters with values - if (this.output.indexOf('CREATE VIEW') > -1) { - var previousFlagStatus = this._disableParameterPlaceholders; - this._disableParameterPlaceholders = true; - this.output = []; - this.output = this.visit(queryNode); - this.params = []; - this._disableParameterPlaceholders = previousFlagStatus; - } - - // create the query object - var query = { text: this.output.join(' '), values: this.params }; - - // reset the internal state of this builder - this.output = []; - this.params = []; - - return query; -}; - -Postgres.prototype.getString = function(queryNode) { - // switch off parameter placeholders - var previousFlagStatus = this._disableParameterPlaceholders; - this._disableParameterPlaceholders = true; - var query; - try { - // use the same code path for query building - query = this.getQuery(queryNode); - } finally { - // always restore the flag afterwards - this._disableParameterPlaceholders = previousFlagStatus; - } - return query.text; -}; - -Postgres.prototype.visit = function(node) { - switch(node.type) { - case 'QUERY' : return this.visitQuery(node); - case 'SUBQUERY' : return this.visitSubquery(node); - case 'SELECT' : return this.visitSelect(node); - case 'INSERT' : return this.visitInsert(node); - case 'REPLACE' : return this.visitReplace(node); - case 'UPDATE' : return this.visitUpdate(node); - case 'DELETE' : return this.visitDelete(node); - case 'CREATE' : return this.visitCreate(node); - case 'DROP' : return this.visitDrop(node); - case 'TRUNCATE' : return this.visitTruncate(node); - case 'DISTINCT' : return this.visitDistinct(node); - case 'DISTINCT ON' : return this.visitDistinctOn(node); - case 'ALIAS' : return this.visitAlias(node); - case 'ALTER' : return this.visitAlter(node); - case 'CAST' : return this.visitCast(node); - case 'FROM' : return this.visitFrom(node); - case 'WHERE' : return this.visitWhere(node); - case 'ORDER BY' : return this.visitOrderBy(node); - case 'ORDER BY VALUE' : return this.visitOrderByValue(node); - case 'GROUP BY' : return this.visitGroupBy(node); - case 'HAVING' : return this.visitHaving(node); - case 'RETURNING' : return this.visitReturning(node); - case 'ONDUPLICATE' : return this.visitOnDuplicate(node); - case 'ONCONFLICT' : return this.visitOnConflict(node); - case 'FOR UPDATE' : return this.visitForUpdate(); - case 'FOR SHARE' : return this.visitForShare(); - case 'TABLE' : return this.visitTable(node); - case 'COLUMN' : return this.visitColumn(node); - case 'FOREIGN KEY' : return this.visitForeignKey(node); - case 'JOIN' : return this.visitJoin(node); - case 'LITERAL' : return this.visitLiteral(node); - case 'TEXT' : return node.text; - case 'PARAMETER' : return this.visitParameter(node); - case 'DEFAULT' : return this.visitDefault(node); - case 'IF EXISTS' : return this.visitIfExists(); - case 'IF NOT EXISTS' : return this.visitIfNotExists(); - case 'OR IGNORE' : return this.visitOrIgnore(); - case 'CASCADE' : return this.visitCascade(); - case 'RESTRICT' : return this.visitRestrict(); - case 'RENAME' : return this.visitRename(node); - case 'ADD COLUMN' : return this.visitAddColumn(node); - case 'DROP COLUMN' : return this.visitDropColumn(node); - case 'RENAME COLUMN' : return this.visitRenameColumn(node); - case 'INDEXES' : return this.visitIndexes(node); - case 'CREATE INDEX' : return this.visitCreateIndex(node); - case 'DROP INDEX' : return this.visitDropIndex(node); - case 'FUNCTION CALL' : return this.visitFunctionCall(node); - case 'ARRAY CALL' : return this.visitArrayCall(node); - case 'CREATE VIEW' : return this.visitCreateView(node); - case 'INTERVAL' : return this.visitInterval(node); - - case 'POSTFIX UNARY' : return this.visitPostfixUnary(node); - case 'PREFIX UNARY' : return this.visitPrefixUnary(node); - case 'BINARY' : return this.visitBinary(node); - case 'TERNARY' : return this.visitTernary(node); - case 'IN' : return this.visitIn(node); - case 'NOT IN' : return this.visitNotIn(node); - case 'CASE' : return this.visitCase(node); - case 'AT' : return this.visitAt(node); - case 'SLICE' : return this.visitSlice(node); - - case 'LIMIT' : - case 'OFFSET': - return this.visitModifier(node); - default: - throw new Error("Unrecognized node type " + node.type); - } -}; - -Postgres.prototype._quoteCharacter = '"'; -Postgres.prototype._aliasText = ' AS '; - -Postgres.prototype.quote = function(word, quoteCharacter) { - var q; - if (quoteCharacter) { - // use the specified quote character if given - q = quoteCharacter; - } else { - q = this._quoteCharacter; - } - // handle square brackets specially - if (q=='['){ - return '['+word+']'; - } else { - return q + word.replace(new RegExp(q,'g'),q+q) + q; - } -}; - -Postgres.prototype.visitSelect = function(select) { - var result = ['SELECT']; - - if (select.isDistinct) result.push('DISTINCT'); - - var distinctOnNode = select.nodes.filter(function (node) {return node.type === 'DISTINCT ON';}).shift(); - var nonDistinctOnNodes = select.nodes.filter(function (node) {return node.type !== 'DISTINCT ON';}); - - if (distinctOnNode) { - result.push(this.visit(distinctOnNode)); - } - - result.push(nonDistinctOnNodes.map(this.visit.bind(this)).join(', ')); - - this._selectOrDeleteEndIndex = this.output.length + result.length; - - return result; -}; - -Postgres.prototype.visitInsert = function(insert) { - var self = this; - // don't use table.column for inserts - this._visitedInsert = true; - - var result = ['INSERT']; - result = result.concat(insert.nodes.map(this.visit.bind(this))); - result.push('INTO ' + this.visit(this._queryNode.table.toNode())); - result.push('(' + insert.columns.map(this.visit.bind(this)).join(', ') + ')'); - - var paramNodes = insert.getParameters(); - - if (paramNodes.length > 0) { - var paramText = paramNodes.map(function (paramSet) { - return paramSet.map(function (param) { - return self.visit(param); - }).join(', '); - }).map(function (param) { - return '('+param+')'; - }).join(', '); - - result.push('VALUES', paramText); - - if (result.slice(2, 5).join(' ') === '() VALUES ()') { - result.splice(2, 3, 'DEFAULT VALUES'); - } - } - - this._visitedInsert = false; - - return result; -}; - -Postgres.prototype.visitReplace = function(replace) { - throw new Error('Postgres does not support REPLACE.'); -}; - -Postgres.prototype.visitUpdate = function(update) { - // don't auto-generate from clause - var params = []; - /* jshint boss: true */ - for(var i = 0, node; node = update.nodes[i]; i++) { - this._visitingUpdateTargetColumn = true; - var target_col = this.visit(node); - this._visitingUpdateTargetColumn = false; - params = params.concat(target_col + ' = ' + this.visit(node.value)); - } - var result = [ - 'UPDATE', - this.visit(this._queryNode.table.toNode()), - 'SET', - params.join(', ') - ]; - return result; -}; - -Postgres.prototype.visitDelete = function (del) { - var result = ['DELETE']; - if (del.nodes.length) { - result.push(del.nodes.map(this.visit.bind(this)).join(', ')); - } - this._selectOrDeleteEndIndex = result.length; - return result; -}; - -Postgres.prototype.visitCreate = function(create) { - this._visitingCreate = true; - // don't auto-generate from clause - var table = this._queryNode.table; - var col_nodes = table.columns.map(function(col) { return col.toNode(); }); - var foreign_key_nodes = table.foreignKeys; - - var result = ['CREATE TABLE']; - if (create.options.isTemporary) result=['CREATE TEMPORARY TABLE']; - result = result.concat(create.nodes.map(this.visit.bind(this))); - result.push(this.visit(table.toNode())); - var primary_col_nodes = col_nodes.filter(function(n) { - return n.primaryKey; - }); - this._visitCreateCompoundPrimaryKey = primary_col_nodes.length > 1; - var colspec = '(' + col_nodes.map(this.visit.bind(this)).join(', '); - if (this._visitCreateCompoundPrimaryKey) { - colspec += ', PRIMARY KEY ('; - colspec += primary_col_nodes.map(function(node) { - return this.quote(node.name); - }.bind(this)).join(', '); - colspec += ')'; - } - if(foreign_key_nodes.length > 0) { - colspec += ', ' + foreign_key_nodes.map(this.visit.bind(this)).join(', '); - } - colspec += ')'; - result.push(colspec); - this._visitCreateCompoundPrimaryKey = false; - this._visitingCreate = false; - return result; -}; - -Postgres.prototype.visitDrop = function(drop) { - // don't auto-generate from clause - var result = ['DROP TABLE']; - result = result.concat(drop.nodes.map(this.visit.bind(this))); - return result; -}; - -Postgres.prototype.visitTruncate = function(truncate) { - var result = ['TRUNCATE TABLE']; - result = result.concat(truncate.nodes.map(this.visit.bind(this))); - return result; -}; - -Postgres.prototype.visitDistinct = function(truncate) { - // Nothing to do here since it's handled in the SELECT clause - return []; -}; - -Postgres.prototype.visitDistinctOn = function(distinctOn) { - return ['DISTINCT ON('+distinctOn.nodes.map(this.visit.bind(this)).join(', ')+')']; -}; - -Postgres.prototype.visitAlias = function(alias) { - var result = [this.visit(alias.value) + this._aliasText + this.quote(alias.alias)]; - return result; -}; - -Postgres.prototype.visitAlter = function(alter) { - this._visitingAlter = true; - // don't auto-generate from clause - var table = this._queryNode.table; - var result = [ - 'ALTER TABLE', - this.visit(table.toNode()), - alter.nodes.map(this.visit.bind(this)).join(', ') - ]; - this._visitingAlter = false; - return result; -}; - -Postgres.prototype.visitCast = function(cast) { - this._visitingCast = true; - var result = ['CAST(' + this.visit(cast.value) + ' AS ' + cast.dataType + ')']; - this._visitingCast = false; - return result; -}; - -Postgres.prototype.visitFrom = function(from) { - var result = []; - if (from.skipFromStatement) { - result.push(','); - } else { - result.push('FROM'); - } - for(var i = 0; i < from.nodes.length; i++) { - result = result.concat(this.visit(from.nodes[i])); - } - return result; -}; - -Postgres.prototype.visitWhere = function(where) { - this._visitingWhere = true; - var result = ['WHERE', where.nodes.map(this.visit.bind(this)).join(', ')]; - this._visitingWhere = false; - return result; -}; - -Postgres.prototype.visitOrderBy = function(orderBy) { - var result = ['ORDER BY', orderBy.nodes.map(this.visit.bind(this)).join(', ')]; - if (this._myClass === Postgres && this.config.nullOrder) { - result.push('NULLS ' + this.config.nullOrder.toUpperCase()); - } - return result; -}; - -Postgres.prototype.visitOrderByValue = function(orderByValue) { - var text = this.visit(orderByValue.value); - if (orderByValue.direction) { - text += ' ' + this.visit(orderByValue.direction); - } - return [text]; -}; - -Postgres.prototype.visitGroupBy = function(groupBy) { - var result = ['GROUP BY', groupBy.nodes.map(this.visit.bind(this)).join(', ')]; - return result; -}; - -Postgres.prototype.visitHaving = function(having) { - var result = ['HAVING', having.nodes.map(this.visit.bind(this)).join(' AND ')]; - return result; -}; - -Postgres.prototype.visitPrefixUnary = function(unary) { - var text = '(' + unary.operator + ' ' + this.visit(unary.left) + ')'; - return [text]; -}; - -Postgres.prototype.visitPostfixUnary = function(unary) { - var text = '(' + this.visit(unary.left) + ' ' + unary.operator + ')'; - return [text]; -}; - -Postgres.prototype.visitBinary = function(binary) { - var self = this; - - binary.left.property = binary.left.name; - binary.right.property = binary.right.name; - - var text = '(' + this.visit(binary.left) + ' ' + binary.operator + ' '; - if (Array.isArray(binary.right)) { - text += '(' + binary.right.map(function (node) { - return self.visit(node); - }).join(', ') + ')'; - } - else { - text += this.visit(binary.right); - } - text += ')'; - return [text]; -}; - -Postgres.prototype.visitTernary = function(ternary) { - var self = this; - var text = '(' + this.visit(ternary.left) + ' ' + ternary.operator + ' '; - - var visitPart = function(value) { - var text = ''; - if (Array.isArray(value)) { - text += '(' + value.map(function (node) { - return self.visit(node); - }).join(', ') + ')'; - } - else { - text += self.visit(value); - } - return text; - }; - - text += visitPart(ternary.middle); - text += ' ' + ternary.separator + ' '; - text += visitPart(ternary.right); - - text += ')'; - return [text]; -}; - -Postgres.prototype.visitIn = function(binary) { - var self = this; - var text = '('; - - if (Array.isArray(binary.right)) { - if (binary.right.length) { - var params = []; - var hasNull = false; - - binary.right.forEach(function(node) { - if (node.type === 'PARAMETER' && node._val === null) { - hasNull = true; - } else { - params.push(self.visit(node)); - } - }); - - if (params.length) { - text += this.visit(binary.left) + ' IN (' + params.join(', ') + ')'; - - if (hasNull) { - text += ' OR ' + this.visit(binary.left) + ' IS NULL'; - } - } else { // implicitely has null - text += this.visit(binary.left) + ' IS NULL'; - } - } else { - text += '1=0'; - } - } else { - text += this.visit(binary.left) + ' IN ' + this.visit(binary.right); - } - - text += ')'; - return [text]; -}; - -Postgres.prototype.visitNotIn = function(binary) { - var self = this; - var text = '('; - - if (Array.isArray(binary.right)) { - if (binary.right.length) { - var params = []; - var hasNull = false; - - binary.right.forEach(function(node) { - if (node.type === 'PARAMETER' && node._val === null) { - hasNull = true; - } else { - params.push(self.visit(node)); - } - }); - - if (params.length && hasNull) { - text += 'NOT ('; - text += this.visit(binary.left) + ' IN (' + params.join(', ') + ')'; - text += ' OR ' + this.visit(binary.left) + ' IS NULL'; - text += ')'; - } else if (params.length) { - text += this.visit(binary.left) + ' NOT IN (' + params.join(', ') + ')'; - } else { // implicitely has null - text += this.visit(binary.left) + ' IS NOT NULL'; - } - } else { - text += '1=1'; - } - } else { - text += this.visit(binary.left) + ' NOT IN ' + this.visit(binary.right); - } - - text += ')'; - return [text]; -}; - -Postgres.prototype.visitCase = function(caseExp) { - assert(caseExp.whenList.length == caseExp.thenList.length); - - var self = this; - var text = '(CASE'; - - this.visitingCase = true; - - for (var i = 0; i < caseExp.whenList.length; i++) { - var whenExp = ' WHEN ' + this.visit(caseExp.whenList[i]); - var thenExp = ' THEN ' + this.visit(caseExp.thenList[i]); - text += whenExp + thenExp; - } - - if (null !== caseExp.else && undefined !== caseExp.else) { - text += ' ELSE ' + this.visit(caseExp.else); - } - - this.visitingCase = false; - - text += ' END)'; - return [text]; -}; - -Postgres.prototype.visitAt = function(at) { - var text = '(' + this.visit(at.value) + ')[' + this.visit(at.index) + ']'; - return [text]; -}; - -Postgres.prototype.visitSlice = function(slice) { - var text = '(' + this.visit(slice.value) + ')'; - text += '[' + this.visit(slice.start) + ':' + this.visit(slice.end) + ']'; - return [text]; -}; - -Postgres.prototype.visitContains = function(contains) { - var text = this.visit(contains.value); - text += ' @> ' + this.visit(contains.set); - return [text]; -}; - -Postgres.prototype.visitContainedBy = function(containedBy) { - var text = this.visit(containedBy.value); - text += ' <@ ' + this.visit(containedBy.set); - return [text]; -}; - -Postgres.prototype.visitOverlap = function(overlap) { - var text = this.visit(overlap.value); - text += ' && ' + this.visit(overlap.set); - return [text]; -}; - -Postgres.prototype.visitQuery = function(queryNode) { - if (this._queryNode) return this.visitSubquery(queryNode,dontParenthesizeSubQuery(this._queryNode)); - this._queryNode = queryNode; - // need to sort the top level query nodes on visitation priority - // so select/insert/update/delete comes before from comes before where - var missingFrom = true; - var hasFrom = false; - var createView; - var isSelect = false; - var actions = []; - var targets = []; - var filters = []; - for(var i = 0; i < queryNode.nodes.length; i++) { - var node = queryNode.nodes[i]; - switch(node.type) { - case "SELECT": - isSelect = true; // jshint ignore:line - case "DELETE": - actions.push(node); - break; - case "INDEXES": - case "INSERT": - case "REPLACE": - case "UPDATE": - case "CREATE": - case "DROP": - case "TRUNCATE": - case "ALTER": - actions.push(node); - missingFrom = false; - break; - case "FROM": - node.skipFromStatement = hasFrom; - hasFrom = true; - missingFrom = false; - targets.push(node); - break; - case "CREATE VIEW": - createView = node; - break; - default: - filters.push(node); - break; - } - } - if(!actions.length) { - // if no actions are given, guess it's a select - actions.push(new Select().add('*')); - isSelect = true; - } - if(missingFrom && queryNode.table instanceof Table) { - // the instanceof handles the situation where a sql.select(some expression) is used and there should be no FROM clause - targets.push(new From().add(queryNode.table)); - } - if (createView) { - if (isSelect) { - actions.unshift(createView); - } else { - throw new Error('Create View requires a Select.'); - } - } - return this.visitQueryHelper(actions,targets,filters); -}; - -/** - * We separate out this part of query building so it can be overridden by other implementations. - * - * @param {Node[]} actions - * @param {Node[]} targets - * @param {Node[]} filters - * @returns {String[]} - */ -Postgres.prototype.visitQueryHelper=function(actions,targets,filters){ - this.handleDistinct(actions, filters); - // lazy-man sorting - var sortedNodes = actions.concat(targets).concat(filters); - for(var i = 0; i < sortedNodes.length; i++) { - var res = this.visit(sortedNodes[i]); - this.output = this.output.concat(res); - } - // implicit 'from' - return this.output; -}; - -Postgres.prototype.visitSubquery = function(queryNode,dontParenthesize) { - // create another query builder of the current class to build the subquery - var subQuery = new this._myClass(this.config); - - // let the subquery modify this instance's params array - subQuery.params = this.params; - - // pass on the disable parameter placeholder flag - var previousFlagStatus = subQuery._disableParameterPlaceholders; - subQuery._disableParameterPlaceholders = this._disableParameterPlaceholders; - try { - subQuery.visitQuery(queryNode); - } finally { - // restore the flag - subQuery._disableParameterPlaceholders = previousFlagStatus; - } - - var alias = queryNode.alias; - if (dontParenthesize) { - return [subQuery.output.join(' ') + (alias ? ' ' + this.quote(alias) : '')]; - } - return ['(' + subQuery.output.join(' ') + ')' + (alias ? ' ' + this.quote(alias) : '')]; -}; - -Postgres.prototype.visitTable = function(tableNode) { - var table = tableNode.table; - var txt=""; - if(table.getSchema()) { - txt = this.quote(table.getSchema()); - txt += '.'; - } - txt += this.quote(table.getName()); - if(typeof table.alias === 'string') { - txt += this._aliasText + this.quote(table.alias); - } - return [txt]; -}; - -Postgres.prototype.visitColumn = function(columnNode) { - var table = columnNode.table; - var inInsertUpdateClause = this._visitedInsert || this._visitedReplace || this._visitingUpdateTargetColumn; - var inDdlClause = this._visitingAddColumn || this._visitingAlter || this._visitingCreate; - var inSelectClause = - this.visitingReturning || - (!this._selectOrDeleteEndIndex - && !this._visitingWhere // jshint ignore:line - && !inInsertUpdateClause // jshint ignore:line - && !inDdlClause // jshint ignore:line - && !this.visitingCase // jshint ignore:line - && !this._visitingJoin // jshint ignore:line - ); - var inFunctionCall = this._visitingFunctionCall; - var inCast = this._visitingCast; - var txt = []; - var closeParen = 0; - if(inSelectClause && (table && !table.alias || !!columnNode.alias)) { - if (columnNode.asArray) { - closeParen++; - txt.push(this._arrayAggFunctionName+'('); - } - - if (!!columnNode.aggregator) { - closeParen++; - txt.push(columnNode.aggregator + '('); - } - - if (columnNode.distinct === true) { - closeParen++; - txt.push('DISTINCT('); - } - } - if(!inInsertUpdateClause && !this.visitingReturning && !this._visitingCreate && !this._visitingAlter && !columnNode.subfieldContainer) { - if (table) { - if (typeof table.alias === 'string') { - txt.push(this.quote(table.alias)); - } else { - if (table.getSchema()) { - txt.push(this.quote(table.getSchema())); - txt.push('.'); - } - txt.push(this.quote(table.getName())); - } - txt.push('.'); - } - } - if (columnNode.star) { - var allCols = []; - var hasAliases = false; - if(columnNode.aggregator !== 'COUNT') { - var tableName = txt.join(''); - for (var i = 0; i < table.columns.length; ++i) { - var col = table.columns[i]; - var aliased = col.name !== (col.alias || col.property); - hasAliases = hasAliases || aliased; - allCols.push(tableName + this.quote(col.name) + (aliased ? this._aliasText + this.quote(col.alias || col.property) : '')); - } - } - if(hasAliases) { - txt = [allCols.join(', ')]; - } - else { - txt.push('*'); - } - } - else if (columnNode.isConstant) { - // this injects directly into SELECT statement rather than creating a parameter - // txt.push(this._getParameterValue(columnNode.literalValue)) - // currently thinking it is better to generate a parameter - var value = columnNode.constantValue; - this.params.push(value); - txt.push(this._getParameterText(this.params.length, value)); - } - else { - if (columnNode.subfieldContainer) { - txt.push('(' + this.visitColumn(columnNode.subfieldContainer) + ').'); - } - txt.push(this.quote(columnNode.name)); - } - if(closeParen) { - for(var j = 0; j < closeParen; j++) { - txt.push(')'); - } - } - if(inSelectClause && !inFunctionCall && !inCast && (columnNode.alias || columnNode.property !== columnNode.name)) { - txt.push(this._aliasText + this.quote(columnNode.alias || columnNode.property)); - } - if(this._visitingCreate || this._visitingAddColumn) { - assert(columnNode.dataType, 'dataType missing for column ' + columnNode.name + - ' (CREATE TABLE and ADD COLUMN statements require a dataType)'); - txt.push(' ' + columnNode.dataType); - - if (this._visitingCreate) { - if (columnNode.primaryKey && !this._visitCreateCompoundPrimaryKey) { - // creating a column as a primary key - txt.push(' PRIMARY KEY'); - } else if (columnNode.notNull) { - txt.push(' NOT NULL'); - } - if (!columnNode.primaryKey && columnNode.unique) { - txt.push(' UNIQUE'); - } - if (columnNode.defaultValue !== undefined) { - txt.push(' DEFAULT ' + this._getParameterValue(columnNode.defaultValue)); - } - } - - if (!!columnNode.references) { - assert.equal(typeof (columnNode.references), 'object', - 'references is not a object for column ' + columnNode.name + - ' (REFERENCES statements within CREATE TABLE and ADD COLUMN statements' + - ' require refrences to be expressed as an object)'); - - //Empty refrence objects are ok - if (Object.keys(columnNode.references).length > 0){ - assert(columnNode.references.table, 'reference.table missing for column ' + - columnNode.name + - ' (REFERENCES statements within CREATE TABLE and ADD COLUMN statements' + - ' require a table and column)'); - assert(columnNode.references.column, 'reference.column missing for column ' + - columnNode.name + - ' (REFERENCES statements within CREATE TABLE and ADD COLUMN statements' + - ' require a table and column)'); - txt.push(' REFERENCES '); - if(columnNode.references.schema) { - txt.push(this.quote(columnNode.references.schema) + '.'); - } - txt.push(this.quote(columnNode.references.table) + '(' + - this.quote(columnNode.references.column) + ')'); - - var onDelete = columnNode.references.onDelete; - if (onDelete) onDelete = onDelete.toUpperCase(); - if (onDelete === 'CASCADE' || onDelete === 'RESTRICT' || onDelete === 'SET NULL' || onDelete === 'SET DEFAULT' || onDelete === 'NO ACTION') { - txt.push(' ON DELETE ' + onDelete); - } - var onUpdate = columnNode.references.onUpdate; - if (onUpdate) onUpdate = onUpdate.toUpperCase(); - if (onUpdate === 'CASCADE' || onUpdate === 'RESTRICT' || onUpdate === 'SET NULL' || onUpdate === 'SET DEFAULT' || onUpdate === 'NO ACTION') { - txt.push(' ON UPDATE ' + onUpdate); - } - var constraint = columnNode.references.constraint; - if (constraint) { - constraint = ' ' + constraint.toUpperCase(); - txt.push(constraint); - } - } - } - } - return [txt.join('')]; -}; - -Postgres.prototype.visitForeignKey = function(foreignKeyNode) -{ - var txt = []; - if(this._visitingCreate) { - assert(foreignKeyNode.table, 'Foreign table missing for table reference'); - assert(foreignKeyNode.columns, 'Columns missing for table reference'); - if(foreignKeyNode.refColumns !== undefined) { - assert.equal(foreignKeyNode.columns.length, foreignKeyNode.refColumns.length, 'Number of local columns and foreign columns differ in table reference'); - } - if(foreignKeyNode.name !== undefined) { - txt.push('CONSTRAINT ' + this.quote(foreignKeyNode.name) + ' '); - } - txt.push('FOREIGN KEY ( '); - for(var i = 0; i < foreignKeyNode.columns.length; i++) { - if(i>0) { - txt.push(', '); - } - txt.push(this.quote(foreignKeyNode.columns[i])); - } - txt.push(' ) REFERENCES '); - if(foreignKeyNode.schema !== undefined) { - txt.push(this.quote(foreignKeyNode.schema) + '.'); - } - txt.push(this.quote(foreignKeyNode.table)); - if(foreignKeyNode.refColumns !== undefined) { - txt.push(' ( '); - for(i = 0; i < foreignKeyNode.refColumns.length; i++) { - if(i>0) { - txt.push(', '); - } - txt.push(this.quote(foreignKeyNode.refColumns[i])); - } - txt.push(' )'); - } - var onDelete = foreignKeyNode.onDelete; - if(onDelete) { - onDelete = onDelete.toUpperCase(); - if(onDelete === 'CASCADE' || onDelete === 'RESTRICT' || onDelete === 'SET NULL' || onDelete === 'SET DEFAULT' || onDelete === 'NO ACTION') { - txt.push(' ON DELETE ' + onDelete); - } - } - var onUpdate = foreignKeyNode.onUpdate; - if(onUpdate) { - onUpdate = onUpdate.toUpperCase(); - if(onUpdate === 'CASCADE' || onUpdate === 'RESTRICT' || onUpdate === 'SET NULL' || onUpdate === 'SET DEFAULT' || onUpdate === 'NO ACTION') { - txt.push(' ON UPDATE ' + onUpdate); - } - } - if(foreignKeyNode.constraint) { - txt.push(' ' + foreignKeyNode.constraint.toUpperCase()); - } - } - return [txt.join('')]; -}; - -Postgres.prototype.visitFunctionCall = function(functionCall) { - this._visitingFunctionCall = true; - var _this = this; - - function _extract() { - var nodes = functionCall.nodes.map(_this.visit.bind(_this)); - if (nodes.length != 1) throw new Error('Not enough parameters passed to ' + functionCall.name + ' function'); - var txt = 'EXTRACT(' + functionCall.name + ' FROM ' + (nodes[0]+'') + ')'; - return txt; - } - - var txt = ""; - // Override date functions since postgres (and others) uses extract - if (['YEAR', 'MONTH', 'DAY', 'HOUR'].indexOf(functionCall.name) >= 0) txt = _extract(); - // Override CURRENT_TIMESTAMP function to remove parens - else if ('CURRENT_TIMESTAMP' == functionCall.name) txt = functionCall.name; - else txt = functionCall.name + '(' + functionCall.nodes.map(this.visit.bind(this)).join(', ') + ')'; - this._visitingFunctionCall = false; - return [txt]; -}; - -Postgres.prototype.visitArrayCall = function(arrayCall) { - var txt = 'ARRAY[' + arrayCall.nodes.map(this.visit.bind(this)).join(', ') + ']'; - return [txt]; -}; - -Postgres.prototype.visitParameter = function(parameter) { - // save the value into the parameters array - var value = parameter.value(); - this.params.push(value); - return parameter.isExplicit ? [] : [this._getParameterText(this.params.length, value)]; -}; - -Postgres.prototype.visitDefault = function(parameter) { - /* jshint unused: false */ - return ['DEFAULT']; -}; - -Postgres.prototype.visitAddColumn = function(addColumn) { - this._visitingAddColumn = true; - var result = ['ADD COLUMN ' + this.visit(addColumn.nodes[0])]; - this._visitingAddColumn = false; - return result; -}; - -Postgres.prototype.visitDropColumn = function(dropColumn) { - return ['DROP COLUMN ' + this.visit(dropColumn.nodes[0])]; -}; - -Postgres.prototype.visitRenameColumn = function(renameColumn) { - return ['RENAME COLUMN ' + this.visit(renameColumn.nodes[0]) + ' TO ' + this.visit(renameColumn.nodes[1])]; -}; - -Postgres.prototype.visitRename = function(rename) { - return ['RENAME TO ' + this.visit(rename.nodes[0])]; -}; - -Postgres.prototype.visitIfExists = function() { - return ['IF EXISTS']; -}; - -Postgres.prototype.visitIfNotExists = function() { - return ['IF NOT EXISTS']; -}; - -Postgres.prototype.visitOrIgnore = function() { - throw new Error('PostgreSQL does not allow orIgnore clause.'); -}; - -Postgres.prototype.visitCascade = function() { - return ['CASCADE']; -}; - -Postgres.prototype.visitRestrict = function() { - return ['RESTRICT']; -}; - -Postgres.prototype.visitForUpdate = function() { - return ['FOR UPDATE']; -}; - -Postgres.prototype.visitForShare = function() { - return ['FOR SHARE']; -}; - -Postgres.prototype.visitJoin = function(join) { - var result = []; - this._visitingJoin = true; - result = result.concat(this.visit(join.from)); - result = result.concat(join.subType + ' JOIN'); - result = result.concat(this.visit(join.to)); - result = result.concat('ON'); - result = result.concat(this.visit(join.on)); - return result; -}; - -Postgres.prototype.visitLiteral = function(node) { - var txt = [node.literal]; - if(node.alias) { - txt.push(this._aliasText + this.quote(node.alias)); - } - return [txt.join('')]; -}; - -Postgres.prototype.visitReturning = function(returning) { - this.visitingReturning = true; - var r = ['RETURNING', returning.nodes.map(this.visit.bind(this)).join(', ')]; - this.visitingReturning = false; - - return r; -}; - -Postgres.prototype.visitOnDuplicate = function(onDuplicate) { - throw new Error('PostgreSQL does not allow onDuplicate clause.'); -}; - -Postgres.prototype.visitOnConflict = function(onConflict) { - var result = ['ON CONFLICT']; - var columns = []; - var updateClause = [], i, col; - var table = this._queryNode.table; - if(onConflict.constraint) - result.push(['ON CONSTRAINT', this.quote(onConflict.constraint)].join(' ')); - else if(onConflict.columns) { - for(i=0; i < onConflict.columns.length; i++) { - columns.push(this.quote(table.getColumn(onConflict.columns[i]).name)); - } - result.push( '(' + columns.join(', ') + ')' ); - } - - if(onConflict.update){ - updateClause.push("DO UPDATE SET"); - var update = onConflict.update; - var setClause = []; - for(i=0; i { + let year = date.getUTCFullYear(); + const isBCYear = year < 1; + if (isBCYear) year = Math.abs(year) + 1; // negative years are 1 off their BC representation + + let ret = + padStart(String(year), 4, '0') + + '-' + + padStart(String(date.getUTCMonth() + 1), 2, '0') + + '-' + + padStart(String(date.getUTCDate()), 2, '0') + + 'T' + + padStart(String(date.getUTCHours()), 2, '0') + + ':' + + padStart(String(date.getUTCMinutes()), 2, '0') + + ':' + + padStart(String(date.getUTCSeconds()), 2, '0') + + '.' + + padStart(String(date.getUTCMilliseconds()), 3, '0'); + + ret += 'Z'; + if (isBCYear) ret += ' BC'; + return ret; +} + +/** + * Config can contain: + * + * nullOrder: 'first' | 'last' + * + * @param config + * @constructor + */ +export class Postgres extends Dialect<{ nullOrder?: string }> { + constructor(config: { nullOrder?: string }) { + super(config); + } + + protected createSubInstance() { + return new Postgres(this.config); + } + + public _getParameterValue( + value: null | boolean | number | string | any[] | Date | Buffer | Record, + quoteChar?: string + ): string | number { + if ('object' === typeof value && Array.isArray(value)) { + // naive check to see if this is an array of objects, which + // is handled differently than an array of primitives + if (value.length && 'object' === typeof value[0] && !isFunction(value[0].toISOString) && !Array.isArray(value[0])) { + value = `'${JSON.stringify(value)}'`; + } else { + // In a Postgres array, strings must be double-quoted + value = value.map((item) => this._getParameterValue(item, '"')); + value = `'{${(value as any[]).join(',')}}'`; + } + } else if ('object' === typeof value && value instanceof Date) { + // Date object's default toString format does not get parsed well + // Handle dates using custom dateToString method for postgres + value = this._getParameterValue(dateToStringUTC(value), quoteChar); + } else { + value = super._getParameterValue(value, quoteChar); + } + // value has been converted at this point + return value; + } + public visitOrderBy(orderByNode: OrderByNode): string[] { + const result = ['ORDER BY', orderByNode.nodes.map(this.visit.bind(this)).join(', ')]; + if (this.config.nullOrder) { + result.push('NULLS ' + this.config.nullOrder.toUpperCase()); + } + return result; + } +} diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js deleted file mode 100644 index 60d46997..00000000 --- a/lib/dialect/sqlite.js +++ /dev/null @@ -1,205 +0,0 @@ -'use strict'; - -var _ = require('lodash'); -var util = require('util'); -var assert = require('assert'); - -var Sqlite = function(config) { - this.output = []; - this.params = []; - this._hasAddedAColumn = false; - this.config = config || {}; -}; - -var Postgres = require('./postgres'); - -util.inherits(Sqlite, Postgres); - -Sqlite.prototype._myClass = Sqlite; - -Sqlite.prototype._arrayAggFunctionName = 'GROUP_CONCAT'; - -Sqlite.prototype.visitReplace = function(replace) { - var self = this; - // don't use table.column for replaces - this._visitedReplace = true; - - var result = ['REPLACE']; - result = result.concat(replace.nodes.map(this.visit.bind(this))); - result.push('INTO ' + this.visit(this._queryNode.table.toNode())); - result.push('(' + replace.columns.map(this.visit.bind(this)).join(', ') + ')'); - - var paramNodes = replace.getParameters(); - - if (paramNodes.length > 0) { - var paramText = paramNodes.map(function (paramSet) { - return paramSet.map(function (param) { - return self.visit(param); - }).join(', '); - }).map(function (param) { - return '('+param+')'; - }).join(', '); - - result.push('VALUES', paramText); - - if (result.slice(2, 5).join(' ') === '() VALUES ()') { - result.splice(2, 3, 'DEFAULT VALUES'); - } - } - - this._visitedReplace = false; - - return result; -}; - -Sqlite.prototype._getParameterValue = function(value) { - if (Buffer.isBuffer(value)) { - value = 'x' + this._getParameterValue(value.toString('hex')); - } else if (value instanceof Date && this.config.dateTimeMillis) { - value = value.getTime(); - } else if('boolean' === typeof value) { - value = value ? 1 : 0; - } else if(_.isArray(value)) { - value = Postgres.prototype._getParameterValue.call(this, JSON.stringify(value)); - } else { - value = Postgres.prototype._getParameterValue.call(this, value); - } - return value; -}; - -Sqlite.prototype.visitDefault = function() { - throw new Error('SQLite requires that all rows of a multi-row insert are for the same columns.'); -}; - -Sqlite.prototype.visitDropColumn = function() { - throw new Error('SQLite does not allow dropping columns.'); -}; - -Sqlite.prototype.visitFunctionCall = function (functionCall) { - var _this = this; - - this._visitingFunctionCall = true; - - function _left() { - // convert LEFT(column,4) to SUBSTR(column,1,4) - var nodes = functionCall.nodes.map(_this.visit.bind(_this)); - if (nodes.length != 2) throw new Error('Not enough parameters passed to LEFT function.'); - var txt = "SUBSTR(" + (nodes[0] + '') + ', 1, ' + (nodes[1] + '') + ')'; - return txt; - } - - function _right() { - // convert RIGHT(column,4) to SUBSTR(column,-4) - var nodes = functionCall.nodes.map(_this.visit.bind(_this)); - if (nodes.length != 2) throw new Error('Not enough parameters passed to RIGHT function.'); - var txt = "SUBSTR(" + (nodes[0] + '') + ', -' + (nodes[1] + '') + ')'; - return txt; - } - - function _extract() { - var nodes = functionCall.nodes.map(_this.visit.bind(_this)); - if (nodes.length != 1) throw new Error('Not enough parameters passed to ' + functionCall.name + ' function'); - var format; - switch (functionCall.name) { - case 'YEAR': - format = "'%Y'"; - break; - case 'MONTH': - format = "'%m'"; - break; - case 'DAY': - format = "'%d'"; - break; - case 'HOUR': - format = "'%H'"; - break; - } - var col = (nodes[0] + ''); - if (_this.config.dateTimeMillis) { - // Convert to a datetime before running the strftime function - // Sqlite unix epoch is in seconds, but javascript is milliseconds. - col = 'datetime(' + col + '/1000, "unixepoch")'; - } - var txt = 'strftime(' + format + ', ' + col + ')'; - return txt; - } - - var txt = ""; - var name = functionCall.name; - // Override LEFT and RIGHT and convert to SUBSTR - if (name == "LEFT") txt = _left(); - else if (name == "RIGHT") txt = _right(); - // Override date functions since sqlite uses strftime - else if (['YEAR', 'MONTH', 'DAY', 'HOUR'].indexOf(functionCall.name) >= 0) txt = _extract(); - else if ('CURRENT_TIMESTAMP' == functionCall.name) txt = functionCall.name; - else txt = name + '(' + functionCall.nodes.map(this.visit.bind(this)).join(', ') + ')'; - - this._visitingFunctionCall = false; - return [txt]; -}; - -Sqlite.prototype.visitTruncate = function(truncate) { - var result = ['DELETE FROM']; - result = result.concat(truncate.nodes.map(this.visit.bind(this))); - return result; -}; - -Sqlite.prototype.visitRenameColumn = function() { - throw new Error('SQLite does not allow renaming columns.'); -}; - -Sqlite.prototype.visitOnDuplicate = function() { - throw new Error('SQLite does not allow onDuplicate clause.'); -}; - -Sqlite.prototype.visitOnConflict = function(onConflict) { - throw new Error('Sqlite does not allow onConflict clause.'); -}; - -Sqlite.prototype.visitReturning = function() { - throw new Error('SQLite does not allow returning clause.'); -}; - -Sqlite.prototype.visitForUpdate = function() { - throw new Error('SQLite does not allow FOR UPDATE clause.'); -}; - -Sqlite.prototype.visitForShare = function() { - throw new Error('SQLite does not allow FOR SHARE clause.'); -}; - -Sqlite.prototype.visitAddColumn = function(addColumn) { - assert(!this._hasAddedAColumn, 'SQLite can not add more that one column at a time'); - var result = Postgres.prototype.visitAddColumn.call(this, addColumn); - this._hasAddedAColumn = true; - return result; -}; - -Sqlite.prototype.visitIndexes = function(node) { - var tableName = this.visit(this._queryNode.table.toNode())[0]; - return "PRAGMA INDEX_LIST(" + tableName + ")"; -}; - -Sqlite.prototype.visitCascade = function() { - throw new Error('Sqlite do not support CASCADE in DROP TABLE'); -}; - -Sqlite.prototype.visitRestrict = function() { - throw new Error('Sqlite do not support RESTRICT in DROP TABLE'); -}; - -Sqlite.prototype.visitBinary = function(binary) { - if(binary.operator === '@@'){ - binary.operator = 'MATCH'; - var ret = Sqlite.super_.prototype.visitBinary.call(this, binary); - binary.operator = '@@'; - return ret; - } - return Sqlite.super_.prototype.visitBinary.call(this, binary); -}; - -Sqlite.prototype.visitOrIgnore = function() { - return ['OR IGNORE']; -}; - -module.exports = Sqlite; diff --git a/lib/dialect/sqlite.ts b/lib/dialect/sqlite.ts new file mode 100644 index 00000000..37e063dc --- /dev/null +++ b/lib/dialect/sqlite.ts @@ -0,0 +1,215 @@ +import assert from 'assert'; +import isArray from 'lodash/isArray.js'; + +import { AddColumnNode } from '../node/addColumn.js'; +import { AsOfNode } from '../node/asOf.js'; +import { BinaryNode } from '../node/binary.js'; +import { CascadeNode } from '../node/cascade.js'; +import { CreateIndexNode } from '../node/createIndex.js'; +import { DefaultNode } from '../node/default.js'; +import { DropColumnNode } from '../node/dropColumn.js'; +import { ForShareNode } from '../node/forShare.js'; +import { ForUpdateNode } from '../node/forUpdate.js'; +import { FunctionCallNode } from '../node/functionCall.js'; +import { IndexesNode } from '../node/indexes.js'; +import { OnConflictNode } from '../node/onConflict.js'; +import { OnDuplicateNode } from '../node/onDuplicate.js'; +import { OrIgnoreNode } from '../node/orIgnore.js'; +import { RenameColumnNode } from '../node/renameColumn.js'; +import { ReplaceNode } from '../node/replace.js'; +import { RestrictNode } from '../node/restrict.js'; +import { ReturningNode } from '../node/returning.js'; +import { TruncateNode } from '../node/truncate.js'; +import { Dialect } from './dialect.js'; + +export class Sqlite extends Dialect<{ dateTimeMillis?: boolean }> { + protected hasAddedAColumn: boolean = false; + constructor(config: { dateTimeMillis?: boolean }) { + super(config); + this.config = config; + this.arrayAggFunctionName = 'GROUP_CONCAT'; + } + protected createSubInstance() { + return new Sqlite(this.config); + } + public _getParameterValue( + value: null | boolean | number | string | any[] | Date | Buffer | Record, + quoteChar?: string + ): string | number { + if (Buffer.isBuffer(value)) { + value = 'x' + this._getParameterValue(value.toString('hex'), quoteChar); + } else if (value instanceof Date && this.config.dateTimeMillis) { + value = value.getTime(); + } else if ('boolean' === typeof value) { + value = value ? 1 : 0; + } else if (isArray(value)) { + value = super._getParameterValue(JSON.stringify(value), quoteChar); + } else { + value = super._getParameterValue(value, quoteChar); + } + return value; + } + public visitAsOf(asOfNode: AsOfNode): string[] { + throw new Error('SQLite does not support AS OF.'); + } + public visitReplace(replaceNode: ReplaceNode): string[] { + // don't use table.column for replaces + this.visitedReplace = true; + let result = ['REPLACE']; + result = result.concat(replaceNode.nodes.map((n) => this.visit(n).join())); + result.push('INTO ' + this.visit(this.queryNode!.table.toNode())); + result.push('(' + replaceNode.columns.map(this.visit.bind(this)).join(', ') + ')'); + const paramNodes = replaceNode.getParameters(); + if (paramNodes.length > 0) { + const paramText = paramNodes + .map((paramSet) => { + return paramSet.map((param) => this.visit(param)).join(', '); + }) + .map((param) => `(${param})`) + .join(', '); + result.push('VALUES', paramText); + if (result.slice(2, 5).join(' ') === '() VALUES ()') { + result.splice(2, 3, 'DEFAULT VALUES'); + } + } + this.visitedReplace = false; + return result; + } + public visitDefault(defaultNode: DefaultNode): string[] { + throw new Error('SQLite requires that all rows of a multi-row insert are for the same columns.'); + } + public visitDropColumn(dropColumnNode: DropColumnNode): string[] { + throw new Error('SQLite does not allow dropping columns.'); + } + public visitFunctionCall(functionCallNode: FunctionCallNode): string[] { + this.visitingFunctionCall = true; + const left = () => { + // convert LEFT(column,4) to SUBSTR(column,1,4) + const nodes = functionCallNode.nodes.map(this.visit.bind(this)); + if (nodes.length !== 2) { + throw new Error('Not enough parameters passed to LEFT function.'); + } + return `SUBSTR(${nodes[0] + ''}, 1, ${nodes[1] + ''})`; + }; + const right = () => { + // convert RIGHT(column,4) to SUBSTR(column,-4) + const nodes = functionCallNode.nodes.map(this.visit.bind(this)); + if (nodes.length !== 2) { + throw new Error('Not enough parameters passed to RIGHT function.'); + } + return `SUBSTR(${nodes[0] + ''}, -${nodes[1] + ''})`; + }; + const extract = () => { + const nodes = functionCallNode.nodes.map(this.visit.bind(this)); + if (nodes.length !== 1) { + throw new Error(`Not enough parameters passed to ${functionCallNode.name} function`); + } + let format; + switch (functionCallNode.name) { + case 'YEAR': + format = "'%Y'"; + break; + case 'MONTH': + format = "'%m'"; + break; + case 'DAY': + format = "'%d'"; + break; + case 'HOUR': + format = "'%H'"; + break; + } + let col = nodes[0] + ''; + if (this.config.dateTimeMillis) { + // Convert to a datetime before running the strftime function + // Sqlite unix epoch is in seconds, but javascript is milliseconds. + col = `datetime(${col}/1000, "unixepoch")`; + } + return `strftime(${format}, ${col})`; + }; + let txt = ''; + const name = functionCallNode.name; + // Override LEFT and RIGHT and convert to SUBSTR + if (name === 'LEFT') { + txt = left(); + } else if (name === 'RIGHT') { + txt = right(); + } + // Override date functions since sqlite uses strftime + else if (['YEAR', 'MONTH', 'DAY', 'HOUR'].indexOf(functionCallNode.name) >= 0) { + txt = extract(); + } else if ('CURRENT_TIMESTAMP' === functionCallNode.name) { + txt = functionCallNode.name; + } else { + txt = `${name}(${functionCallNode.nodes.map(this.visit.bind(this)).join(', ')})`; + } + this.visitingFunctionCall = false; + return [txt]; + } + public visitTruncate(truncateNode: TruncateNode): string[] { + const result = ['DELETE FROM']; + return result.concat(truncateNode.nodes.map((n) => this.visit(n).join())); + } + public visitRenameColumn(renameColumnNode: RenameColumnNode): string[] { + throw new Error('SQLite does not allow renaming columns.'); + } + public visitOnDuplicate(onDuplicateNode: OnDuplicateNode): string[] { + throw new Error('SQLite does not allow onDuplicate clause.'); + } + public visitOnConflict(onConflictNode: OnConflictNode): string[] { + throw new Error('Sqlite does not allow onConflict clause.'); + } + public visitReturning(returningNode: ReturningNode): string[] { + throw new Error('SQLite does not allow returning clause.'); + } + public visitForUpdate(forUpdateNode: ForUpdateNode): string[] { + throw new Error('SQLite does not allow FOR UPDATE clause.'); + } + public visitForShare(forShareNode: ForShareNode): string[] { + throw new Error('SQLite does not allow FOR SHARE clause.'); + } + public visitAddColumn(addColumnNode: AddColumnNode): string[] { + assert(!this.hasAddedAColumn, 'SQLite can not add more that one column at a time'); + const result = super.visitAddColumn.call(this, addColumnNode); + this.hasAddedAColumn = true; + return result; + } + public visitIndexes(indexesNode: IndexesNode): string[] { + const tableName = this.visit(this.queryNode!.table.toNode())[0]; + return [`PRAGMA INDEX_LIST(${tableName})`]; + } + public visitCreateIndex(createIndexNode: CreateIndexNode): string[] { + const { indexType, ifNotExists, indexName, tableName, algorithm, columns, parser } = this._visitCreateIndex(createIndexNode); + + return [ + 'CREATE', + indexType, + 'INDEX', + ...ifNotExists, + indexName, + algorithm, + 'ON', + ...tableName, + columns, + parser + ].filter(this.notEmpty); + } + public visitCascade(cascadeNode: CascadeNode): string[] { + throw new Error('Sqlite do not support CASCADE in DROP TABLE'); + } + public visitRestrict(restrictNode: RestrictNode): string[] { + throw new Error('Sqlite do not support RESTRICT in DROP TABLE'); + } + public visitBinary(binaryNode: BinaryNode): string[] { + if (binaryNode.operator === '@@') { + binaryNode.operator = 'MATCH'; + const ret = super.visitBinary(binaryNode); + binaryNode.operator = '@@'; + return ret; + } + return super.visitBinary(binaryNode); + } + public visitOrIgnore(orIgnoreNode: OrIgnoreNode): string[] { + return ['OR IGNORE']; + } +} diff --git a/lib/functions.js b/lib/functions.js deleted file mode 100644 index fe9cdaaf..00000000 --- a/lib/functions.js +++ /dev/null @@ -1,75 +0,0 @@ -'use strict'; -var _ = require('lodash'); -var sliced = require('sliced'); -var FunctionCall = require('./node/functionCall'); - -// create a function that creates a function call of the specific name, using the specified sql instance -var getFunctionCallCreator = function(name) { - return function() { - // turn array-like arguments object into a true array - return new FunctionCall(name, sliced(arguments)); - }; -}; - -// creates a hash of functions for a sql instance -var getFunctions = function(functionNames) { - if (typeof functionNames === 'string') - return getFunctionCallCreator(functionNames); - - var functions = _.reduce(functionNames, function(reducer, name) { - reducer[name] = getFunctionCallCreator(name); - return reducer; - }, {}); - return functions; -}; - -// aggregate functions available to all databases -var aggregateFunctions = [ - 'AVG', - 'COUNT', - 'DISTINCT', - 'MAX', - 'MIN', - 'SUM' -]; - -// common scalar functions available to most databases -var scalarFunctions = [ - 'ABS', - 'COALESCE', - 'LEFT', - 'LENGTH', - 'LOWER', - 'LTRIM', - 'RANDOM', - 'RIGHT', - 'ROUND', - 'RTRIM', - 'SUBSTR', - 'TRIM', - 'UPPER' -]; - -var dateFunctions = [ - 'YEAR', - 'MONTH', - 'DAY', - 'HOUR', - 'CURRENT_TIMESTAMP' -]; - -// hstore function available to Postgres -var hstoreFunction = 'HSTORE'; - -//text search functions available to Postgres -var textsearchFunctions = ['TS_RANK','TS_RANK_CD', 'PLAINTO_TSQUERY', 'TO_TSQUERY', 'TO_TSVECTOR', 'SETWEIGHT']; - -var standardFunctionNames = aggregateFunctions.concat(scalarFunctions).concat(hstoreFunction).concat(textsearchFunctions).concat(dateFunctions); - -// creates a hash of standard functions for a sql instance -var getStandardFunctions = function() { - return getFunctions(standardFunctionNames); -}; - -module.exports.getFunctions = getFunctions; -module.exports.getStandardFunctions = getStandardFunctions; diff --git a/lib/functions.ts b/lib/functions.ts new file mode 100644 index 00000000..44ac2f4d --- /dev/null +++ b/lib/functions.ts @@ -0,0 +1,104 @@ +import reduce from 'lodash/reduce.js'; +import sliced from 'sliced'; +import { FunctionCallNode } from './node/functionCall.js'; + +// create a function that creates a function call of the specific name, using the specified sql instance +const getFunctionCallCreator = (name: string) => { + return (...args: any[]) => { + // turn array-like arguments object into a true array + return new FunctionCallNode(name, sliced(args)); + }; +}; + +// creates a hash of functions for a sql instance +const getFunctions = (functionNames: string | string[] | readonly string[]) => { + if (typeof functionNames === 'string') { return getFunctionCallCreator(functionNames); } + + const functions = reduce( + functionNames, + (reducer, name) => { + (reducer as any)[name] = getFunctionCallCreator(name); + return reducer; + }, + {} + ); + return functions; +}; + +// aggregate functions available to all databases +const aggregateFunctions = ['AVG', 'COUNT', 'DISTINCT', 'MAX', 'MIN', 'SUM'] as const; + +// common scalar functions available to most databases +const scalarFunctions = [ + 'ABS', + 'COALESCE', + 'LEFT', + 'LENGTH', + 'LOWER', + 'LTRIM', + 'RANDOM', + 'RIGHT', + 'ROUND', + 'RTRIM', + 'SUBSTR', + 'TRIM', + 'UPPER' +] as const; + +const dateFunctions = ['YEAR', 'MONTH', 'DAY', 'HOUR', 'CURRENT_TIMESTAMP'] as const; + +// hstore function available to Postgres +const hstoreFunctions = ['HSTORE'] as const; + +// text search functions available to Postgres +const textsearchFunctions = ['TS_RANK', 'TS_RANK_CD', 'PLAINTO_TSQUERY', 'TO_TSQUERY', 'TO_TSVECTOR', 'SETWEIGHT'] as const; + +// jsonb functions available to postgres +const jsonbFunctions = [ + 'JSONB_ARRAY_LENGTH', + 'JSONB_BUILD_ARRAY', + 'JSONB_BUILD_OBECT', + 'JSONB_EXTRACT_PATH', + 'JSONB_INSERT', + 'JSONB_OBJECT', + 'JSONB_PRETTY', + 'JSONB_SET', + 'JSONB_STRIP_NULLS', + 'JSONB_TYPEOF', + 'TO_JSONB', + 'JSONB_ARRAY_ELEMENTS', + 'JSONB_ARRAY_ELEMENTS_TEXT', + 'JSONB_EACH', + 'JSONB_EACH_TEXT', + 'JSONB_OBJECT_KEYS', + 'JSONB_AGG' +] as const; + +// time travel timestamp functions available to cockroachdb +const timeTravelFunctions = [ + 'STATEMENT_TIMESTAMP', + 'FOLLOWER_READ_TIMESTAMP', + 'WITH_MIN_TIMESTAMP', + 'WITH_MAX_STALENESS' +] as const; + +const standardFunctionNames = [ + ...aggregateFunctions, + ...scalarFunctions, + ...hstoreFunctions, + ...textsearchFunctions, + ...dateFunctions, + ...jsonbFunctions, + ...timeTravelFunctions +] as const; + +type StandardFunctions = { + [K in (typeof standardFunctionNames)[number]]: (...args: any[]) => FunctionCallNode; +} + +// creates a hash of standard functions for a sql instance +const getStandardFunctions = (): StandardFunctions => { + return getFunctions(standardFunctionNames) as StandardFunctions; +}; + +export { StandardFunctions, getFunctions, getStandardFunctions }; diff --git a/lib/index.js b/lib/index.js deleted file mode 100644 index f6cf39e6..00000000 --- a/lib/index.js +++ /dev/null @@ -1,91 +0,0 @@ -'use strict'; - -var _ = require('lodash'); -var Column = require("./column"); -var FunctionCall = require('./node/functionCall'); -var ArrayCall = require('./node/arrayCall'); -var functions = require('./functions'); -var getDialect = require('./dialect'); -var Query = require('./node/query'); -var sliced = require('sliced'); -var Table = require('./table'); -var Interval = require('./node/interval'); - -// default dialect is postgres -var DEFAULT_DIALECT = 'postgres'; - -var Sql = function(dialect, config) { - this.setDialect(dialect || DEFAULT_DIALECT, config); - - // attach the standard SQL functions to this instance - this.functions = functions.getStandardFunctions(); - this.function = functions.getFunctions; -}; - -// Define a table -Sql.prototype.define = function(def) { - def = _.defaults(def || {}, { - sql: this - }); - - return Table.define(def); -}; - -// Returns a function call creator -Sql.prototype.functionCallCreator = function(name) { - return function() { - return new FunctionCall(name, sliced(arguments)); - }; -}; - -// Returns a bracketed call creator literal -Sql.prototype.array = function() { - var arrayCall = new ArrayCall(sliced(arguments)); - arrayCall.sql = this; - return arrayCall; -}; - -// Returns a select statement -Sql.prototype.select = function() { - var query = new Query({sql: this}); - query.select.apply(query, arguments); - return query; -}; - -// Returns an interval clause -Sql.prototype.interval = function() { - var interval = new Interval(sliced(arguments)); - return interval; -}; - -// Set the dialect -Sql.prototype.setDialect = function(dialect, config) { - this.dialect = getDialect(dialect); - this.dialectName = dialect; - this.config = config; - - return this; -}; - -// Create a constant Column (for use in SELECT) -Sql.prototype.constant = function(value) { - var config={ - name:"constant", - property:"constant", - isConstant:true, - constantValue:value, - }; - var cn = new Column(config); - return cn; -}; - - -// back compat shim for the Sql class constructor -var create = function(dialect, config) { - return new Sql(dialect, {}); -}; - -module.exports = new Sql(DEFAULT_DIALECT, {}); -module.exports.create = create; -module.exports.Sql = Sql; -module.exports.Table = Table; diff --git a/lib/index.ts b/lib/index.ts new file mode 100644 index 00000000..1621ba88 --- /dev/null +++ b/lib/index.ts @@ -0,0 +1,91 @@ +export * from './node/node.js'; +import './node/_internal.js'; + +export * from './node/select.js'; +export * from './node/insert.js'; +export * from './node/replace.js'; +export * from './node/update.js'; +export * from './node/delete.js'; +export * from './node/create.js'; +export * from './node/drop.js'; +export * from './node/truncate.js'; +export * from './node/distinct.js'; +export * from './node/distinctOn.js'; +export * from './node/alias.js'; +export * from './node/alter.js'; +export * from './node/cast.js'; +export * from './node/from.js'; +export * from './node/where.js'; +export * from './node/orderBy.js'; +export * from './node/orderByValue.js'; +export * from './node/groupBy.js'; +export * from './node/having.js'; +export * from './node/prefixUnary.js'; +export * from './node/postfixUnary.js'; +export * from './node/binary.js'; +export * from './node/ternary.js'; +export * from './node/in.js'; +export * from './node/notIn.js'; +export * from './node/case.js'; +export * from './node/at.js'; +export * from './node/slice.js'; +export * from './node/table.js'; +export * from './node/column.js'; +export * from './node/foreignKey.js'; +export * from './node/functionCall.js'; +export * from './node/arrayCall.js'; +export * from './node/rowCall.js'; +export * from './node/parameter.js'; +export * from './node/default.js'; +export * from './node/addColumn.js'; +export * from './node/dropColumn.js'; +export * from './node/renameColumn.js'; +export * from './node/rename.js'; +export * from './node/ifExists.js'; +export * from './node/ifNotExists.js'; +export * from './node/orIgnore.js'; +export * from './node/cascade.js'; +export * from './node/restrict.js'; +export * from './node/forUpdate.js'; +export * from './node/forShare.js'; +export * from './node/join.js'; +export * from './node/literal.js'; +export * from './node/returning.js'; +export * from './node/onDuplicate.js'; +export * from './node/onConflict.js'; +export * from './node/indexes.js'; +export * from './node/createIndex.js'; +export * from './node/dropIndex.js'; +export * from './node/createView.js'; +export * from './node/interval.js'; +export * from './node/modifier.js'; + +export * from './node/query.js'; + +export * from './dialect/mapper.js'; +export * from './sql.js'; +export * from './column.js'; +export * from './table.js'; + +import { Dialect } from './dialect/dialect.js'; +import { Mssql } from './dialect/mssql.js'; +import { Mysql } from './dialect/mysql.js'; +import { Oracle } from './dialect/oracle.js'; +import { Postgres } from './dialect/postgres.js'; +import { Sqlite } from './dialect/sqlite.js'; +import { registerDialect } from './dialect/mapper.js'; + +registerDialect('mssql', Mssql); +registerDialect('mysql', Mysql); +registerDialect('oracle', Oracle); +registerDialect('postgres', Postgres); +registerDialect('sqlite', Sqlite); + +export { + Dialect, + Mssql, + Mysql, + Oracle, + Postgres, + Sqlite +} diff --git a/lib/joiner.js b/lib/joiner.js deleted file mode 100644 index 5ce82cf9..00000000 --- a/lib/joiner.js +++ /dev/null @@ -1,40 +0,0 @@ -'use strict'; - -var getPrimaryKeyColumn = function(table) { - for (var i = 0; i < table.columns.length; i++) { - var col = table.columns[i]; - if (col.primaryKey) { - return col; - } - } -}; - -var findReference = function(left, right) { - // find reference - for (var i = 0; i < right.columns.length; i++) { - var col = right.columns[i]; - if (col.references) { - var leftName = left.getName(); - if (col.references === leftName || col.references.table === leftName) { - var leftCol = left[col.references.column] || getPrimaryKeyColumn(left); - return { - left: leftCol, - right: col - }; - } - } - } -}; - -module.exports = { - // auto-join two tables based on column properties - // requires one column to have { references: {table: 'foreignTableName', column: 'foreignColumnName'}} - // or to have { references: 'foreignTableName'} -- in which case the foreign table's primary key is assumed - leftJoin: function(left, right) { - var ref = findReference(left, right); - if (!ref) { - ref = findReference(right, left); - } - return left.join(right).on(ref.left.equals(ref.right)); - } -}; diff --git a/lib/joiner.ts b/lib/joiner.ts new file mode 100644 index 00000000..5570c3d7 --- /dev/null +++ b/lib/joiner.ts @@ -0,0 +1,48 @@ +import { Table } from './table.js'; + +const getPrimaryKeyColumn = (table: Table) => { + for (const col of table.columns) { + if (col.primaryKey) { + return col; + } + } + return; +}; + +const findReference = (left: Table, right: Table) => { + // find reference + for (const col of right.columns) { + const references = col.references; + if (references) { + const leftName = left.getName(); + if (typeof references === 'string') { + if (references === leftName) { + const leftCol = getPrimaryKeyColumn(left); + return { + left: leftCol, + right: col + }; + } + } else if (references.table === leftName) { + const leftCol = references.column ? (left as any)[references.column] : getPrimaryKeyColumn(left); + return { + left: leftCol, + right: col + }; + } + } + } + return; +}; +// auto-join two tables based on column properties +// requires one column to have { references: {table: 'foreignTableName', column: 'foreignColumnName'}} +// or to have { references: 'foreignTableName'} -- in which case the foreign table's primary key is assumed +const leftJoin = (left: Table, right: Table) => { + let ref = findReference(left, right); + if (!ref) { + ref = findReference(right, left); + } + return left.join(right).on(ref!.left.equals(ref!.right)); +}; + +export { leftJoin }; diff --git a/lib/node/_internal.ts b/lib/node/_internal.ts new file mode 100644 index 00000000..6b30ef4c --- /dev/null +++ b/lib/node/_internal.ts @@ -0,0 +1,12 @@ +export * from './valueExpression.js'; +export * from './at.js'; +export * from './binary.js'; +export * from './case.js'; +export * from './cast.js'; +export * from './in.js'; +export * from './notIn.js'; +export * from './orderByValue.js'; +export * from './postfixUnary.js'; +export * from './prefixUnary.js'; +export * from './slice.js'; +export * from './ternary.js'; diff --git a/lib/node/addColumn.js b/lib/node/addColumn.js deleted file mode 100644 index 3d7d4066..00000000 --- a/lib/node/addColumn.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'ADD COLUMN' -}); diff --git a/lib/node/addColumn.ts b/lib/node/addColumn.ts new file mode 100644 index 00000000..46f945fe --- /dev/null +++ b/lib/node/addColumn.ts @@ -0,0 +1,7 @@ +import { Node } from './node.js'; + +export class AddColumnNode extends Node { + constructor() { + super('ADD COLUMN'); + } +} diff --git a/lib/node/alias.js b/lib/node/alias.js deleted file mode 100644 index 9f9855f5..00000000 --- a/lib/node/alias.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict'; - -var _ = require('lodash'); -var Node = require('./index'); - -var AliasNode = Node.define({ - type: 'ALIAS', - constructor: function(value, alias) { - Node.call(this); - - this.value = value; - this.alias = alias; - } -}); - -var AliasMixin = { - as: function(alias) { - // create an alias node - var aliasNode = new AliasNode(this, alias); - - // defaults the properties of the aliased node - _.defaults(aliasNode, this); - - return aliasNode; - } -}; - -module.exports = AliasNode; -module.exports.AliasMixin = AliasMixin; diff --git a/lib/node/alias.ts b/lib/node/alias.ts new file mode 100644 index 00000000..dd89e684 --- /dev/null +++ b/lib/node/alias.ts @@ -0,0 +1,25 @@ +import defaults from 'lodash/defaults.js'; +import { Node } from './node.js'; + +export class AliasNode extends Node { + public value: Node; + public alias: string; + constructor(value: Node, alias: string) { + super('ALIAS'); + + this.value = value; + this.alias = alias; + } +} + +export const AliasMixin = { + as(this: Node, alias: string) { + // create an alias node + const aliasNode = new AliasNode(this, alias); + + // defaults the properties of the aliased node + defaults(aliasNode, this); + + return aliasNode; + } +}; diff --git a/lib/node/alter.js b/lib/node/alter.js deleted file mode 100644 index 4aae4d83..00000000 --- a/lib/node/alter.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'ALTER' -}); diff --git a/lib/node/alter.ts b/lib/node/alter.ts new file mode 100644 index 00000000..4c113b67 --- /dev/null +++ b/lib/node/alter.ts @@ -0,0 +1,7 @@ +import { Node } from './node.js'; + +export class AlterNode extends Node { + constructor() { + super('ALTER'); + } +} diff --git a/lib/node/arrayCall.js b/lib/node/arrayCall.js deleted file mode 100644 index 7533190d..00000000 --- a/lib/node/arrayCall.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; - -var _ = require('lodash'); -var Node = require('./index'); -var ParameterNode = require('./parameter'); -var valueExpressionMixin = require('./valueExpression'); - -var ArrayCallNode = Node.define({ - type: 'ARRAY CALL', - constructor: function(args) { - Node.call(this); - args = _.flatten(args); - this.addAll(args.map(ParameterNode.getNodeOrParameterNode)); - } -}); - -// mix in value expression -_.extend(ArrayCallNode.prototype, valueExpressionMixin()); - -// allow aliasing -var AliasNode = require('./alias'); -_.extend(ArrayCallNode.prototype, AliasNode.AliasMixin); - -module.exports = ArrayCallNode; diff --git a/lib/node/arrayCall.ts b/lib/node/arrayCall.ts new file mode 100644 index 00000000..5de7aa05 --- /dev/null +++ b/lib/node/arrayCall.ts @@ -0,0 +1,14 @@ +import flatten from 'lodash/flatten.js'; +import { AliasMixin } from './alias.js'; +import { ParameterNode } from './parameter.js'; +import { ValueExpressionNode } from './_internal.js'; + +export class ArrayCallNode extends ValueExpressionNode { + constructor(args: any[]) { + super('ARRAY CALL'); + args = flatten(args); + this.addAll(args.map(ParameterNode.getNodeOrParameterNode)); + } + + public as = AliasMixin.as; +} diff --git a/lib/node/asOf.ts b/lib/node/asOf.ts new file mode 100644 index 00000000..685b4648 --- /dev/null +++ b/lib/node/asOf.ts @@ -0,0 +1,7 @@ +import { Node } from './node.js'; + +export class AsOfNode extends Node { + constructor() { + super('AS OF'); + } +} diff --git a/lib/node/at.js b/lib/node/at.js deleted file mode 100644 index 5e8ca47b..00000000 --- a/lib/node/at.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict'; - -var _ = require('lodash'); -var Node = require('./index'); -var valueExpressionMixin = require('./valueExpression'); - -var valueExpressionMixed = false; -var AtNode = Node.define({ - type: 'AT', - constructor: function(value, index) { - Node.call(this); - this.value = value; - this.index = index; - // Delay mixin to runtime, when all nodes have been defined, and - // mixin only once. ValueExpressionMixin has circular dependencies. - if (!valueExpressionMixed) { - valueExpressionMixed = true; - _.extend(AtNode.prototype, valueExpressionMixin()); - } - } -}); - -// allow aliasing -var AliasNode = require('./alias'); -_.extend(AtNode.prototype, AliasNode.AliasMixin); - -module.exports = AtNode; diff --git a/lib/node/at.ts b/lib/node/at.ts new file mode 100644 index 00000000..af9274bd --- /dev/null +++ b/lib/node/at.ts @@ -0,0 +1,17 @@ +import { AliasMixin } from './alias.js'; +import { Node } from './node.js'; +import { classMap, ValueExpressionNode } from './_internal.js'; + +export class AtNode extends ValueExpressionNode { + public value: Node; + public index: Node; + constructor(value: Node, index: Node) { + super('AT'); + this.value = value; + this.index = index; + } + + public as = AliasMixin.as; +} + +classMap.set('AT', AtNode); diff --git a/lib/node/binary.js b/lib/node/binary.js deleted file mode 100644 index da8eb8bd..00000000 --- a/lib/node/binary.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict'; - -var _ = require('lodash'); -var Node = require('./index'); -var valueExpressionMixin = require('./valueExpression'); - -var valueExpressionMixed = false; -var BinaryNode = Node.define(_.extend({ - type: 'BINARY', - constructor: function(config) { - Node.call(this); - this.left = config.left; - this.operator = config.operator; - this.right = config.right; - - // Delay mixin to runtime, when all nodes have been defined, and - // mixin only once. ValueExpressionMixin has circular dependencies. - if (!valueExpressionMixed) { - valueExpressionMixed = true; - _.extend(BinaryNode.prototype, valueExpressionMixin()); - } - }, -})); - -// allow aliasing -var AliasNode = require('./alias'); -_.extend(BinaryNode.prototype, AliasNode.AliasMixin); - -module.exports = BinaryNode; diff --git a/lib/node/binary.ts b/lib/node/binary.ts new file mode 100644 index 00000000..04ace610 --- /dev/null +++ b/lib/node/binary.ts @@ -0,0 +1,19 @@ +import { AliasMixin } from './alias.js'; +import { Node } from './node.js'; +import { classMap, ValueExpressionNode } from './_internal.js'; + +export class BinaryNode extends ValueExpressionNode { + public left: Node; + public operator: string; + public right: Node | Node[]; + constructor(config: { left: Node; operator: string; right: Node | Node[] }) { + super('BINARY'); + this.left = config.left; + this.operator = config.operator; + this.right = config.right; + } + + public as = AliasMixin.as; +} + +classMap.set('BINARY', BinaryNode); diff --git a/lib/node/cascade.js b/lib/node/cascade.js deleted file mode 100644 index 4b6646fd..00000000 --- a/lib/node/cascade.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'CASCADE' -}); diff --git a/lib/node/cascade.ts b/lib/node/cascade.ts new file mode 100644 index 00000000..d8c90dcf --- /dev/null +++ b/lib/node/cascade.ts @@ -0,0 +1,7 @@ +import { Node } from './node.js'; + +export class CascadeNode extends Node { + constructor() { + super('CASCADE'); + } +} diff --git a/lib/node/case.js b/lib/node/case.js deleted file mode 100644 index ac3bf214..00000000 --- a/lib/node/case.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict'; - -var _ = require('lodash'); -var Node = require('./index'); -var valueExpressionMixin = require('./valueExpression'); - -var valueExpressionMixed = false; -var CaseNode = Node.define(_.extend({ - type: 'CASE', - constructor: function(config) { - Node.call(this); - this.whenList = config.whenList; - this.thenList = config.thenList; - this.else = config.else; - - // Delay mixin to runtime, when all nodes have been defined, and - // mixin only once. ValueExpressionMixin has circular dependencies. - if (!valueExpressionMixed) { - valueExpressionMixed = true; - _.extend(CaseNode.prototype, valueExpressionMixin()); - } - }, -})); - -// allow aliasing -var AliasNode = require('./alias'); -_.extend(CaseNode.prototype, AliasNode.AliasMixin); - -module.exports = CaseNode; diff --git a/lib/node/case.ts b/lib/node/case.ts new file mode 100644 index 00000000..652a3122 --- /dev/null +++ b/lib/node/case.ts @@ -0,0 +1,19 @@ +import { AliasMixin } from './alias.js'; +import { Node } from './node.js'; +import { classMap, ValueExpressionNode } from './_internal.js'; + +export class CaseNode extends ValueExpressionNode { + public whenList: Node[]; + public thenList: Node[]; + public else?: Node; + constructor(config: { whenList: Node[]; thenList: Node[]; else?: Node }) { + super('CASE'); + this.whenList = config.whenList; + this.thenList = config.thenList; + this.else = config.else; + } + + public as = AliasMixin.as; +} + +classMap.set('CASE', CaseNode); diff --git a/lib/node/cast.js b/lib/node/cast.js deleted file mode 100644 index be915b1e..00000000 --- a/lib/node/cast.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict'; - -var _ = require('lodash'); -var Node = require('./index'); -var valueExpressionMixin = require('./valueExpression'); - -var valueExpressionMixed = false; -var CastNode = Node.define({ - type: 'CAST', - constructor: function(value, dataType) { - Node.call(this); - this.value = value; - this.dataType = dataType; - // Delay mixin to runtime, when all nodes have been defined, and - // mixin only once. ValueExpressionMixin has circular dependencies. - if (!valueExpressionMixed) { - valueExpressionMixed = true; - _.extend(CastNode.prototype, valueExpressionMixin()); - } - } -}); - -// allow aliasing -var AliasNode = require('./alias'); -_.extend(CastNode.prototype, AliasNode.AliasMixin); - -module.exports = CastNode; diff --git a/lib/node/cast.ts b/lib/node/cast.ts new file mode 100644 index 00000000..470e6038 --- /dev/null +++ b/lib/node/cast.ts @@ -0,0 +1,17 @@ +import { AliasMixin } from './alias.js'; +import { Node } from './node.js'; +import { classMap, ValueExpressionNode } from './_internal.js'; + +export class CastNode extends ValueExpressionNode { + public value: Node; + public dataType: string; + constructor(value: Node, dataType: string) { + super('CAST'); + this.value = value; + this.dataType = dataType; + } + + public as = AliasMixin.as; +} + +classMap.set('CAST', CastNode); diff --git a/lib/node/column.js b/lib/node/column.js deleted file mode 100644 index 6b145d74..00000000 --- a/lib/node/column.js +++ /dev/null @@ -1,36 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'COLUMN', - constructor: function(config) { - Node.call(this); - this.name = config.name; - this.property = config.property || config.name; - this.alias = config.alias; - this.star = config.star; - this.isConstant = config.isConstant; - this.constantValue = config.constantValue; - this.asArray = config.asArray; - this.aggregator = config.aggregator; - this.table = config.table; - this.value = config.getValue(); - this.dataType = config.dataType; - this.distinct = config.distinct; - this.primaryKey = config.primaryKey; - this.notNull = config.notNull; - this.defaultValue = config.defaultValue; - this.references = config.references; - // If subfieldContainer is present, this is a subfield and subfieldContainer - // is the parent Column - this.subfieldContainer = config.subfieldContainer; - this.subfields = config.subfields; - this.autoGenerated = !!config.autoGenerated; - this.unique = !!config.unique; - }, - as: function(alias) { - this.alias = alias; - return this; - } -}); diff --git a/lib/node/column.ts b/lib/node/column.ts new file mode 100644 index 00000000..b2a176dd --- /dev/null +++ b/lib/node/column.ts @@ -0,0 +1,67 @@ +import { Column } from '../column.js'; +import { Table } from '../table.js'; +import { Node } from './node.js'; + +export class ColumnNode extends Node { + public name: string; + public property: string; + public alias?: string; + public star?: boolean; + public isConstant?: boolean; + public constantValue?: any; + public asArray?: boolean; + public aggregator?: string; + public table?: Table; + public value: any; + public dataType?: string; + public isDistinct?: boolean; + public primaryKey?: boolean; + public notNull?: boolean; + public defaultValue?: any; + public references?: + | string + | { + table?: string; + column?: string; + constraint?: string; + onDelete?: 'restrict' | 'cascade' | 'no action' | 'set null' | 'set default'; + onUpdate?: 'restrict' | 'cascade' | 'no action' | 'set null' | 'set default'; + }; + public subfieldContainer?: Column; + public subfields: { [key: string]: Column }; + public autoGenerated: boolean; + public unique: boolean; + constructor(config: Column) { + super('COLUMN'); + this.name = config.name; + this.property = config.property || config.name; + this.alias = config.alias; + this.star = config.star; + this.isConstant = config.isConstant; + this.constantValue = config.constantValue; + this.asArray = config.asArray; + this.aggregator = config.aggregator; + this.table = config.table; + this.value = config.getValue(); + this.dataType = config.dataType; + this.isDistinct = config.isDistinct; + this.primaryKey = config.primaryKey; + this.notNull = config.notNull; + this.defaultValue = config.defaultValue; + this.references = config.references; + // If subfieldContainer is present, this is a subfield and subfieldContainer + // is the parent Column + this.subfieldContainer = config.subfieldContainer; + this.subfields = config.subfields; + this.autoGenerated = !!config.autoGenerated; + this.unique = !!config.unique; + } + public distinct(): this { + this.isDistinct = true; + return this; + } + public as(alias: string): this { + this.alias = alias; + return this; + } +} diff --git a/lib/node/create.js b/lib/node/create.js deleted file mode 100644 index 67cd9b3d..00000000 --- a/lib/node/create.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'CREATE', - - constructor: function(isTemporary) { - Node.call(this); - - this.options = { isTemporary: isTemporary}; - }, - -}); diff --git a/lib/node/create.ts b/lib/node/create.ts new file mode 100644 index 00000000..476708ba --- /dev/null +++ b/lib/node/create.ts @@ -0,0 +1,11 @@ +import { Node } from './node.js'; + +export class CreateNode extends Node { + public options: { isTemporary: boolean }; + + constructor(isTemporary: boolean) { + super('CREATE'); + + this.options = { isTemporary }; + } +} diff --git a/lib/node/createIndex.js b/lib/node/createIndex.js deleted file mode 100644 index 8f8f0d04..00000000 --- a/lib/node/createIndex.js +++ /dev/null @@ -1,63 +0,0 @@ -'use strict'; - -var Node = require('./'); -var sliced = require('sliced'); - -module.exports = Node.define({ - type: 'CREATE INDEX', - - constructor: function(table, indexName) { - Node.call(this); - - this.table = table; - this.options = { indexName: indexName, columns: [] }; - }, - - unique: function() { - this.options.type = 'unique'; - return this; - }, - - spatial: function() { - this.options.type = 'spatial'; - return this; - }, - - fulltext: function() { - this.options.type = 'fulltext'; - return this; - }, - - using: function(algorithm) { - this.options.algorithm = algorithm; - return this; - }, - - on: function() { - var args = sliced(arguments); - this.options.columns = this.options.columns.concat(args); - return this; - }, - - withParser: function(parser) { - this.options.parser = parser; - return this; - }, - - indexName: function() { - var result = this.options.indexName; - - if (!result) { - var columns = this.options.columns.map(function(col) { - var column = col.name ? col.name : col.value.name; - return column; - }).sort(); - - result = [this.table._name]; - result = result.concat(columns); - result = result.join('_'); - } - - return result; - } -}); diff --git a/lib/node/createIndex.ts b/lib/node/createIndex.ts new file mode 100644 index 00000000..0f16f539 --- /dev/null +++ b/lib/node/createIndex.ts @@ -0,0 +1,71 @@ +import sliced from 'sliced'; +import { Column } from '../column.js'; +import { IndexCreationQuery, Table } from '../table.js'; +import { Node } from './node.js'; + +export class CreateIndexNode extends Node implements IndexCreationQuery { + public table: Table; + public options: { + indexName: string; + columns: Column[]; + type?: string; + algorithm?: string; + parser?: string; + ifNotExists?: boolean; + }; + + constructor(table: Table, indexName: string) { + super('CREATE INDEX'); + + this.table = table; + this.options = { indexName, columns: [] }; + } + + public unique() { + this.options.type = 'unique'; + return this; + } + + public spatial() { + this.options.type = 'spatial'; + return this; + } + + public fulltext() { + this.options.type = 'fulltext'; + return this; + } + + public using(algorithm: string) { + this.options.algorithm = algorithm; + return this; + } + + public on(...columns: Column[]) { + const args = sliced(columns); + this.options.columns = this.options.columns.concat(args); + return this; + } + + public withParser(parser: string) { + this.options.parser = parser; + return this; + } + + public indexName() { + let result = this.options.indexName; + + if (!result) { + const columns = this.options.columns.map((col) => (col.name ? col.name : col.value.name)).sort(); + + result = [this.table.getName(), ...columns].join('_'); + } + + return result; + } + + public ifNotExists() { + this.options.ifNotExists = true; + return this; + } +} diff --git a/lib/node/createView.js b/lib/node/createView.js deleted file mode 100644 index 7d456d90..00000000 --- a/lib/node/createView.js +++ /dev/null @@ -1,13 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'CREATE VIEW', - - constructor: function(viewName) { - Node.call(this); - - this.options = { viewName: viewName}; - } -}); diff --git a/lib/node/createView.ts b/lib/node/createView.ts new file mode 100644 index 00000000..0d946fe5 --- /dev/null +++ b/lib/node/createView.ts @@ -0,0 +1,11 @@ +import { Node } from './node.js'; + +export class CreateViewNode extends Node { + public options: { viewName: string }; + + constructor(viewName: string) { + super('CREATE VIEW'); + + this.options = { viewName }; + } +} diff --git a/lib/node/default.js b/lib/node/default.js deleted file mode 100644 index b5adc894..00000000 --- a/lib/node/default.js +++ /dev/null @@ -1,8 +0,0 @@ -'use strict'; - -module.exports = require('./index').define({ - type: 'DEFAULT', - value: function() { - return; - } -}); diff --git a/lib/node/default.ts b/lib/node/default.ts new file mode 100644 index 00000000..b9997196 --- /dev/null +++ b/lib/node/default.ts @@ -0,0 +1,7 @@ +import { Node } from './node.js'; + +export class DefaultNode extends Node { + constructor() { + super('DEFAULT'); + } +} diff --git a/lib/node/delete.js b/lib/node/delete.js deleted file mode 100644 index 0d02ebab..00000000 --- a/lib/node/delete.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'DELETE' -}); diff --git a/lib/node/delete.ts b/lib/node/delete.ts new file mode 100644 index 00000000..efaee58b --- /dev/null +++ b/lib/node/delete.ts @@ -0,0 +1,7 @@ +import { Node } from './node.js'; + +export class DeleteNode extends Node { + constructor() { + super('DELETE'); + } +} diff --git a/lib/node/distinct.js b/lib/node/distinct.js deleted file mode 100644 index 8c681551..00000000 --- a/lib/node/distinct.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'DISTINCT', -}); diff --git a/lib/node/distinct.ts b/lib/node/distinct.ts new file mode 100644 index 00000000..a1600599 --- /dev/null +++ b/lib/node/distinct.ts @@ -0,0 +1,7 @@ +import { Node } from './node.js'; + +export class DistinctNode extends Node { + constructor() { + super('DISTINCT'); + } +} diff --git a/lib/node/distinctOn.js b/lib/node/distinctOn.js deleted file mode 100644 index 72c430e8..00000000 --- a/lib/node/distinctOn.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'DISTINCT ON', -}); diff --git a/lib/node/distinctOn.ts b/lib/node/distinctOn.ts new file mode 100644 index 00000000..2c0236c1 --- /dev/null +++ b/lib/node/distinctOn.ts @@ -0,0 +1,7 @@ +import { Node } from './node.js'; + +export class DistinctOnNode extends Node { + constructor() { + super('DISTINCT ON'); + } +} diff --git a/lib/node/drop.js b/lib/node/drop.js deleted file mode 100644 index b0428347..00000000 --- a/lib/node/drop.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'DROP', - - constructor: function(table) { - Node.call(this); - this.add(table); - } -}); diff --git a/lib/node/drop.ts b/lib/node/drop.ts new file mode 100644 index 00000000..3772b2c4 --- /dev/null +++ b/lib/node/drop.ts @@ -0,0 +1,9 @@ +import { Table } from '../table.js'; +import { Node } from './node.js'; + +export class DropNode extends Node { + constructor(table: Table) { + super('DROP'); + this.add(table); + } +} diff --git a/lib/node/dropColumn.js b/lib/node/dropColumn.js deleted file mode 100644 index 01fe36c5..00000000 --- a/lib/node/dropColumn.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'DROP COLUMN' -}); diff --git a/lib/node/dropColumn.ts b/lib/node/dropColumn.ts new file mode 100644 index 00000000..ea49c548 --- /dev/null +++ b/lib/node/dropColumn.ts @@ -0,0 +1,7 @@ +import { Node } from './node.js'; + +export class DropColumnNode extends Node { + constructor() { + super('DROP COLUMN'); + } +} diff --git a/lib/node/dropIndex.js b/lib/node/dropIndex.js deleted file mode 100644 index 9b5e020d..00000000 --- a/lib/node/dropIndex.js +++ /dev/null @@ -1,39 +0,0 @@ -'use strict'; - -var Node = require('./'); - -module.exports = Node.define({ - type: 'DROP INDEX', - - constructor: function(table, indexName) { - if (!indexName) { - throw new Error('No index defined!'); - } else if (Array.isArray(indexName) && (typeof indexName[0] === 'string')) { - indexName = indexName[0]; - } else if (Array.isArray(indexName)) { - var columns = indexName.map(function(col) { return col.name; }).sort(); - indexName = [table._name].concat(columns).join('_'); - } - - Node.call(this); - - this.table = table; - this.options = { indexName: indexName }; - }, - - indexName: function() { - var result = this.options.indexName; - - if (!result) { - var columns = this.options.columns.map(function(col) { - return col.name; - }).sort(); - - result = [this.table._name]; - result = result.concat(columns); - result = result.join('_'); - } - - return result; - } -}); diff --git a/lib/node/dropIndex.ts b/lib/node/dropIndex.ts new file mode 100644 index 00000000..c800507e --- /dev/null +++ b/lib/node/dropIndex.ts @@ -0,0 +1,29 @@ +import { Column } from '../column.js'; +import { Table } from '../table.js'; +import { Node } from './node.js'; + +export class DropIndexNode extends Node { + public table: Table; + public options: { indexName: string, ifExists?: boolean }; + + constructor(table: Table, indexName: string | string[] | Column[]) { + super('DROP INDEX'); + + if (!indexName) { + throw new Error('No index defined!'); + } else if (Array.isArray(indexName) && typeof indexName[0] === 'string') { + indexName = indexName[0] as string; + } else if (Array.isArray(indexName)) { + const columns = (indexName as Column[]).map((col) => col.name).sort(); + indexName = [table.getName()].concat(columns).join('_'); + } + + this.table = table; + this.options = { indexName }; + } + + public ifExists(): DropIndexNode { + this.options.ifExists = true; + return this + } +} diff --git a/lib/node/forShare.js b/lib/node/forShare.js deleted file mode 100644 index 68a83678..00000000 --- a/lib/node/forShare.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'FOR SHARE' -}); diff --git a/lib/node/forShare.ts b/lib/node/forShare.ts new file mode 100644 index 00000000..a70b254e --- /dev/null +++ b/lib/node/forShare.ts @@ -0,0 +1,7 @@ +import { Node } from './node.js'; + +export class ForShareNode extends Node { + constructor() { + super('FOR SHARE'); + } +} diff --git a/lib/node/forUpdate.js b/lib/node/forUpdate.js deleted file mode 100644 index da4a2518..00000000 --- a/lib/node/forUpdate.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'FOR UPDATE' -}); diff --git a/lib/node/forUpdate.ts b/lib/node/forUpdate.ts new file mode 100644 index 00000000..b48d15b9 --- /dev/null +++ b/lib/node/forUpdate.ts @@ -0,0 +1,7 @@ +import { Node } from './node.js'; + +export class ForUpdateNode extends Node { + constructor() { + super('FOR UPDATE'); + } +} diff --git a/lib/node/foreignKey.js b/lib/node/foreignKey.js deleted file mode 100644 index a0ad99c1..00000000 --- a/lib/node/foreignKey.js +++ /dev/null @@ -1,19 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'FOREIGN KEY', - constructor: function(config) { - Node.call(this); - this.name = config.name; - this.columns = config.columns; - this.schema = config.schema; - this.table = config.table; - this.refColumns = config.refColumns; - this.onUpdate = config.onUpdate; - this.onDelete = config.onDelete; - this.constraint = config.constraint; - } -}); - diff --git a/lib/node/foreignKey.ts b/lib/node/foreignKey.ts new file mode 100644 index 00000000..b380563e --- /dev/null +++ b/lib/node/foreignKey.ts @@ -0,0 +1,32 @@ +import { Node } from './node.js'; + +export class ForeignKeyNode extends Node { + public name?: string; + public columns: string[]; + public schema?: string; + public table: string; + public refColumns?: string[]; + public onUpdate?: string; + public onDelete?: string; + public constraint?: string; + constructor(config: { + table: string; + columns: string[]; + refColumns?: string[]; + onDelete?: string; + onUpdate?: string; + name?: string; + schema?: string; + constraint?: string; + }) { + super('FOREIGN KEY'); + this.name = config.name; + this.columns = config.columns; + this.schema = config.schema; + this.table = config.table; + this.refColumns = config.refColumns; + this.onUpdate = config.onUpdate; + this.onDelete = config.onDelete; + this.constraint = config.constraint; + } +} diff --git a/lib/node/from.js b/lib/node/from.js deleted file mode 100644 index 12b54565..00000000 --- a/lib/node/from.js +++ /dev/null @@ -1,9 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -var From = Node.define({ - type: 'FROM' -}); - -module.exports = From; diff --git a/lib/node/from.ts b/lib/node/from.ts new file mode 100644 index 00000000..222d7d75 --- /dev/null +++ b/lib/node/from.ts @@ -0,0 +1,8 @@ +import { Node } from './node.js'; + +export class FromNode extends Node { + public skipFromStatement: boolean = false; + constructor() { + super('FROM'); + } +} diff --git a/lib/node/functionCall.js b/lib/node/functionCall.js deleted file mode 100644 index 608a3c1e..00000000 --- a/lib/node/functionCall.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; - -var _ = require('lodash'); -var Node = require('./index'); -var ParameterNode = require('./parameter'); -var valueExpressionMixin = require('./valueExpression'); - -var FunctionCallNode = Node.define({ - type: 'FUNCTION CALL', - constructor: function(name, args) { - Node.call(this); - this.name = name; - this.addAll(args.map(ParameterNode.getNodeOrParameterNode)); - } -}); - -// mix in value expression -_.extend(FunctionCallNode.prototype, valueExpressionMixin()); - -// allow aliasing -var AliasNode = require('./alias'); -_.extend(FunctionCallNode.prototype, AliasNode.AliasMixin); - -module.exports = FunctionCallNode; diff --git a/lib/node/functionCall.ts b/lib/node/functionCall.ts new file mode 100644 index 00000000..018ca126 --- /dev/null +++ b/lib/node/functionCall.ts @@ -0,0 +1,14 @@ +import { AliasMixin } from './alias.js'; +import { ParameterNode } from './parameter.js'; +import { ValueExpressionNode } from './_internal.js'; + +export class FunctionCallNode extends ValueExpressionNode { + public name: string; + constructor(name: string, args: any[]) { + super('FUNCTION CALL'); + this.name = name; + this.addAll(args.map(ParameterNode.getNodeOrParameterNode)); + } + + public as = AliasMixin.as; +} diff --git a/lib/node/groupBy.js b/lib/node/groupBy.js deleted file mode 100644 index 53f63e94..00000000 --- a/lib/node/groupBy.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'GROUP BY' -}); diff --git a/lib/node/groupBy.ts b/lib/node/groupBy.ts new file mode 100644 index 00000000..1800e953 --- /dev/null +++ b/lib/node/groupBy.ts @@ -0,0 +1,7 @@ +import { Node } from './node.js'; + +export class GroupByNode extends Node { + constructor() { + super('GROUP BY'); + } +} diff --git a/lib/node/having.js b/lib/node/having.js deleted file mode 100644 index 6f1523ac..00000000 --- a/lib/node/having.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'HAVING' -}); diff --git a/lib/node/having.ts b/lib/node/having.ts new file mode 100644 index 00000000..d3663edd --- /dev/null +++ b/lib/node/having.ts @@ -0,0 +1,7 @@ +import { Node } from './node.js'; + +export class HavingNode extends Node { + constructor() { + super('HAVING'); + } +} diff --git a/lib/node/ifExists.js b/lib/node/ifExists.js deleted file mode 100644 index c26df660..00000000 --- a/lib/node/ifExists.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'IF EXISTS' -}); diff --git a/lib/node/ifExists.ts b/lib/node/ifExists.ts new file mode 100644 index 00000000..30266f80 --- /dev/null +++ b/lib/node/ifExists.ts @@ -0,0 +1,7 @@ +import { Node } from './node.js'; + +export class IfExistsNode extends Node { + constructor() { + super('IF EXISTS'); + } +} diff --git a/lib/node/ifNotExists.js b/lib/node/ifNotExists.js deleted file mode 100644 index d731ccb2..00000000 --- a/lib/node/ifNotExists.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'IF NOT EXISTS' -}); diff --git a/lib/node/ifNotExists.ts b/lib/node/ifNotExists.ts new file mode 100644 index 00000000..b576048b --- /dev/null +++ b/lib/node/ifNotExists.ts @@ -0,0 +1,7 @@ +import { Node } from './node.js'; + +export class IfNotExistsNode extends Node { + constructor() { + super('IF NOT EXISTS'); + } +} diff --git a/lib/node/in.js b/lib/node/in.js deleted file mode 100644 index 233b7c28..00000000 --- a/lib/node/in.js +++ /dev/null @@ -1,28 +0,0 @@ -'use strict'; - -var _ = require('lodash'); -var Node = require('./index'); -var valueExpressionMixin = require('./valueExpression'); - -var valueExpressionMixed = false; -var InNode = Node.define(_.extend({ - type: 'IN', - constructor: function(config) { - Node.call(this); - this.left = config.left; - this.right = config.right; - - // Delay mixin to runtime, when all nodes have been defined, and - // mixin only once. ValueExpressionMixin has circular dependencies. - if (!valueExpressionMixed) { - valueExpressionMixed = true; - _.extend(InNode.prototype, valueExpressionMixin()); - } - }, -})); - -// allow aliasing -var AliasNode = require('./alias'); -_.extend(InNode.prototype, AliasNode.AliasMixin); - -module.exports = InNode; diff --git a/lib/node/in.ts b/lib/node/in.ts new file mode 100644 index 00000000..2261c2af --- /dev/null +++ b/lib/node/in.ts @@ -0,0 +1,17 @@ +import { AliasMixin } from './alias.js'; +import { Node } from './node.js'; +import { classMap, ValueExpressionNode } from './_internal.js'; + +export class InNode extends ValueExpressionNode { + public left: Node; + public right: Node | Node[]; + constructor(config: { left: Node; right: Node | Node[] }) { + super('IN'); + this.left = config.left; + this.right = config.right; + } + + public as = AliasMixin.as; +} + +classMap.set('IN', InNode); diff --git a/lib/node/index.js b/lib/node/index.js deleted file mode 100644 index 66c0e481..00000000 --- a/lib/node/index.js +++ /dev/null @@ -1,101 +0,0 @@ -'use strict'; - -var assert = require('assert'); -var getDialect = require('../dialect'); -var util = require('util'); - -var Node = function(type) { - /* jshint unused: false */ - this.nodes = []; -}; - -Node.prototype.toNode = function() { - return this; -}; - -Node.prototype.add = function(node) { - assert(node, 'Error while trying to add a non-existant node to a query'); - var newNode; - if (typeof node === 'string') newNode = new TextNode(node); - else if (node.toNode) newNode = node.toNode(); - else newNode = node; - this.nodes.push(newNode); - return this; -}; - -Node.prototype.unshift = function(node) { - assert(node, 'Error while trying to add a non-existant node to a query'); - this.nodes.unshift(typeof node === 'string' ? new TextNode(node) : node.toNode()); - return this; -}; - -// Before the change that introduced parallel dialects, every node could be turned -// into a query. The parallel dialects change made it impossible to change some nodes -// into a query because not all nodes are constructed with the sql instance. -var determineDialect = function(query, dialect) { - var sql = query.sql || (query.table && query.table.sql); - var Dialect; - - if (dialect) { - // dialect is specified - Dialect = getDialect(dialect); - } else if (sql && sql.dialect) { - // dialect is not specified, use the dialect from the sql instance - Dialect = sql.dialect; - } else { - // dialect is not specified, use the default dialect - Dialect = require('../').dialect; - } - return Dialect; -}; - -var initializeDialect = function(Dialect, query) { - var config = query.sql ? query.sql.config : {}; - return new Dialect(config); -}; - -Node.prototype.toQuery = function(dialect) { - var Dialect = determineDialect(this, dialect); - return initializeDialect(Dialect, this).getQuery(this); -}; - -Node.prototype.toNamedQuery = function(name, dialect) { - if (!name || typeof name !== 'string' || name === '') { - throw new Error('A query name has to be a non-empty String.'); - } - var query = this.toQuery(dialect); - query.name = name; - return query; -}; - -Node.prototype.toString = function(dialect) { - var Dialect = determineDialect(this, dialect); - return initializeDialect(Dialect, this).getString(this); -}; - -Node.prototype.addAll = function(nodes) { - for(var i = 0, len = nodes.length; i < len; i++) { - this.add(nodes[i]); - } - return this; -}; - -Node.define = function(def) { - var c = function() { - Node.call(this); - }; - // allow custom sub-class constructor - if(def.constructor && def.constructor !== {}.constructor) { - c = def.constructor; - } - util.inherits(c, Node); - for (var key in def) { - if (def.hasOwnProperty(key)) { - c.prototype[key] = def[key]; - } - } - return c; -}; - -module.exports = Node; -var TextNode = require('./text'); diff --git a/lib/node/indexes.js b/lib/node/indexes.js deleted file mode 100644 index b1614a9a..00000000 --- a/lib/node/indexes.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -var Node = require('./'); - -var IndexesNode = Node.define({ - type: 'INDEXES', - - constructor: function(table) { - Node.call(this); - - this.table = table; - } -}); - -module.exports = IndexesNode; diff --git a/lib/node/indexes.ts b/lib/node/indexes.ts new file mode 100644 index 00000000..4e814524 --- /dev/null +++ b/lib/node/indexes.ts @@ -0,0 +1,12 @@ +import { Node } from './node.js'; +import { Table } from '../table.js'; + +export class IndexesNode extends Node { + public table: Table; + + constructor(table: Table) { + super('INDEXES'); + + this.table = table; + } +} diff --git a/lib/node/insert.js b/lib/node/insert.js deleted file mode 100644 index 9cd12fbe..00000000 --- a/lib/node/insert.js +++ /dev/null @@ -1,70 +0,0 @@ -'use strict'; - -var DefaultNode = require('./default'); -var Node = require('./'); -var ParameterNode = require('./parameter'); - -var Insert = Node.define({ - type: 'INSERT', - constructor: function () { - Node.call(this); - this.names = []; - this.columns = []; - this.valueSets = []; - } -}); - -module.exports = Insert; - -Insert.prototype.add = function (nodes) { - var hasColumns = false; - var hasValues = false; - var self = this; - var values = {}; - nodes.forEach(function (node) { - var column = node.toNode(); - var name = column.name; - var idx = self.names.indexOf(name); - if (idx < 0) { - self.names.push(name); - self.columns.push(column); - } - hasColumns = true; - hasValues = hasValues || column.value !== undefined; - values[name] = column; - }); - - // When none of the columns have a value, it's ambiguous whether the user - // intends to insert a row of default values or append a SELECT statement - // later. Resolve the ambiguity by assuming that if no columns are specified - // it is a row of default values, otherwise a SELECT will be added. - if (hasValues || !hasColumns) { - this.valueSets.push(values); - } - - return self; -}; - -/* - * Get parameters for all values to be inserted. This function - * handles handles bulk inserts, where keys may be present - * in some objects and not others. When keys are not present, - * the insert should refer to the column value as DEFAULT. - */ -Insert.prototype.getParameters = function () { - var self = this; - return this.valueSets - .map(function (nodeDict) { - var set = []; - self.names.forEach(function (name) { - var node = nodeDict[name]; - if (node) { - set.push(ParameterNode.getNodeOrParameterNode(node.value)); - } - else { - set.push(new DefaultNode()); - } - }); - return set; - }); -}; diff --git a/lib/node/insert.ts b/lib/node/insert.ts new file mode 100644 index 00000000..c7ce9ce4 --- /dev/null +++ b/lib/node/insert.ts @@ -0,0 +1,70 @@ +import { Column } from '../column.js'; +import { INodeable } from '../nodeable.js'; +import { ColumnNode } from './column.js'; +import { DefaultNode } from './default.js'; +import { Node } from './node.js'; +import { ParameterNode } from './parameter.js'; + +export class InsertNode extends Node { + public names: string[]; + public columns: ColumnNode[]; + public valueSets: { [key: string]: ColumnNode }[]; + constructor() { + super('INSERT'); + this.names = []; + this.columns = []; + this.valueSets = []; + } + + public add(nodes: Column[] | Node | INodeable | string): this { + if (!Array.isArray(nodes)) { + throw new Error('Not an array of column instances'); + } + let hasColumns = false; + let hasValues = false; + const values: { [key: string]: ColumnNode } = {}; + nodes.forEach((node) => { + const column = node.toNode(); + const name = column.name; + const idx = this.names.indexOf(name); + if (idx < 0) { + this.names.push(name); + this.columns.push(column); + } + hasColumns = true; + hasValues = hasValues || column.value !== undefined; + values[name] = column; + }); + + // When none of the columns have a value, it's ambiguous whether the user + // intends to insert a row of default values or append a SELECT statement + // later. Resolve the ambiguity by assuming that if no columns are specified + // it is a row of default values, otherwise a SELECT will be added. + if (hasValues || !hasColumns) { + this.valueSets.push(values); + } + + return this; + } + + /* + * Get parameters for all values to be inserted. This function + * handles handles bulk inserts, where keys may be present + * in some objects and not others. When keys are not present, + * the insert should refer to the column value as DEFAULT. + */ + public getParameters() { + return this.valueSets.map((nodeDict) => { + const set: Node[] = []; + this.names.forEach((name) => { + const node = nodeDict[name]; + if (node) { + set.push(ParameterNode.getNodeOrParameterNode(node.value)); + } else { + set.push(new DefaultNode()); + } + }); + return set; + }); + } +} diff --git a/lib/node/interval.js b/lib/node/interval.js deleted file mode 100644 index 9f46f9ab..00000000 --- a/lib/node/interval.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; - -var Node = require('./index'); -var ParameterNode = require('./parameter'); - -var IntervalNode = Node.define({ - type: 'INTERVAL', - constructor: function(args) { - Node.call(this); - var interval = args[0] || {}; - this.years = interval.years; - this.months = interval.months; - this.days = interval.days; - this.hours = interval.hours; - this.minutes = interval.minutes; - this.seconds = interval.seconds; - } -}); - -module.exports = IntervalNode; - diff --git a/lib/node/interval.ts b/lib/node/interval.ts new file mode 100644 index 00000000..f485c1cc --- /dev/null +++ b/lib/node/interval.ts @@ -0,0 +1,29 @@ +import { Node } from './node.js'; + +interface Interval { + years: number; + months: number; + days: number; + hours: number; + minutes: number; + seconds: number; +} + +export class IntervalNode extends Node { + public years: number; + public months: number; + public days: number; + public hours: number; + public minutes: number; + public seconds: number; + constructor(args: Interval[]) { + super('INTERVAL'); + const interval = args[0] || {}; + this.years = interval.years; + this.months = interval.months; + this.days = interval.days; + this.hours = interval.hours; + this.minutes = interval.minutes; + this.seconds = interval.seconds; + } +} diff --git a/lib/node/join.js b/lib/node/join.js deleted file mode 100644 index bbc1f93a..00000000 --- a/lib/node/join.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -var Node = require('./index'); -var JoinNode = module.exports = Node.define({ - type: 'JOIN', - constructor: function(subType, from, to) { - Node.call(this); - this.sql = (from.table && from.table.sql) || (to.table && to.table.sql); - this.subType = subType; - this.from = from.toNode(); - this.to = to.toNode(); - }, - on: function(node) { - this.on = node; - return this; - }, - join: function(other) { - return new JoinNode('INNER', this, other); - }, - leftJoin: function(other) { - return new JoinNode('LEFT', this, other); - } -}); diff --git a/lib/node/join.ts b/lib/node/join.ts new file mode 100644 index 00000000..cab29b1d --- /dev/null +++ b/lib/node/join.ts @@ -0,0 +1,27 @@ +import { INodeable } from '../nodeable.js'; +import { hasTable } from '../tableTracker.js'; +import { Node } from './node.js'; + +export class JoinNode extends Node { + public subType: string; + public from: Node; + public to: Node; + public onNode!: Node; + constructor(subType: string, from: INodeable, to: INodeable) { + super('JOIN'); + this.sql = (hasTable(from) && from.table.sql) || (hasTable(to) && to.table.sql) || undefined; + this.subType = subType; + this.from = from.toNode(); + this.to = to.toNode(); + } + public on(node: Node) { + this.onNode = node; + return this; + } + public join(other: INodeable) { + return new JoinNode('INNER', this, other); + } + public leftJoin(other: INodeable) { + return new JoinNode('LEFT', this, other); + } +} diff --git a/lib/node/literal.js b/lib/node/literal.js deleted file mode 100644 index f5a1ea58..00000000 --- a/lib/node/literal.js +++ /dev/null @@ -1,16 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'LITERAL', - constructor: function(literal) { - Node.call(this); - this.literal = literal; - this.alias = null; - }, - as: function(alias) { - this.alias = alias; - return this; - } -}); diff --git a/lib/node/literal.ts b/lib/node/literal.ts new file mode 100644 index 00000000..9a93beef --- /dev/null +++ b/lib/node/literal.ts @@ -0,0 +1,15 @@ +import { Node } from './node.js'; + +export class LiteralNode extends Node { + public literal: string; + public alias?: string; + constructor(literal: string) { + super('LITERAL'); + this.literal = literal; + this.alias = undefined; + } + public as(alias: string) { + this.alias = alias; + return this; + } +} diff --git a/lib/node/modifier.ts b/lib/node/modifier.ts new file mode 100644 index 00000000..430b16e4 --- /dev/null +++ b/lib/node/modifier.ts @@ -0,0 +1,13 @@ +import { Node } from './node.js'; +import { ParameterNode } from './parameter.js'; +import { Query } from './query.js'; + +export class ModifierNode extends Node { + public query: Query; + public count: Node; + constructor(query: Query, type: 'LIMIT' | 'OFFSET', count: unknown) { + super(type); + this.query = query; + this.count = ParameterNode.getNodeOrParameterNode(count); + } +} diff --git a/lib/node/node.ts b/lib/node/node.ts new file mode 100644 index 00000000..d846dd23 --- /dev/null +++ b/lib/node/node.ts @@ -0,0 +1,82 @@ +import assert from 'assert'; +import { DEFAULT_DIALECT, getDialect } from '../dialect/mapper.js'; +import type { Dialect } from '../dialect/dialect.js'; +import { INodeable, instanceofINodeable } from '../nodeable.js'; +import type { Sql } from '../sql.js'; +import type { Query } from './query.js'; + +export abstract class Node implements INodeable { + public sql?: Sql; + public readonly type: string; + public nodes: Node[]; + constructor(type: string) { + this.type = type; + this.nodes = []; + } + public toNode() { + return this; + } + public add(node: Node | INodeable) { + assert(node, 'Error while trying to add a non-existent node to a query'); + if (!instanceofINodeable(node)) { + throw new Error('Expected Node or INodeable, got ' + typeof node); + } + this.nodes.push(node.toNode()); + return this; + } + public unshift(node: Node | INodeable) { + assert(node, 'Error while trying to add a non-existent node to a query'); + if (!instanceofINodeable(node)) { + throw new Error('Expected Node or INodeable, got ' + typeof node); + } + this.nodes.unshift(node.toNode()); + return this; + } + public toQuery(dialect?: string) { + const DialectClass = determineDialect(this, dialect); + return initializeDialect(DialectClass, this).getQuery(this as unknown as Query); + } + public toNamedQuery(name: string, dialect?: string) { + if (!name || typeof name !== 'string' || name === '') { + throw new Error('A query name has to be a non-empty String.'); + } + const query = this.toQuery(dialect); + return { ...query, name }; + } + public toString(dialect?: string) { + const DialectClass = determineDialect(this, dialect); + return initializeDialect(DialectClass, this).getString(this as unknown as Query); + } + public addAll(nodes: (Node | INodeable)[]) { + for (let i = 0, len = nodes.length; i < len; i++) { + this.add(nodes[i]); + } + return this; + } +} + +// Before the change that introduced parallel dialects, every node could be turned +// into a query. The parallel dialects change made it impossible to change some nodes +// into a query because not all nodes are constructed with the sql instance. +const determineDialect = (query: any, dialect?: string): new (...args: any[]) => Dialect => { + const sql = query.sql || (query.table && query.table.sql); + let DialectClass; + + if (dialect) { + // dialect is specified + DialectClass = getDialect(dialect); + } else if (sql && sql.dialect) { + // dialect is not specified, use the dialect from the sql instance + DialectClass = sql.dialect; + } else { + // dialect is not specified, use the default dialect + DialectClass = getDialect(DEFAULT_DIALECT); + } + return DialectClass; +}; + +const initializeDialect = Dialect>(DialectClass: T, query: any): Dialect => { + const sql = query.sql || (query.table && query.table.sql); + const config = sql ? sql.config : {}; + return new DialectClass(config); +}; diff --git a/lib/node/notIn.js b/lib/node/notIn.js deleted file mode 100644 index c50976c3..00000000 --- a/lib/node/notIn.js +++ /dev/null @@ -1,28 +0,0 @@ -'use strict'; - -var _ = require('lodash'); -var Node = require('./index'); -var valueExpressionMixin = require('./valueExpression'); - -var valueExpressionMixed = false; -var NotInNode = Node.define(_.extend({ - type: 'NOT IN', - constructor: function(config) { - Node.call(this); - this.left = config.left; - this.right = config.right; - - // Delay mixin to runtime, when all nodes have been defined, and - // mixin only once. ValueExpressionMixin has circular dependencies. - if (!valueExpressionMixed) { - valueExpressionMixed = true; - _.extend(NotInNode.prototype, valueExpressionMixin()); - } - }, -})); - -// allow aliasing -var AliasNode = require('./alias'); -_.extend(NotInNode.prototype, AliasNode.AliasMixin); - -module.exports = NotInNode; diff --git a/lib/node/notIn.ts b/lib/node/notIn.ts new file mode 100644 index 00000000..63d3fb70 --- /dev/null +++ b/lib/node/notIn.ts @@ -0,0 +1,17 @@ +import { AliasMixin } from './alias.js'; +import { Node } from './node.js'; +import { classMap, ValueExpressionNode } from './_internal.js'; + +export class NotInNode extends ValueExpressionNode { + public left: Node; + public right: Node | Node[]; + constructor(config: { left: Node; right: Node | Node[] }) { + super('NOT IN'); + this.left = config.left; + this.right = config.right; + } + + public as = AliasMixin.as; +} + +classMap.set('NOT IN', NotInNode); diff --git a/lib/node/onConflict.js b/lib/node/onConflict.js deleted file mode 100644 index cc71ac47..00000000 --- a/lib/node/onConflict.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'ONCONFLICT' -}); diff --git a/lib/node/onConflict.ts b/lib/node/onConflict.ts new file mode 100644 index 00000000..b10082a9 --- /dev/null +++ b/lib/node/onConflict.ts @@ -0,0 +1,17 @@ +import { INodeable } from '../nodeable.js'; +import { Node } from './node.js'; + +export class OnConflictNode extends Node { + public columns?: string[]; + public constraint?: string; + public where?: Node; + public update?: string[]; + + constructor(config: { columns?: string[]; constraint?: string; where?: INodeable; update?: string[] } = {}) { + super('ONCONFLICT'); + this.columns = config.columns; + this.constraint = config.constraint; + this.where = config.where?.toNode(); + this.update = config.update; + } +} diff --git a/lib/node/onDuplicate.js b/lib/node/onDuplicate.js deleted file mode 100644 index cd653cb3..00000000 --- a/lib/node/onDuplicate.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'ONDUPLICATE' -}); diff --git a/lib/node/onDuplicate.ts b/lib/node/onDuplicate.ts new file mode 100644 index 00000000..49a37b8e --- /dev/null +++ b/lib/node/onDuplicate.ts @@ -0,0 +1,7 @@ +import { Node } from './node.js'; + +export class OnDuplicateNode extends Node { + constructor() { + super('ONDUPLICATE'); + } +} diff --git a/lib/node/operator.ts b/lib/node/operator.ts new file mode 100644 index 00000000..759cc4d8 --- /dev/null +++ b/lib/node/operator.ts @@ -0,0 +1,54 @@ +import { BinaryNode, PostfixUnaryNode, PrefixUnaryNode, TernaryNode } from './_internal.js'; +import { Node } from './node.js'; +import { ParameterNode } from './parameter.js'; + +// Process values, wrapping them in ParameterNode if necessary. +const processParam = (val: unknown): Node => { + if (Array.isArray(val)) { + throw new Error('expected single value'); + } + return ParameterNode.getNodeOrParameterNode(val); +}; +const processParamOrParams = (val: any): Node | Node[] => { + return Array.isArray(val) ? val.map(ParameterNode.getNodeOrParameterNode) : ParameterNode.getNodeOrParameterNode(val); +}; + +export const prefixUnaryOperator = (operator: string) => { + return (left: any): PrefixUnaryNode => { + return new PrefixUnaryNode({ + left: processParam(left), + operator, + }); + }; +}; + +export const postfixUnaryOperator = (operator: string) => { + return (left: any): PostfixUnaryNode => { + return new PostfixUnaryNode({ + left: processParam(left), + operator, + }); + }; +}; + +export const binaryOperator = (operator: string) => { + return (left: any, val: any): BinaryNode => { + return new BinaryNode({ + left: processParam(left), + operator, + right: processParamOrParams(val), + }); + }; +}; + +export const ternaryOperator = (operator: string, separator: string) => { + return (left: any, middle: any, right: any): TernaryNode => { + return new TernaryNode({ + left: processParam(left), + operator, + middle: processParam(middle), + separator, + right: processParam(right), + }); + }; +}; diff --git a/lib/node/orIgnore.js b/lib/node/orIgnore.js deleted file mode 100644 index e23c9d6d..00000000 --- a/lib/node/orIgnore.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'OR IGNORE' -}); diff --git a/lib/node/orIgnore.ts b/lib/node/orIgnore.ts new file mode 100644 index 00000000..1ff2a5bc --- /dev/null +++ b/lib/node/orIgnore.ts @@ -0,0 +1,7 @@ +import { Node } from './node.js'; + +export class OrIgnoreNode extends Node { + constructor() { + super('OR IGNORE'); + } +} diff --git a/lib/node/orderBy.js b/lib/node/orderBy.js deleted file mode 100644 index b97fb891..00000000 --- a/lib/node/orderBy.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'ORDER BY' -}); diff --git a/lib/node/orderBy.ts b/lib/node/orderBy.ts new file mode 100644 index 00000000..8a6087cd --- /dev/null +++ b/lib/node/orderBy.ts @@ -0,0 +1,13 @@ +import { ModifierNode } from './modifier.js'; +import { Node } from './node.js'; + +export class OrderByNode extends Node { + public msSQLOffsetNode?: ModifierNode; + public msSQLLimitNode?: ModifierNode; + constructor() { + super('ORDER BY'); + // used when processing OFFSET and LIMIT clauses in MSSQL + this.msSQLOffsetNode = undefined; + this.msSQLLimitNode = undefined; + } +} diff --git a/lib/node/orderByValue.js b/lib/node/orderByValue.js deleted file mode 100644 index 47a8d5c0..00000000 --- a/lib/node/orderByValue.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -var OrderByColumn = Node.define({ - type: 'ORDER BY VALUE', - constructor: function(config) { - Node.call(this); - this.value = config.value; - this.direction = config.direction; - // used when processing OFFSET and LIMIT clauses in MSSQL - this.msSQLOffsetNode=undefined; - this.msSQLLimitNode=undefined; - } -}); - - module.exports = OrderByColumn; diff --git a/lib/node/orderByValue.ts b/lib/node/orderByValue.ts new file mode 100644 index 00000000..df43ce93 --- /dev/null +++ b/lib/node/orderByValue.ts @@ -0,0 +1,15 @@ +import { Node } from './node.js'; +import { TextNode } from './text.js'; +import { classMap } from './valueExpression.js'; + +export class OrderByValueNode extends Node { + public value: Node; + public direction?: TextNode; + constructor(config: { value: Node; direction?: TextNode }) { + super('ORDER BY VALUE'); + this.value = config.value; + this.direction = config.direction; + } +} + +classMap.set('ORDER BY VALUE', OrderByValueNode); diff --git a/lib/node/parameter.js b/lib/node/parameter.js deleted file mode 100644 index 051ed852..00000000 --- a/lib/node/parameter.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -var ParameterNode = module.exports = Node.define({ - type: 'PARAMETER', - constructor: function(val) { - Node.call(this); - this._val = val; - this.isExplicit = false; - }, - value: function() { - return this._val; - } -}); - -// wrap a value as a parameter node if value is not already a node -module.exports.getNodeOrParameterNode = function(value) { - if (value && value.toNode) { - // use toNode - return value.toNode(); - } else { - // wrap as parameter node - return new ParameterNode(value); - } -}; diff --git a/lib/node/parameter.ts b/lib/node/parameter.ts new file mode 100644 index 00000000..db1cac05 --- /dev/null +++ b/lib/node/parameter.ts @@ -0,0 +1,19 @@ +import { INodeable, instanceofINodeable } from '../nodeable.js'; +import { Node } from './node.js'; + +export class ParameterNode extends Node { + // wrap a value as a parameter node if value is not already a node + public static getNodeOrParameterNode(value?: INodeable | unknown) { + return value && instanceofINodeable(value) ? value.toNode() : new ParameterNode(value); + } + public isExplicit: boolean; + private val: any; + constructor(val: any) { + super('PARAMETER'); + this.val = val; + this.isExplicit = false; + } + public value() { + return this.val; + } +} diff --git a/lib/node/postfixUnary.js b/lib/node/postfixUnary.js deleted file mode 100644 index 8c66b89f..00000000 --- a/lib/node/postfixUnary.js +++ /dev/null @@ -1,28 +0,0 @@ -'use strict'; - -var _ = require('lodash'); -var Node = require('./index'); -var valueExpressionMixin = require('./valueExpression'); - -var valueExpressionMixed = false; -var PostfixUnaryNode = Node.define({ - type: 'POSTFIX UNARY', - constructor: function(config) { - Node.call(this); - this.left = config.left; - this.operator = config.operator; - - // Delay mixin to runtime, when all nodes have been defined, and - // mixin only once. ValueExpressionMixin has circular dependencies. - if (!valueExpressionMixed) { - valueExpressionMixed = true; - _.extend(PostfixUnaryNode.prototype, valueExpressionMixin()); - } - } -}); - -// allow aliasing -var AliasNode = require('./alias'); -_.extend(PostfixUnaryNode.prototype, AliasNode.AliasMixin); - -module.exports = PostfixUnaryNode; diff --git a/lib/node/postfixUnary.ts b/lib/node/postfixUnary.ts new file mode 100644 index 00000000..f757e9fe --- /dev/null +++ b/lib/node/postfixUnary.ts @@ -0,0 +1,17 @@ +import { AliasMixin } from './alias.js'; +import { Node } from './node.js'; +import { classMap, ValueExpressionNode } from './_internal.js'; + +export class PostfixUnaryNode extends ValueExpressionNode { + public left: Node; + public operator: string; + constructor(config: { left: Node; operator: string }) { + super('POSTFIX UNARY'); + this.left = config.left; + this.operator = config.operator; + } + + public as = AliasMixin.as; +} + +classMap.set('POSTFIX UNARY', PostfixUnaryNode); diff --git a/lib/node/prefixUnary.js b/lib/node/prefixUnary.js deleted file mode 100644 index fbde69c0..00000000 --- a/lib/node/prefixUnary.js +++ /dev/null @@ -1,28 +0,0 @@ -'use strict'; - -var _ = require('lodash'); -var Node = require('./index'); -var valueExpressionMixin = require('./valueExpression'); - -var valueExpressionMixed = false; -var PrefixUnaryNode = Node.define({ - type: 'PREFIX UNARY', - constructor: function(config) { - Node.call(this); - this.left = config.left; - this.operator = config.operator; - - // Delay mixin to runtime, when all nodes have been defined, and - // mixin only once. ValueExpressionMixin has circular dependencies. - if (!valueExpressionMixed) { - valueExpressionMixed = true; - _.extend(PrefixUnaryNode.prototype, valueExpressionMixin()); - } - } -}); - -// allow aliasing -var AliasNode = require('./alias'); -_.extend(PrefixUnaryNode.prototype, AliasNode.AliasMixin); - -module.exports = PrefixUnaryNode; diff --git a/lib/node/prefixUnary.ts b/lib/node/prefixUnary.ts new file mode 100644 index 00000000..ccbd9e8c --- /dev/null +++ b/lib/node/prefixUnary.ts @@ -0,0 +1,17 @@ +import { AliasMixin } from './alias.js'; +import { Node } from './node.js'; +import { classMap, ValueExpressionNode } from './_internal.js'; + +export class PrefixUnaryNode extends ValueExpressionNode { + public left: Node; + public operator: string; + constructor(config: { left: Node; operator: string }) { + super('PREFIX UNARY'); + this.left = config.left; + this.operator = config.operator; + } + + public as = AliasMixin.as; +} + +classMap.set('PREFIX UNARY', PrefixUnaryNode); diff --git a/lib/node/query.js b/lib/node/query.js deleted file mode 100644 index ebb3ecfa..00000000 --- a/lib/node/query.js +++ /dev/null @@ -1,552 +0,0 @@ -'use strict'; - -var _ = require('lodash'); -var alias = require('./alias'); -var assert = require('assert'); -var sliced = require('sliced'); -var util = require('util'); -var valueExpressionMixin = require('./valueExpression'); - -var Node = require('./'); -var Select = require('./select'); -var From = require('./from'); -var Where = require('./where'); -var OrderBy = require('./orderBy'); -var GroupBy = require('./groupBy'); -var Having = require('./having'); -var Insert = require('./insert'); -var Replace = require('./replace'); -var Update = require('./update'); -var Delete = require('./delete'); -var Returning = require('./returning'); -var OnDuplicate = require('./onDuplicate'); -var OnConflict = require('./onConflict'); -var ForUpdate = require('./forUpdate'); -var ForShare = require('./forShare'); -var Create = require('./create'); -var Drop = require('./drop'); -var Truncate = require('./truncate'); -var Distinct = require('./distinct'); -var DistinctOn = require('./distinctOn'); -var Alter = require('./alter'); -var AddColumn = require('./addColumn'); -var DropColumn = require('./dropColumn'); -var RenameColumn = require('./renameColumn'); -var Rename = require('./rename'); -var Column = require('../column'); -var ParameterNode = require('./parameter'); -var PrefixUnaryNode = require('./prefixUnary'); -var IfExists = require('./ifExists'); -var IfNotExists = require('./ifNotExists'); -var OrIgnore = require('./orIgnore'); -var Cascade = require('./cascade'); -var Restrict = require('./restrict'); -var Indexes = require('./indexes'); -var CreateIndex = require('./createIndex'); -var DropIndex = require('./dropIndex'); -var Table = require('./table'); -var CreateView = require('./createView'); -var JoinNode = require('./join'); - -var Modifier = Node.define({ - constructor: function(table, type, count) { - this.table = table; - this.type = type; - this.count = count; - } -}); - -// get the first element of an arguments if it is an array, else return arguments as an array -var getArrayOrArgsAsArray = function(args) { - if (util.isArray(args[0])) { - return args[0]; - } - return sliced(args); -}; - -var Query = Node.define({ - type: 'QUERY', - - constructor: function(table) { - Node.call(this); - this.table = table; - if (table) { - this.sql = table.sql; - } - }, - - select: function() { - var select; - if (this._select) { - select = this._select; - } else { - select = this._select = new Select(); - this.add(select); - } - - //allow things like .select(a.star(), [ a.id, a.name ]) - //this will flatten them into a single array - var args = sliced(arguments).reduce(function(cur, next) { - if (util.isArray(next)) { - return cur.concat(next); - } - - cur.push(next); - return cur; - }, []); - - select.addAll(args); - - // if this is a subquery then add reference to this column - if (this.type === 'SUBQUERY') { - for (var j = 0; j < select.nodes.length; j++) { - var name = select.nodes[j].alias || select.nodes[j].name; - var col = new Column(select.nodes[j]); - col.name = name; - col.property = name; - col.table = this; - if (this[name] === undefined) { - this[name] = col; - } - } - } - return this; - }, - - star: function() { - assert(this.type === 'SUBQUERY', 'star() can only be used on a subQuery'); - return new Column({ - table: this, - star: true - }); - }, - - from: function() { - var tableNodes = arguments; - - if (Array.isArray(arguments[0])) { - tableNodes = arguments[0]; - } - - for (var i=0; i 1) { - // allow multiple where clause arguments - var args = sliced(arguments); - for (var i = 0; i < args.length; i++) { - this.where(args[i]); - } - return this; - } - // calling #where twice functions like calling #where & then #and - if (this.whereClause) { - return this.and(node); - } - this.whereClause = new Where(this.table); - this.whereClause.add(node); - return this.add(this.whereClause); - }, - - or: function(node) { - if (!this.whereClause) return this.where(node); - this.whereClause.or(node); - return this; - }, - - and: function(node) { - if (!this.whereClause) return this.where(node); - this.whereClause.and(node); - return this; - }, - - order: function() { - var args = getArrayOrArgsAsArray(arguments); - var orderBy; - if (args.length === 0) { - return this; - } - if (this._orderBy) { - orderBy = this._orderBy; - } else { - orderBy = this._orderBy = new OrderBy(); - this.add(orderBy); - } - orderBy.addAll(args); - return this; - }, - - group: function() { - var args = getArrayOrArgsAsArray(arguments); - var groupBy = new GroupBy().addAll(args); - return this.add(groupBy); - }, - - having: function() { - var args = getArrayOrArgsAsArray(arguments); - var having = new Having().addAll(args); - return this.add(having); - }, - - insert: function(o) { - var self = this; - - var args = sliced(arguments); - // object literal - if (arguments.length === 1 && !o.toNode && !o.forEach) { - args = []; - Object.keys(o).forEach(function(key) { - var col = self.table.get(key); - if(col && !col.autoGenerated) - args.push(col.value(o[key])); - }); - } else if (o.forEach) { - o.forEach(function(arg) { - return self.insert.call(self, arg); - }); - return self; - } - - if (self.insertClause) { - self.insertClause.add(args); - return self; - } else { - self.insertClause = new Insert(); - self.insertClause.add(args); - return self.add(self.insertClause); - } - - }, - - replace: function(o) { - var self = this; - - var args = sliced(arguments); - // object literal - if (arguments.length === 1 && !o.toNode && !o.forEach) { - args = []; - Object.keys(o).forEach(function(key) { - var col = self.table.get(key); - if(col && !col.autoGenerated) - args.push(col.value(o[key])); - }); - } else if (o.forEach) { - o.forEach(function(arg) { - return self.replace.call(self, arg); - }); - return self; - } - - if (self.replaceClause) { - self.replaceClause.add(args); - return self; - } else { - self.replaceClause = new Replace(); - self.replaceClause.add(args); - return self.add(self.replaceClause); - } - - }, - - update: function(o) { - var self = this; - var update = new Update(); - Object.keys(o).forEach(function(key) { - var col = self.table.get(key); - if(col && !col.autoGenerated) { - var val = o[key]; - update.add(col.value(ParameterNode.getNodeOrParameterNode(val))); - } - }); - return this.add(update); - }, - - parameter: function(v) { - var param = ParameterNode.getNodeOrParameterNode(v); - param.isExplicit = true; - return this.add(param); - }, - - delete: function(params) { - var result; - if (params) { - var TableDefinition = require('../table'); - if (params instanceof TableDefinition || Array.isArray(params)) { - //handle explicit delete queries: - // e.g. post.delete(post).from(post) -> DELETE post FROM post - // e.g. post.delete([post, user]).from(post) -> DELETE post, user FROM post - if (Array.isArray(params)) { - params = params.map(function(table) { return new Table(table); }); - } else { - params = [ new Table(params) ]; - } - result = this.add(new Delete().addAll(params)); - } else { - //syntax sugar for post.delete().from(post).where(params) - result = this.add(new Delete()).where(params); - } - } else{ - result = this.add(new Delete()); - } - return result; - }, - - returning: function() { - var returning = new Returning(); - if (arguments.length === 0) - returning.add('*'); - else - returning.addAll(getArrayOrArgsAsArray(arguments)); - - return this.add(returning); - }, - - onDuplicate: function(o) { - var self = this; - - var onDuplicate = new OnDuplicate(); - Object.keys(o).forEach(function(key) { - var col = self.table.get(key); - if(col && !col.autoGenerated) - var val = o[key]; - onDuplicate.add(col.value(ParameterNode.getNodeOrParameterNode(val))); // jshint ignore:line - }); - - return self.add(onDuplicate); - }, - - onConflict: function(o) { - var self = this; - - var onConflict = new OnConflict(); - Object.keys(o).forEach(function(key) { - onConflict[key] = o[key]; - }); - return self.add(onConflict); - }, - - forUpdate: function() { - assert(typeof this._select !== 'undefined', 'FOR UPDATE can be used only in a select statement'); - this.add(new ForUpdate()); - return this; - }, - - forShare: function() { - assert(typeof this._select !== 'undefined', 'FOR SHARE can be used only in a select statement'); - this.add(new ForShare()); - return this; - }, - - create: function(indexName) { - if (this.indexesClause) { - var createIndex = new CreateIndex(this.table, indexName); - this.add(createIndex); - return createIndex; - } else { - return this.add(new Create(this.table.isTemporary)); - } - }, - - drop: function() { - if (this.indexesClause) { - var args = sliced(arguments); - var dropIndex = new DropIndex(this.table, args); - this.add(dropIndex); - return dropIndex; - } else { - return this.add(new Drop(this.table)); - } - }, - - truncate: function() { - return this.add(new Truncate(this.table)); - }, - - distinct: function() { - return this.add(new Distinct()); - }, - - distinctOn: function() { - var distinctOn; - if (this._distinctOn) { - distinctOn = this._distinctOn; - } else { - var select = this.nodes.filter(function (node) {return node.type === 'SELECT';}).shift(); - - distinctOn = this._distinctOn = new DistinctOn(); - select.add(distinctOn); - } - - //allow things like .distinctOn(a.star(), [ a.id, a.name ]) - //this will flatten them into a single array - var args = sliced(arguments).reduce(function(cur, next) { - if (util.isArray(next)) { - return cur.concat(next); - } - - cur.push(next); - return cur; - }, []); - - distinctOn.addAll(args); - - return this; - }, - - alter: function() { - return this.add(new Alter()); - }, - - rename: function(newName) { - var renameClause = new Rename(); - if (!newName.toNode) { - newName = new Column({ - name: newName, - table: this.table - }); - } - renameClause.add(newName.toNode()); - this.nodes[0].add(renameClause); - return this; - }, - - addColumn: function(column, dataType) { - var addClause = new AddColumn(); - if (!column.toNode) { - column = new Column({ - name: column, - table: this.table - }); - } - if (dataType) { - column.dataType = dataType; - } - addClause.add(column.toNode()); - this.nodes[0].add(addClause); - return this; - }, - - dropColumn: function(column) { - var dropClause = new DropColumn(); - if (!column.toNode) { - column = new Column({ - name: column, - table: this.table - }); - } - dropClause.add(column.toNode()); - this.nodes[0].add(dropClause); - return this; - }, - - renameColumn: function(oldColumn, newColumn) { - var renameClause = new RenameColumn(); - if (!oldColumn.toNode) { - oldColumn = new Column({ - name: oldColumn, - table: this.table - }); - } - if (!newColumn.toNode) { - newColumn = new Column({ - name: newColumn, - table: this.table - }); - } - renameClause.add(oldColumn.toNode()); - renameClause.add(newColumn.toNode()); - this.nodes[0].add(renameClause); - return this; - }, - - limit: function(count) { - return this.add(new Modifier(this, 'LIMIT', count)); - }, - - offset: function(count) { - return this.add(new Modifier(this, 'OFFSET', count)); - }, - - exists: function() { - assert(this.type === 'SUBQUERY', 'exists() can only be used on a subQuery'); - return new PrefixUnaryNode({ - left: this, - operator: "EXISTS" - }); - }, - - notExists: function() { - assert(this.type === 'SUBQUERY', 'notExists() can only be used on a subQuery'); - return new PrefixUnaryNode({ - left: this, - operator: "NOT EXISTS" - }); - }, - - ifExists: function() { - this.nodes[0].unshift(new IfExists()); - return this; - }, - - ifNotExists: function() { - this.nodes[0].unshift(new IfNotExists()); - return this; - }, - - orIgnore: function() { - this.nodes[0].unshift(new OrIgnore()); - return this; - }, - - cascade: function() { - this.nodes[0].add(new Cascade()); - return this; - }, - - restrict: function() { - this.nodes[0].add(new Restrict()); - return this; - }, - - indexes: function() { - this.indexesClause = new Indexes({ - table: this.table - }); - return this.add(this.indexesClause); - }, - - createView: function(viewName) { - this.add(new CreateView(viewName)); - return this; - } -}); - -// Here we are extending query with valueExpressions so that it's possible to write queries like -// var query=sql.select(a.select(a.x.sum()).plus(b.select(b.y.sum())) -// which generates: -// SELECT (SELECT SUM(a.x) FROM a) + (SELECT SUM(b.y) FROM b) -// We need to remove "or" and "and" from here because it conflicts with the already existing functionality of appending -// to the where clause like so: -// var query=a.select().where(a.name.equals("joe")).or(a.name.equals("sam")) -var valueExpressions=valueExpressionMixin(); -delete valueExpressions.or; -delete valueExpressions.and; -_.extend(Query.prototype, valueExpressions); - -// Extend the query with the aliasMixin so that it's possible to write queries like -// var query=sql.select(a.select(a.count()).as("column1")) -// which generates: -// SELECT (SELECT COUNT(*) FROM a) AS "column1" -_.extend(Query.prototype, alias.AliasMixin); - -module.exports = Query; diff --git a/lib/node/query.ts b/lib/node/query.ts new file mode 100644 index 00000000..1f3f8009 --- /dev/null +++ b/lib/node/query.ts @@ -0,0 +1,580 @@ +import assert from 'assert'; +import sliced from 'sliced'; + +import { Column } from '../column.js'; +import { INodeable, instanceofINodeable, PartialNodeable } from '../nodeable.js'; +import { Table } from '../table.js'; +import { AddColumnNode } from './addColumn.js'; +import { AliasMixin } from './alias.js'; +import { AlterNode } from './alter.js'; +import { CascadeNode } from './cascade.js'; +import { ColumnNode } from './column.js'; +import { CreateNode } from './create.js'; +import { CreateIndexNode } from './createIndex.js'; +import { CreateViewNode } from './createView.js'; +import { DeleteNode } from './delete.js'; +import { DistinctNode } from './distinct.js'; +import { DistinctOnNode } from './distinctOn.js'; +import { DropNode } from './drop.js'; +import { DropColumnNode } from './dropColumn.js'; +import { DropIndexNode } from './dropIndex.js'; +import { ForShareNode } from './forShare.js'; +import { ForUpdateNode } from './forUpdate.js'; +import { FromNode } from './from.js'; +import { GroupByNode } from './groupBy.js'; +import { HavingNode } from './having.js'; +import { IfExistsNode } from './ifExists.js'; +import { IfNotExistsNode } from './ifNotExists.js'; +import { IndexesNode } from './indexes.js'; +import { InsertNode } from './insert.js'; +import { JoinNode } from './join.js'; +import { ModifierNode } from './modifier.js'; +import { Node } from './node.js'; +import { OnConflictNode } from './onConflict.js'; +import { OnDuplicateNode } from './onDuplicate.js'; +import { OrderByNode } from './orderBy.js'; +import { OrIgnoreNode } from './orIgnore.js'; +import { ParameterNode } from './parameter.js'; +import { PrefixUnaryNode } from './prefixUnary.js'; +import { RenameNode } from './rename.js'; +import { RenameColumnNode } from './renameColumn.js'; +import { ReplaceNode } from './replace.js'; +import { RestrictNode } from './restrict.js'; +import { ReturningNode } from './returning.js'; +import { SelectNode } from './select.js'; +import { TableNode } from './table.js'; +import { TextNode } from './text.js'; +import { TruncateNode } from './truncate.js'; +import { UpdateNode } from './update.js'; +import { ValueExpressionBaseNode } from './_internal.js'; +import { WhereNode } from './where.js'; +import { AsOfNode } from './asOf.js'; + +// get the first element of an arguments if it is an array, else return arguments as an array +const getArrayOrArgsAsArray = (args: (T | T[])[]): T[] => { + const first = args[0]; + return Array.isArray(first) ? first : sliced(args as T[]); +}; + +const nodeableOrTextNode = (val: INodeable | string) => { + return instanceofINodeable(val) ? val.toNode() : new TextNode(val); +} + +// Here we are extending query from ValueExpressionBaseNode so that it's possible to write queries like +// const query=sql.select(a.select(a.x.sum()).plus(b.select(b.y.sum())) +// which generates: +// SELECT (SELECT SUM(a.x) FROM a) + (SELECT SUM(b.y) FROM b) +export class Query extends ValueExpressionBaseNode { + public table: Table; + public nodes: Node[] = []; + public alias?: string; + private whereClause?: WhereNode; + private insertClause?: InsertNode; + private replaceClause?: ReplaceNode; + private indexesClause?: IndexesNode; + private _select?: SelectNode; + private _orderBy?: OrderByNode; + private _distinctOn?: DistinctOnNode; + + constructor(table: Table, isSubquery?: boolean) { + super(isSubquery ? 'SUBQUERY' : 'QUERY'); + + this.table = table; + if (table) { + this.sql = table.sql; + } + } + + // Extend the query with the aliasMixin so that it's possible to write queries like + // const query=sql.select(a.select(a.count()).as("column1")) + // which generates: + // SELECT (SELECT COUNT(*) FROM a) AS "column1" + public as = AliasMixin.as; + + public select(...args: any[]): this { + let select; + if (this._select) { + select = this._select; + } else { + select = this._select = new SelectNode(); + this.add(select); + } + + // allow things like .select(a.star(), [ a.id, a.name ]) + // this will flatten them into a single array + const flattenedArgs = sliced(args).reduce((cur: any[], next: any) => { + if (Array.isArray(next)) { + return cur.concat(next); + } + + cur.push(next); + return cur; + }, []); + + select.addAll(flattenedArgs.map(nodeableOrTextNode)); + + // if this is a subquery then add reference to this column + if (this.type === 'SUBQUERY') { + for (const node of select.nodes as ColumnNode[]) { + const name = node.alias || node.property || node.name; + const col = new Column(node as any); + col.name = name; + col.property = name; + col.table = this as any; + col.star = undefined; + const subQuery = (this as unknown as SubQuery); + if (subQuery[name] === undefined) { + subQuery[name] = col; + } + subQuery.columns.push(col); + } + } + return this; + } + + public star(): Column { + assert(this.type === 'SUBQUERY', 'star() can only be used on a subQuery'); + return new Column({ + star: true, + table: this as any + }); + } + + public from(node: INodeable[] | INodeable | string): this; + public from(...nodes: INodeable[]): this; + public from(...nodes: (string | INodeable | INodeable[])[]): this { + const sourceNodes = Array.isArray(nodes[0]) ? (nodes[0] as Table[]) : (nodes as Table[]); + + for (const node of sourceNodes) { + this.add(new FromNode().add(nodeableOrTextNode(node))); + } + + return this; + } + + public asOf(node: INodeable | string): this { + this.add(new AsOfNode().add(nodeableOrTextNode(node))); + return this; + } + + public leftJoin(other: INodeable): JoinNode { + assert(this.type === 'SUBQUERY', 'leftJoin() can only be used on a subQuery'); + return new JoinNode('LEFT', this, other.toNode()); + } + + public where(object: Partial | Node[] | Node | string): this; + public where(...nodes: Node[]): this; + public where(...nodes: (Node[] | Node | Partial | string)[]): this { + if (nodes.length > 1) { + // allow multiple where clause arguments + const args = sliced(nodes as Node[]); + for (const arg of args) { + this.where(arg); + } + return this; + } else { + const node = nodes[0] as Node[] | Node | Partial | string; + // calling #where twice functions like calling #where & then #and + if (this.whereClause) { + return this.and(node); + } + this.whereClause = new WhereNode(this.table); + this.whereClause.add(node); + return this.add(this.whereClause); + } + } + + public or(object: Partial | Node | string): this { + if (!this.whereClause) { + return this.where(object); + } + this.whereClause.or(object); + return this; + } + + public and(object: Partial | Node[] | Node | string): this; + public and(node: Node[] | Node | Partial | string): this { + if (!this.whereClause) { + return this.where(node); + } + this.whereClause.and(node); + return this; + } + + public order(node: INodeable[] | INodeable): this; + public order(...nodes: INodeable[]): this; + public order(...nodes: (INodeable[] | INodeable)[]): this { + const args: INodeable[] = getArrayOrArgsAsArray(nodes); + let orderBy; + if (args.length === 0) { + return this; + } + if (this._orderBy) { + orderBy = this._orderBy; + } else { + orderBy = this._orderBy = new OrderByNode(); + this.add(orderBy); + } + orderBy.addAll(args); + return this; + } + + public group(node: INodeable[] | INodeable): this; + public group(...nodes: INodeable[]): this; + public group(...nodes: (INodeable[] | INodeable)[]): this { + const args: INodeable[] = getArrayOrArgsAsArray(nodes); + const groupBy = new GroupByNode().addAll(args); + return this.add(groupBy); + } + + public having(node: INodeable[] | INodeable): this; + public having(...nodes: INodeable[]): this; + public having(...nodes: (INodeable[] | INodeable)[]): this { + const args: INodeable[] = getArrayOrArgsAsArray(nodes); + const having = new HavingNode().addAll(args); + return this.add(having); + } + + public insert(object: Column[] | Column): this; + // eslint-disable-next-line @typescript-eslint/unified-signatures + public insert(object: PartialNodeable[] | PartialNodeable): this; + public insert(...nodes: Column[]): this; + public insert(...nodes: (Column[] | Column | PartialNodeable[] | PartialNodeable)[]): this { + let args = sliced(nodes) as Column[]; + const object = nodes[0]; + + if (Array.isArray(object)) { + for (const col of object) { + this.insert(col as any); + } + return this; + } else if (!instanceofINodeable(object) && typeof object === 'object') { + args = []; + Object.keys(object).forEach((key) => { + const col = this.table.get(key); + if (col && !col.autoGenerated) { + args.push(col.value((object as any)[key])); + } + }); + } + + if (this.insertClause) { + this.insertClause.add(args); + return this; + } else { + this.insertClause = new InsertNode(); + this.insertClause.add(args); + return this.add(this.insertClause); + } + } + + public replace(object: Column[] | Column): this; + // eslint-disable-next-line @typescript-eslint/unified-signatures + public replace(object: Partial[] | Partial): this; + public replace(...nodes: Column[]): this; + public replace(...nodes: (Column[] | Column | Partial[] | Partial)[]): this { + let args = sliced(nodes) as Column[]; + const object = nodes[0]; + + if (Array.isArray(object)) { + for (const col of object) { + this.replace(col as any); + } + return this; + } else if (!instanceofINodeable(object) && typeof object === 'object') { + args = []; + Object.keys(object).forEach((key) => { + const col = this.table.get(key); + if (col && !col.autoGenerated) { + args.push(col.value((object as any)[key])); + } + }); + } + + if (this.replaceClause) { + this.replaceClause.add(args); + return this; + } else { + this.replaceClause = new ReplaceNode(); + this.replaceClause.add(args); + return this.add(this.replaceClause); + } + } + + public update(object: PartialNodeable): this { + const update = new UpdateNode(); + Object.keys(object).forEach((key) => { + const col = this.table.get(key); + if (col && !col.autoGenerated) { + const val = (object as any)[key]; + update.add(col.value(ParameterNode.getNodeOrParameterNode(val))); + } + }); + return this.add(update); + } + + public parameter(v: any): this { + const param = ParameterNode.getNodeOrParameterNode(v) as ParameterNode; + param.isExplicit = true; + return this.add(param); + } + + // eslint-disable-next-line @typescript-eslint/unified-signatures + public delete(table: Table[] | Table | Partial): this; + public delete(): this; + public delete(params?: Table | Table[] | Partial): this { + let result; + if (params) { + if (params instanceof Table || Array.isArray(params)) { + // handle explicit delete queries: + // e.g. post.delete(post).from(post) -> DELETE post FROM post + // e.g. post.delete([post, user]).from(post) -> DELETE post, user FROM post + const newParams = Array.isArray(params) ? params.map((table) => new TableNode(table)) : [new TableNode(params)]; + result = this.add(new DeleteNode().addAll(newParams)); + } else { + // syntax sugar for post.delete().from(post).where(params) + result = this.add(new DeleteNode()).where(params); + } + } else { + result = this.add(new DeleteNode()); + } + return result; + } + + public returning(...args: any[]): this { + const returning = new ReturningNode(); + if (args.length === 0) { + returning.add(new TextNode('*')); + } else { + returning.addAll(getArrayOrArgsAsArray(args).map(nodeableOrTextNode)); + } + + return this.add(returning); + } + + public onDuplicate(object: Partial): this { + const onDuplicate = new OnDuplicateNode(); + Object.keys(object).forEach((key) => { + const col = this.table.get(key)!; + let val; + if (col && !col.autoGenerated) { + val = (object as any)[key]; + } + onDuplicate.add(col.value(ParameterNode.getNodeOrParameterNode(val))); + }); + + return this.add(onDuplicate); + } + + public onConflict(options?: { constraint: string; update?: string[] } | { columns: string[]; where?: INodeable; update?: string[] }): this { + const onConflict = new OnConflictNode(options); + return this.add(onConflict); + } + + public forUpdate(): this { + assert(typeof this._select !== 'undefined', 'FOR UPDATE can be used only in a select statement'); + this.add(new ForUpdateNode()); + return this; + } + + public forShare(): this { + assert(typeof this._select !== 'undefined', 'FOR SHARE can be used only in a select statement'); + return this.add(new ForShareNode()); + } + + public create(): this + public create(indexName: string): CreateIndexNode + public create(indexName?: string): this | CreateIndexNode { + if (this.indexesClause) { + const createIndex = new CreateIndexNode(this.table, indexName!); + this.add(createIndex); + return createIndex; + } else { + return this.add(new CreateNode(this.table.isTemporary)); + } + } + + public drop(): this; + public drop(indexName: string): DropIndexNode; + public drop(...columns: Column[]): DropIndexNode; + public drop(): this | DropIndexNode { + if (this.indexesClause) { + const args = sliced(arguments); + const dropIndex = new DropIndexNode(this.table, args); + this.add(dropIndex); + return dropIndex; + } else { + return this.add(new DropNode(this.table)); + } + } + + public truncate(): this { + return this.add(new TruncateNode(this.table)); + } + + public distinct(): this { + return this.add(new DistinctNode()); + } + + public distinctOn(...args: any[]): this { + let distinctOn; + if (this._distinctOn) { + distinctOn = this._distinctOn; + } else { + const select = this.nodes.filter((node) => node.type === 'SELECT').shift(); + + distinctOn = this._distinctOn = new DistinctOnNode(); + select!.add(distinctOn); + } + + // allow things like .distinctOn(a.star(), [ a.id, a.name ]) + // this will flatten them into a single array + const flattenedArgs = sliced(args).reduce((cur, next) => { + if (Array.isArray(next)) { + return cur.concat(next); + } + + cur.push(next); + return cur; + }, []); + + distinctOn.addAll(flattenedArgs.map(nodeableOrTextNode)); + + return this; + } + + public alter(): this { + return this.add(new AlterNode()); + } + + public rename(newName: Column | string): this { + const renameClause = new RenameNode(); + if (typeof newName === 'string') { + newName = new Column({ + name: newName, + table: this.table + }); + } + renameClause.add(newName.toNode()); + this.nodes[0].add(renameClause); + return this; + } + + public addColumn(column: Column | string, dataType?: string): this { + const addClause = new AddColumnNode(); + if (typeof column === 'string') { + column = new Column({ + name: column, + table: this.table + }); + } + if (dataType) { + column.dataType = dataType; + } + addClause.add(column.toNode()); + this.nodes[0].add(addClause); + return this; + } + + public dropColumn(column: Column | string): this { + const dropClause = new DropColumnNode(); + if (typeof column === 'string') { + column = new Column({ + name: column, + table: this.table + }); + } + dropClause.add(column.toNode()); + this.nodes[0].add(dropClause); + return this; + } + + public renameColumn(oldColumn: Column | string, newColumn: Column | string): this { + const renameClause = new RenameColumnNode(); + if (typeof oldColumn === 'string') { + oldColumn = new Column({ + name: oldColumn, + table: this.table + }); + } + if (typeof newColumn === 'string') { + newColumn = new Column({ + name: newColumn, + table: this.table + }); + } + renameClause.add(oldColumn.toNode()); + renameClause.add(newColumn.toNode()); + this.nodes[0].add(renameClause); + return this; + } + + public limit(count: unknown): this { + return this.add(new ModifierNode(this, 'LIMIT', count)); + } + + public offset(count: unknown): this { + return this.add(new ModifierNode(this, 'OFFSET', count)); + } + + public exists(): PrefixUnaryNode { + assert(this.type === 'SUBQUERY', 'exists() can only be used on a subQuery'); + return new PrefixUnaryNode({ + left: this, + operator: 'EXISTS' + }); + } + + public notExists(): PrefixUnaryNode { + assert(this.type === 'SUBQUERY', 'notExists() can only be used on a subQuery'); + return new PrefixUnaryNode({ + left: this, + operator: 'NOT EXISTS' + }); + } + + public ifExists(): this { + this.nodes[0].unshift(new IfExistsNode()); + return this; + } + + public ifNotExists(): this { + this.nodes[0].unshift(new IfNotExistsNode()); + return this; + } + + public orIgnore(): this { + this.nodes[0].unshift(new OrIgnoreNode()); + return this; + } + + public cascade(): this { + this.nodes[0].add(new CascadeNode()); + return this; + } + + public restrict(): this { + this.nodes[0].add(new RestrictNode()); + return this; + } + + public indexes(): this { + this.indexesClause = new IndexesNode(this.table); + return this.add(this.indexesClause); + } + + public createView(viewName: string): this { + this.add(new CreateViewNode(viewName)); + return this; + } +} + +type SubQueryExtensions> = { + join: (other: INodeable) => JoinNode; +} & { + columns: Column[] +} & { + [P in NonNullable]: Column +}; + +export type SubQuery> = Query & SubQueryExtensions; \ No newline at end of file diff --git a/lib/node/rename.js b/lib/node/rename.js deleted file mode 100644 index c87bcfb3..00000000 --- a/lib/node/rename.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'RENAME' -}); diff --git a/lib/node/rename.ts b/lib/node/rename.ts new file mode 100644 index 00000000..0ed6f43c --- /dev/null +++ b/lib/node/rename.ts @@ -0,0 +1,7 @@ +import { Node } from './node.js'; + +export class RenameNode extends Node { + constructor() { + super('RENAME'); + } +} diff --git a/lib/node/renameColumn.js b/lib/node/renameColumn.js deleted file mode 100644 index c3c66865..00000000 --- a/lib/node/renameColumn.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'RENAME COLUMN' -}); diff --git a/lib/node/renameColumn.ts b/lib/node/renameColumn.ts new file mode 100644 index 00000000..0040e8c1 --- /dev/null +++ b/lib/node/renameColumn.ts @@ -0,0 +1,7 @@ +import { Node } from './node.js'; + +export class RenameColumnNode extends Node { + constructor() { + super('RENAME COLUMN'); + } +} diff --git a/lib/node/replace.js b/lib/node/replace.js deleted file mode 100644 index d17099d2..00000000 --- a/lib/node/replace.js +++ /dev/null @@ -1,70 +0,0 @@ -'use strict'; - -var DefaultNode = require('./default'); -var Node = require('./'); -var ParameterNode = require('./parameter'); - -var Replace = Node.define({ - type: 'REPLACE', - constructor: function () { - Node.call(this); - this.names = []; - this.columns = []; - this.valueSets = []; - } -}); - -module.exports = Replace; - -Replace.prototype.add = function (nodes) { - var hasColumns = false; - var hasValues = false; - var self = this; - var values = {}; - nodes.forEach(function (node) { - var column = node.toNode(); - var name = column.name; - var idx = self.names.indexOf(name); - if (idx < 0) { - self.names.push(name); - self.columns.push(column); - } - hasColumns = true; - hasValues = hasValues || column.value !== undefined; - values[name] = column; - }); - - // When none of the columns have a value, it's ambiguous whether the user - // intends to replace a row of default values or append a SELECT statement - // later. Resolve the ambiguity by assuming that if no columns are specified - // it is a row of default values, otherwise a SELECT will be added. - if (hasValues || !hasColumns) { - this.valueSets.push(values); - } - - return self; -}; - -/* - * Get parameters for all values to be replaced. This function - * handles handles bulk replaces, where keys may be present - * in some objects and not others. When keys are not present, - * the replace should refer to the column value as DEFAULT. - */ -Replace.prototype.getParameters = function () { - var self = this; - return this.valueSets - .map(function (nodeDict) { - var set = []; - self.names.forEach(function (name) { - var node = nodeDict[name]; - if (node) { - set.push(ParameterNode.getNodeOrParameterNode(node.value)); - } - else { - set.push(new DefaultNode()); - } - }); - return set; - }); -}; diff --git a/lib/node/replace.ts b/lib/node/replace.ts new file mode 100644 index 00000000..a740bfd9 --- /dev/null +++ b/lib/node/replace.ts @@ -0,0 +1,70 @@ +import { Column } from '../column.js'; +import { INodeable } from '../nodeable.js'; +import { ColumnNode } from './column.js'; +import { DefaultNode } from './default.js'; +import { Node } from './node.js'; +import { ParameterNode } from './parameter.js'; + +export class ReplaceNode extends Node { + public columns: ColumnNode[]; + public names: string[]; + public valueSets: { [key: string]: ColumnNode }[]; + constructor() { + super('REPLACE'); + this.names = []; + this.columns = []; + this.valueSets = []; + } + + public add(nodes: Column[] | Node | INodeable | string): this { + if (!Array.isArray(nodes)) { + throw new Error('Not an array of column instances'); + } + let hasColumns = false; + let hasValues = false; + const values: { [key: string]: ColumnNode } = {}; + nodes.forEach((node) => { + const column = node.toNode() as ColumnNode; + const name = column.name; + const idx = this.names.indexOf(name); + if (idx < 0) { + this.names.push(name); + this.columns.push(column); + } + hasColumns = true; + hasValues = hasValues || column.value !== undefined; + values[name] = column; + }); + + // When none of the columns have a value, it's ambiguous whether the user + // intends to replace a row of default values or append a SELECT statement + // later. Resolve the ambiguity by assuming that if no columns are specified + // it is a row of default values, otherwise a SELECT will be added. + if (hasValues || !hasColumns) { + this.valueSets.push(values); + } + + return this; + } + + /* + * Get parameters for all values to be replaced. This function + * handles handles bulk replaces, where keys may be present + * in some objects and not others. When keys are not present, + * the replace should refer to the column value as DEFAULT. + */ + public getParameters() { + return this.valueSets.map((nodeDict) => { + const set: Node[] = []; + this.names.forEach((name) => { + const node = nodeDict[name]; + if (node) { + set.push(ParameterNode.getNodeOrParameterNode(node.value)); + } else { + set.push(new DefaultNode()); + } + }); + return set; + }); + } +} diff --git a/lib/node/restrict.js b/lib/node/restrict.js deleted file mode 100644 index 942f4112..00000000 --- a/lib/node/restrict.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'RESTRICT' -}); diff --git a/lib/node/restrict.ts b/lib/node/restrict.ts new file mode 100644 index 00000000..5ac7bc52 --- /dev/null +++ b/lib/node/restrict.ts @@ -0,0 +1,7 @@ +import { Node } from './node.js'; + +export class RestrictNode extends Node { + constructor() { + super('RESTRICT'); + } +} diff --git a/lib/node/returning.js b/lib/node/returning.js deleted file mode 100644 index 2f27d067..00000000 --- a/lib/node/returning.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'RETURNING' -}); diff --git a/lib/node/returning.ts b/lib/node/returning.ts new file mode 100644 index 00000000..9d61edf7 --- /dev/null +++ b/lib/node/returning.ts @@ -0,0 +1,7 @@ +import { Node } from './node.js'; + +export class ReturningNode extends Node { + constructor() { + super('RETURNING'); + } +} diff --git a/lib/node/rowCall.ts b/lib/node/rowCall.ts new file mode 100644 index 00000000..f955abfe --- /dev/null +++ b/lib/node/rowCall.ts @@ -0,0 +1,14 @@ +import flatten from 'lodash/flatten.js'; +import { AliasMixin } from './alias.js'; +import { ParameterNode } from './parameter.js'; +import { ValueExpressionNode } from './_internal.js'; + +export class RowCallNode extends ValueExpressionNode { + constructor(args: any[]) { + super('ROW CALL'); + args = flatten(args); + this.addAll(args.map(ParameterNode.getNodeOrParameterNode)); + } + + public as = AliasMixin.as; +} diff --git a/lib/node/select.js b/lib/node/select.js deleted file mode 100644 index 93e22538..00000000 --- a/lib/node/select.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'SELECT', - constructor: function(arg) { - Node.call(this); - if (arg && arg.sql) { - this.sql = arg.sql; - } - // used when processing LIMIT clauses in MSSQL - this.msSQLLimitNode = undefined; - // set to true when a DISTINCT is used on the entire result set - this.isDistinct = false; - } -}); diff --git a/lib/node/select.ts b/lib/node/select.ts new file mode 100644 index 00000000..f78b3ad7 --- /dev/null +++ b/lib/node/select.ts @@ -0,0 +1,14 @@ +import { ModifierNode } from './modifier.js'; +import { Node } from './node.js'; + +export class SelectNode extends Node { + public msSQLLimitNode?: ModifierNode; + public isDistinct: boolean; + constructor() { + super('SELECT'); + // used when processing LIMIT clauses in MSSQL + this.msSQLLimitNode = undefined; + // set to true when a DISTINCT is used on the entire result set + this.isDistinct = false; + } +} diff --git a/lib/node/slice.js b/lib/node/slice.js deleted file mode 100644 index 86c1ce21..00000000 --- a/lib/node/slice.js +++ /dev/null @@ -1,28 +0,0 @@ -'use strict'; - -var _ = require('lodash'); -var Node = require('./index'); -var valueExpressionMixin = require('./valueExpression'); - -var valueExpressionMixed = false; -var SliceNode = Node.define({ - type: 'SLICE', - constructor: function(value, start, end) { - Node.call(this); - this.value = value; - this.start = start; - this.end = end; - // Delay mixin to runtime, when all nodes have been defined, and - // mixin only once. ValueExpressionMixin has circular dependencies. - if (!valueExpressionMixed) { - valueExpressionMixed = true; - _.extend(SliceNode.prototype, valueExpressionMixin()); - } - } -}); - -// allow aliasing -var AliasNode = require('./alias'); -_.extend(SliceNode.prototype, AliasNode.AliasMixin); - -module.exports = SliceNode; diff --git a/lib/node/slice.ts b/lib/node/slice.ts new file mode 100644 index 00000000..ec5d0bb3 --- /dev/null +++ b/lib/node/slice.ts @@ -0,0 +1,19 @@ +import { AliasMixin } from './alias.js'; +import { Node } from './node.js'; +import { classMap, ValueExpressionNode } from './_internal.js'; + +export class SliceNode extends ValueExpressionNode { + public value: Node; + public start: Node; + public end: Node; + constructor(value: Node, start: Node, end: Node) { + super('SLICE'); + this.value = value; + this.start = start; + this.end = end; + } + + public as = AliasMixin.as; +} + +classMap.set('SLICE', SliceNode); diff --git a/lib/node/table.js b/lib/node/table.js deleted file mode 100644 index 4fca70d1..00000000 --- a/lib/node/table.js +++ /dev/null @@ -1,10 +0,0 @@ -'use strict'; - -var Node = require('./index'); -module.exports = Node.define({ - type: 'TABLE', - constructor: function(table) { - Node.call(this); - this.table = table; - } -}); diff --git a/lib/node/table.ts b/lib/node/table.ts new file mode 100644 index 00000000..915814df --- /dev/null +++ b/lib/node/table.ts @@ -0,0 +1,10 @@ +import { Table } from '../table.js'; +import { Node } from './node.js'; + +export class TableNode extends Node { + public table: Table; + constructor(table: Table) { + super('TABLE'); + this.table = table; + } +} diff --git a/lib/node/ternary.js b/lib/node/ternary.js deleted file mode 100644 index 3f688ba9..00000000 --- a/lib/node/ternary.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; - -var _ = require('lodash'); -var Node = require('./index'); -var valueExpressionMixin = require('./valueExpression'); - -var valueExpressionMixed = false; -var TernaryNode = Node.define(_.extend({ - type: 'TERNARY', - constructor: function(config) { - Node.call(this); - this.left = config.left; - this.middle = config.middle; - this.operator = config.operator; - this.right = config.right; - this.separator = config.separator; - - // Delay mixin to runtime, when all nodes have been defined, and - // mixin only once. ValueExpressionMixin has circular dependencies. - if (!valueExpressionMixed) { - valueExpressionMixed = true; - _.extend(TernaryNode.prototype, valueExpressionMixin()); - } - }, -})); - -// allow aliasing -var AliasNode = require('./alias'); -_.extend(TernaryNode.prototype, AliasNode.AliasMixin); - -module.exports = TernaryNode; diff --git a/lib/node/ternary.ts b/lib/node/ternary.ts new file mode 100644 index 00000000..a276085d --- /dev/null +++ b/lib/node/ternary.ts @@ -0,0 +1,23 @@ +import { AliasMixin } from './alias.js'; +import { Node } from './node.js'; +import { classMap, ValueExpressionNode } from './_internal.js'; + +export class TernaryNode extends ValueExpressionNode { + public left: Node; + public middle: Node; + public operator: string; + public right: Node; + public separator: string; + constructor(config: { left: Node; middle: Node; operator: string; right: Node; separator: string }) { + super('TERNARY'); + this.left = config.left; + this.middle = config.middle; + this.operator = config.operator; + this.right = config.right; + this.separator = config.separator; + } + + public as = AliasMixin.as; +} + +classMap.set('TERNARY', TernaryNode); diff --git a/lib/node/text.js b/lib/node/text.js deleted file mode 100644 index bf026151..00000000 --- a/lib/node/text.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'TEXT', - constructor: function(text) { - Node.call(this); - this.text = text; - } -}); diff --git a/lib/node/text.ts b/lib/node/text.ts new file mode 100644 index 00000000..37951998 --- /dev/null +++ b/lib/node/text.ts @@ -0,0 +1,9 @@ +import { Node } from './node.js'; + +export class TextNode extends Node { + public text: string; + constructor(text: string) { + super('TEXT'); + this.text = text; + } +} \ No newline at end of file diff --git a/lib/node/truncate.js b/lib/node/truncate.js deleted file mode 100644 index 165e0d9e..00000000 --- a/lib/node/truncate.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'TRUNCATE', - - constructor: function(table) { - Node.call(this); - this.add(table); - } -}); diff --git a/lib/node/truncate.ts b/lib/node/truncate.ts new file mode 100644 index 00000000..7ae5ba5e --- /dev/null +++ b/lib/node/truncate.ts @@ -0,0 +1,9 @@ +import { Table } from '../table.js'; +import { Node } from './node.js'; + +export class TruncateNode extends Node { + constructor(table: Table) { + super('TRUNCATE'); + this.add(table); + } +} diff --git a/lib/node/update.js b/lib/node/update.js deleted file mode 100644 index 890fbee9..00000000 --- a/lib/node/update.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var Node = require('./index'); - -module.exports = Node.define({ - type: 'UPDATE' -}); diff --git a/lib/node/update.ts b/lib/node/update.ts new file mode 100644 index 00000000..5b75b48f --- /dev/null +++ b/lib/node/update.ts @@ -0,0 +1,7 @@ +import { Node } from './node.js'; + +export class UpdateNode extends Node { + constructor() { + super('UPDATE'); + } +} diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js deleted file mode 100644 index 2fa741a9..00000000 --- a/lib/node/valueExpression.js +++ /dev/null @@ -1,160 +0,0 @@ -'use strict'; - -var OrderByValueNode = require('./orderByValue'); -var ParameterNode = require('./parameter'); -var TextNode = require('./text'); - -// Process values, wrapping them in ParameterNode if necessary. -var processParams = function(val) { - return Array.isArray(val) ? val.map(ParameterNode.getNodeOrParameterNode) : ParameterNode.getNodeOrParameterNode(val); -}; - -// Value expressions can be composed to form new value expressions. -// ValueExpressionMixin is evaluated at runtime, hence the -// "thunk" around it. -var ValueExpressionMixin = function() { - var BinaryNode = require('./binary'); - var InNode = require('./in'); - var NotInNode = require('./notIn'); - var CastNode = require('./cast'); - var PostfixUnaryNode = require('./postfixUnary'); - var TernaryNode = require('./ternary'); - var CaseNode = require('./case'); - var AtNode = require('./at'); - var SliceNode = require('./slice'); - - var postfixUnaryMethod = function(operator) { - /*jshint unused: false */ - return function(val) { - return new PostfixUnaryNode({ - left : this.toNode(), - operator : operator - }); - }; - }; - - var binaryMethod = function(operator) { - return function(val) { - return new BinaryNode({ - left : this.toNode(), - operator : operator, - right : processParams(val) - }); - }; - }; - - var inMethod = function(val) { - return new InNode({ - left : this.toNode(), - right : processParams(val) - }); - }; - - var notInMethod = function(val) { - return new NotInNode({ - left : this.toNode(), - right : processParams(val) - }); - }; - - var ternaryMethod = function(operator, separator) { - return function(middle, right) { - return new TernaryNode({ - left : this.toNode(), - operator : operator, - middle : processParams(middle), - separator : separator, - right : processParams(right) - }); - }; - }; - - var atMethod = function(index) { - return new AtNode(this.toNode(), processParams(index)); - }; - - var sliceMethod = function(start, end) { - return new SliceNode(this.toNode(), processParams(start), processParams(end)); - }; - - var castMethod = function(dataType) { - return new CastNode(this.toNode(), dataType); - }; - - var orderMethod = function(direction) { - return function() { - return new OrderByValueNode({ - value : this.toNode(), - direction : direction ? new TextNode(direction) : undefined - }); - }; - }; - - var caseMethod = function(whenList, thenList, elseBranch) { - if (undefined !== elseBranch) { - elseBranch = processParams(elseBranch); - } - return new CaseNode({ - whenList : processParams(whenList), - thenList : processParams(thenList), - else : elseBranch - }); - }; - - return { - isNull : postfixUnaryMethod('IS NULL'), - isNotNull : postfixUnaryMethod('IS NOT NULL'), - or : binaryMethod('OR'), - and : binaryMethod('AND'), - equals : binaryMethod('='), - equal : binaryMethod('='), - notEquals : binaryMethod('<>'), - notEqual : binaryMethod('<>'), - gt : binaryMethod('>'), - gte : binaryMethod('>='), - lt : binaryMethod('<'), - lte : binaryMethod('<='), - plus : binaryMethod('+'), - minus : binaryMethod('-'), - multiply : binaryMethod('*'), - divide : binaryMethod('/'), - modulo : binaryMethod('%'), - leftShift : binaryMethod('<<'), - rightShift : binaryMethod('>>'), - bitwiseAnd : binaryMethod('&'), - bitwiseNot : binaryMethod('~'), - bitwiseOr : binaryMethod('|'), - bitwiseXor : binaryMethod('#'), - regex : binaryMethod('~'), - iregex : binaryMethod('~*'), - regexp : binaryMethod('REGEXP'), - notRegex : binaryMethod('!~'), - notIregex : binaryMethod('!~*'), - concat : binaryMethod('||'), - key : binaryMethod('->'), - keyText : binaryMethod('->>'), - path : binaryMethod('#>'), - pathText : binaryMethod('#>>'), - like : binaryMethod('LIKE'), - rlike : binaryMethod('RLIKE'), - notLike : binaryMethod('NOT LIKE'), - ilike : binaryMethod('ILIKE'), - notIlike : binaryMethod('NOT ILIKE'), - match : binaryMethod('@@'), - in : inMethod, - notIn : notInMethod, - between : ternaryMethod('BETWEEN', 'AND'), - notBetween : ternaryMethod('NOT BETWEEN', 'AND'), - at : atMethod, - contains : binaryMethod('@>'), - containedBy : binaryMethod('<@'), - containsKey : binaryMethod('?'), - overlap : binaryMethod('&&'), - slice : sliceMethod, - cast : castMethod, - descending : orderMethod('DESC'), - case : caseMethod - }; -}; - -module.exports = ValueExpressionMixin; diff --git a/lib/node/valueExpression.ts b/lib/node/valueExpression.ts new file mode 100644 index 00000000..dab8fb75 --- /dev/null +++ b/lib/node/valueExpression.ts @@ -0,0 +1,224 @@ +/* eslint-disable max-classes-per-file */ +import { INodeable } from '../nodeable.js'; +import type { + AtNode, + BinaryNode, + CaseNode, + CastNode, + InNode, + NotInNode, + OrderByValueNode, + PostfixUnaryNode, + PrefixUnaryNode, + SliceNode, + TernaryNode +} from './_internal.js'; +import { Node } from './node.js'; +import { ParameterNode } from './parameter.js'; +import { TextNode } from './text.js'; + +export const classMap = new Map any>(); + +// Process values, wrapping them in ParameterNode if necessary. +const processParam = (val: unknown): Node => { + if (Array.isArray(val)) { + throw new Error('expected single value'); + } + return ParameterNode.getNodeOrParameterNode(val); +}; +const processParams = (val: any): Node[] => { + if (!Array.isArray(val)) { + throw new Error('expected array value'); + } + return val.map(ParameterNode.getNodeOrParameterNode); +}; +const processParamOrParams = (val: any): Node | Node[] => { + return Array.isArray(val) ? val.map(ParameterNode.getNodeOrParameterNode) : ParameterNode.getNodeOrParameterNode(val); +}; + +// Builder functions + +const postfixUnaryMethod = (operator: string) => { + return function(this: INodeable): PostfixUnaryNode { + const ctor = classMap.get('POSTFIX UNARY')!; + return new ctor({ + left: this.toNode(), + operator + }); + }; +}; + +const binaryMethod = (operator: string) => { + return function(this: INodeable, val: any): BinaryNode { + const ctor = classMap.get('BINARY')!; + return new ctor({ + left: this.toNode(), + operator, + right: processParamOrParams(val) + }); + }; +}; + +const ternaryMethod = (operator: string, separator: string) => { + return function(this: INodeable, middle: any, right: any): TernaryNode { + const ctor = classMap.get('TERNARY')!; + return new ctor({ + left: this.toNode(), + operator, + middle: processParam(middle), + separator, + right: processParam(right) + }); + }; +}; + +const orderMethod = (direction: string) => { + return function(this: INodeable): OrderByValueNode { + const ctor = classMap.get('ORDER BY VALUE')!; + return new ctor({ + value: this.toNode(), + direction: direction ? new TextNode(direction) : undefined + }); + }; +}; + +// eslint-disable-next-line prefer-arrow/prefer-arrow-functions +export function ValueExpressionBaseMixin INodeable>(Base: TBase) { + abstract class ValueExpressionBaseClass extends Base { + + public in(val: any) : InNode { + const ctor = classMap.get('IN')!; + return new ctor({ + left: this.toNode(), + right: processParamOrParams(val) + }); + } + + public notIn(val: any): NotInNode { + const ctor = classMap.get('NOT IN')!; + return new ctor({ + left: this.toNode(), + right: processParamOrParams(val) + }); + } + + public at(index: any): AtNode { + const ctor = classMap.get('AT')!; + return new ctor(this.toNode(), processParam(index)); + } + + public slice(start: number, end: number): SliceNode { + const ctor = classMap.get('SLICE')!; + return new ctor(this.toNode(), processParam(start), processParam(end)); + } + + public cast(dataType: string): CastNode { + const ctor = classMap.get('CAST')!; + return new ctor(this.toNode(), dataType); + } + + public case(whenList: any[], thenList: any[], elseBranch?: any): CaseNode { + const ctor = classMap.get('CASE')!; + if (undefined !== elseBranch) { + elseBranch = processParam(elseBranch); + } + return new ctor({ + whenList: processParams(whenList), + thenList: processParams(thenList), + else: elseBranch + }); + } + + public prefixUnaryOperator(operator: string): PrefixUnaryNode { + const ctor = classMap.get('PREFIX UNARY')!; + return new ctor({ + left: this.toNode(), + operator + }); + }; + + public postfixUnaryOperator(operator: string): PostfixUnaryNode { + const ctor = classMap.get('POSTFIX UNARY')!; + return new ctor({ + left: this.toNode(), + operator + }); + }; + + public binaryOperator(operator: string, right: any): BinaryNode { + const ctor = classMap.get('BINARY')!; + return new ctor({ + left: this.toNode(), + operator, + right: processParamOrParams(right) + }); + }; + + public ternaryOperator(operator: string, middle: any, separator: string, right: any): TernaryNode { + const ctor = classMap.get('TERNARY')!; + return new ctor({ + left: this.toNode(), + operator, + middle: processParam(middle), + separator, + right: processParam(right) + }); + }; + + public isNull = postfixUnaryMethod('IS NULL'); + public isNotNull = postfixUnaryMethod('IS NOT NULL'); + public equals = binaryMethod('='); + public notEquals = binaryMethod('<>'); + public gt = binaryMethod('>'); + public gte = binaryMethod('>='); + public lt = binaryMethod('<'); + public lte = binaryMethod('<='); + public plus = binaryMethod('+'); + public minus = binaryMethod('-'); + public multiply = binaryMethod('*'); + public divide = binaryMethod('/'); + public modulo = binaryMethod('%'); + public leftShift = binaryMethod('<<'); + public rightShift = binaryMethod('>>'); + public bitwiseAnd = binaryMethod('&'); + public bitwiseNot = binaryMethod('~'); + public bitwiseOr = binaryMethod('|'); + public bitwiseXor = binaryMethod('#'); + public regex = binaryMethod('~'); + public iregex = binaryMethod('~*'); + public regexp = binaryMethod('REGEXP'); + public notRegex = binaryMethod('!~'); + public notIregex = binaryMethod('!~*'); + public concat = binaryMethod('||'); + public key = binaryMethod('->'); + public keyText = binaryMethod('->>'); + public path = binaryMethod('#>'); + public pathText = binaryMethod('#>>'); + public like = binaryMethod('LIKE'); + public rlike = binaryMethod('RLIKE'); + public notLike = binaryMethod('NOT LIKE'); + public ilike = binaryMethod('ILIKE'); + public notIlike = binaryMethod('NOT ILIKE'); + public match = binaryMethod('@@'); + public between = ternaryMethod('BETWEEN', 'AND'); + public notBetween = ternaryMethod('NOT BETWEEN', 'AND'); + public contains = binaryMethod('@>'); + public containedBy = binaryMethod('<@'); + public containsKey = binaryMethod('?'); + public overlap = binaryMethod('&&'); + public descending = orderMethod('DESC'); + } + return ValueExpressionBaseClass; +} + +// eslint-disable-next-line prefer-arrow/prefer-arrow-functions +export function ValueExpressionMixin INodeable>(Base: TBase) { + abstract class ValueExpressionClass extends ValueExpressionBaseMixin(Base) { + public or = binaryMethod('OR'); + public and = binaryMethod('AND'); + } + return ValueExpressionClass; +} + +export const ValueExpressionBaseNode = ValueExpressionBaseMixin(Node); +export const ValueExpressionNode = ValueExpressionMixin(Node); diff --git a/lib/node/where.js b/lib/node/where.js deleted file mode 100644 index 5c0465fc..00000000 --- a/lib/node/where.js +++ /dev/null @@ -1,74 +0,0 @@ -'use strict'; - -var Node = require('./index'); -var BinaryNode = require('./binary'); -var TextNode = require('./text'); - -var normalizeNode = function(table, node) { - var result = node; - if(typeof node === 'string') { - result = new TextNode('(' + node + ')'); - } - else if (Array.isArray(node)) { - result = false; - - if (node.length === 0) { - result = new TextNode('(1 = 1)'); - } else { - node.forEach(function (subNode) { - if (!result) { - result = subNode; - } else { - result = result.and(subNode); - } - }); - } - } - else if (!node.toNode && typeof node === 'object'){ - result = false; - for (var colName in node) { - if (node.hasOwnProperty(colName)) { - var column = table.getColumn(colName); - var query = column.equals(node[colName]); - if (!result) { - result = query; - } else { - result = result.and(query); - } - } - } - } - return result; -}; - -module.exports = Node.define({ - constructor: function(table) { - Node.call(this); - this.table = table; - }, - type: 'WHERE', - add: function(node) { - node = normalizeNode(this.table, node); - return Node.prototype.add.call(this, node); - }, - or: function(other) { - var right = normalizeNode(this.table, other); - // calling 'or' without an initial 'where' - if(!this.nodes.length) { - return this.add(other); - } - return this.nodes.push(new BinaryNode({ - left: this.nodes.pop(), - operator: 'OR', - right: right - })); - }, - and: function(other) { - var right = normalizeNode(this.table, other); - return this.nodes.push(new BinaryNode({ - left: this.nodes.pop(), - operator: 'AND', - right: right - })); - } -}); diff --git a/lib/node/where.ts b/lib/node/where.ts new file mode 100644 index 00000000..2db17e45 --- /dev/null +++ b/lib/node/where.ts @@ -0,0 +1,73 @@ +import { INodeable, instanceofINodeable } from '../nodeable.js'; +import { Table } from '../table.js'; +import { BinaryNode } from './binary.js'; +import { Node } from './node.js'; +import { TextNode } from './text.js'; + +const normalizeNode = (table: Table, node: Node[] | Node | INodeable | Record | string): Node => { + if (typeof node === 'string') { + return new TextNode(`(${node})`); + } else if (Array.isArray(node)) { + if (node.length === 0) { + return new TextNode('(1 = 1)'); + } else { + let result: Node | undefined; + for (const subNode of node) { + result = !result ? subNode : (result as any).and(subNode); + } + return result!; + } + } else if (!instanceofINodeable(node) && typeof node === 'object') { + let result: Node | undefined; + for (const colName in node) { + if (colName in node) { + const column = table.getColumn(colName)!; + const query = column.equals((node as any)[colName]); + result = !result ? query : (result as any).and(query); + } + } + return result!; + } else { + return node.toNode(); + } +}; + +export class WhereNode extends Node { + public table: Table; + constructor(table: Table) { + super('WHERE'); + this.table = table; + } + + public add(node: Node[] | Node | INodeable | Record | string) { + const add = normalizeNode(this.table, node); + return super.add(add); + } + + public or(other: Node | Record | string): void { + const right = normalizeNode(this.table, other); + // calling 'or' without an initial 'where' + if (!this.nodes.length) { + this.add(other); + } else { + this.nodes.push( + new BinaryNode({ + left: this.nodes.pop()!, + operator: 'OR', + right + }) + ); + } + } + + public and(other: Node[] | Node | Record | string): void { + const right = normalizeNode(this.table, other); + this.nodes.push( + new BinaryNode({ + left: this.nodes.pop()!, + operator: 'AND', + right + }) + ); + } +} diff --git a/lib/nodeable.ts b/lib/nodeable.ts new file mode 100644 index 00000000..28cc5402 --- /dev/null +++ b/lib/nodeable.ts @@ -0,0 +1,12 @@ +import type { Node } from './node/node.js'; + +export interface INodeable { + toNode(): Node; +} + +// eslint-disable-next-line prefer-arrow/prefer-arrow-functions +export function instanceofINodeable(o: unknown): o is INodeable { + return typeof o === 'object' && o !== null && 'toNode' in o; +} + +export type PartialNodeable = { [P in keyof T]?: T[P] | INodeable | Buffer | null }; diff --git a/lib/sql.ts b/lib/sql.ts new file mode 100644 index 00000000..a20c8797 --- /dev/null +++ b/lib/sql.ts @@ -0,0 +1,102 @@ +import defaults from 'lodash/defaults.js'; +import sliced from 'sliced'; +import { Column } from './column.js'; +import { ColumnDefinition, SQLDialects, TableDefinition } from './configTypes.js'; +import { DEFAULT_DIALECT, getDialect } from './dialect/mapper.js'; +import * as functions from './functions.js'; +import { ArrayCallNode } from './node/arrayCall.js'; +import { FunctionCallNode } from './node/functionCall.js'; +import { IntervalNode } from './node/interval.js'; +import { LiteralNode } from './node/literal.js'; +import { ParameterNode } from './node/parameter.js'; +import { Query } from './node/query.js'; +import { RowCallNode } from './node/rowCall.js'; +import { Table, TableWithColumns } from './table.js'; +import { + binaryOperator, + postfixUnaryOperator, + prefixUnaryOperator, + ternaryOperator +} from './node/operator.js'; + +export class Sql { + public functions: functions.StandardFunctions; + public dialect: any; + public dialectName!: SQLDialects; + public config: any; + private _function: any; + constructor(dialect: SQLDialects = DEFAULT_DIALECT, config: any = {}) { + this.setDialect(dialect, config); + // attach the standard SQL functions to this instance + this.functions = functions.getStandardFunctions(); + this._function = functions.getFunctions; + } + // Define a function + public function(functionNames: string[]): { [key: string]: (...args: any[]) => FunctionCallNode }; + public function(functionName: string): (...args: any[]) => FunctionCallNode; + public function(...args: any[]): any { + return this._function(...args); + } + // Define an operator + public prefixUnaryOperator = prefixUnaryOperator; + public postfixUnaryOperator = postfixUnaryOperator; + public binaryOperator = binaryOperator; + public ternaryOperator = ternaryOperator; + // Define a table + public define(def: TableDefinition): TableWithColumns { + def = defaults(def || {}, { + sql: this + }); + return Table.define(def); + } + public defineColumn(def: ColumnDefinition): Column { + return new Column(def); + } + // Returns a bracketed call creator literal + public array(...args: any[]) { + const arrayCall = new ArrayCallNode(sliced(args)); + return arrayCall; + } + // Returns a bracketed call creator literal + public row(...args: any[]) { + const rowCall = new RowCallNode(sliced(args)); + return rowCall; + } + // Returns a select statement + public select(...args: any[]) { + const query = new Query({ sql: this } as any); + query.select(...args); + return query; + } + // Returns an interval clause + public interval(...args: any[]) { + const interval = new IntervalNode(sliced(args)); + return interval; + } + // Set the dialect + public setDialect(dialect: SQLDialects, config: any = {}) { + this.dialect = getDialect(dialect); + this.dialectName = dialect; + this.config = config; + return this; + } + // Create a constant Column (for use in SELECT) + public constant(value: any) { + const config = { + constantValue: value, + isConstant: true, + name: 'constant', + property: 'constant' + }; + const cn = new Column(config); + return cn; + } + // Create a literal + public literal(literal: any): LiteralNode { + return new LiteralNode(literal); + } + // Create a parameter + public parameter(value: any): ParameterNode { + return new ParameterNode(value); + } +} diff --git a/lib/table.js b/lib/table.js deleted file mode 100644 index 3fae2710..00000000 --- a/lib/table.js +++ /dev/null @@ -1,290 +0,0 @@ -'use strict'; - -var util = require('util'); -var lodash = require('lodash'); - -var Query = require('./node/query'); -var Column = require('./column'); -var TableNode = require('./node/table'); -var JoinNode = require('./node/join'); -var LiteralNode = require('./node/literal'); -var Joiner = require('./joiner'); -var ForeignKeyNode = require('./node/foreignKey'); - -var Table = function(config) { - this._schema = config.schema; - this._name = config.name; - this._initialConfig = config; - this.columnWhiteList = !!config.columnWhiteList; - this.isTemporary=!!config.isTemporary; - this.snakeToCamel = !!config.snakeToCamel; - this.columns = []; - this.foreignKeys = []; - this.table = this; - if (!config.sql) { - config.sql = require('./index'); - } - this.sql = config.sql; -}; - -Table.define = function(config) { - var table = new Table(config); - // allow hash of columns as well as array - if (config.columns && !util.isArray(config.columns)) { - var cols = []; - - for (var key in config.columns) { - if (config.columns.hasOwnProperty(key)) { - var col = config.columns[key]; - col.name = key; - cols.push(col); - } - } - - config.columns = cols; - } - - for (var i = 0; i < config.columns.length; i++) { - table.addColumn(config.columns[i]); - } - - if(config.foreignKeys !== undefined) { - if(util.isArray(config.foreignKeys)) { - for(i = 0; i < config.foreignKeys.length; i++) { - table.foreignKeys.push(new ForeignKeyNode(config.foreignKeys[i])); - } - } else { - table.foreignKeys.push(new ForeignKeyNode(config.foreignKeys)); - } - } - return table; -}; - -Table.prototype.clone = function(config) { - return Table.define(lodash.extend({ - schema: this._schema, - name: this._name, - sql: this.sql, - columnWhiteList: !!this.columnWhiteList, - snakeToCamel: !!this.snakeToCamel, - columns: this.columns, - foreignKeys: this.foreignKeys - }, config || {})); -}; - -Table.prototype.createColumn = function(col) { - if(!(col instanceof Column)) { - if(typeof col === 'string') { - col = { name: col }; - } - - col.table = this; - col = new Column(col); - - // Load subfields from array into an object of form name: Column - if(util.isArray(col.subfields)) { - col.subfields = lodash.chain(col.subfields) - .map(lodash.bind(function (subfield) { - return [subfield, new Column({ - table: this, - subfieldContainer: col, - name: subfield - })]; - }, this)) - .fromPairs() - .value(); - } - } - - return col; -}; - -Table.prototype.addColumn = function(col, options) { - col = this.createColumn(col); - options = lodash.extend({ - noisy: true - }, options || {}); - - if(this.hasColumn(col)) { - if (options.noisy) { - throw new Error('Table ' + this._name + ' already has column or property by the name of ' + col.name); - } else { - return this; - } - } else if(!!this[col.name] && (process.env.NODE_ENV === 'debug')) { - console.log('Please notice that you have just defined the column "' + col.name + '". In order to access it, you need to use "table.getColumn(\'' + col.name + '\');"!'); - } - this.columns.push(col); - - function snakeToCamel(snakeName) { - return snakeName.replace(/[\-_]([a-z])/g, function(m, $1){ return $1.toUpperCase(); }); - } - - var property = col.property = col.property || (this.snakeToCamel ? snakeToCamel(col.name) : col.name); - this[property] = this[property] || col; - return this; -}; - -Table.prototype.hasColumn = function(col) { - var columnName = col instanceof Column ? col.name : col; - return this.columns.some(function(column) { - return column.property === columnName || column.name === columnName; - }); -}; - -Table.prototype.getColumn = -Table.prototype.get = -function(colName) { - for(var i = 0; i < this.columns.length; i++) { - var col = this.columns[i]; - if (colName === col.property || colName === col.name) { - return col; - } - } - if(this.columnWhiteList) - return null; - throw new Error('Table ' + this._name + ' does not have a column or property named ' + colName); -}; - -Table.prototype.getSchema = function() { - return this._schema; -}; - -Table.prototype.setSchema = function(schema) { - this._schema = schema; -}; - -Table.prototype.getName = function() { - if (this.sql && this.sql.dialectName=="mssql" && this.isTemporary) return "#"+this._name; - return this._name; -}; - -Table.prototype.star = function(options) { - options = options || {}; - if (options.prefix) { - return this.columns.map(function(column) { - return this[column.name].as(options.prefix + column.name); - }.bind(this)); - } - - return new Column({table: this, star: true}); -}; - -Table.prototype.literal = function(literal) { - return new LiteralNode(literal); -}; - -Table.prototype.count = function(alias) { - var name = this.alias || this._name, - col = new Column({table: this, star: true}); - // ColumnNode - return col.count(alias || name + '_count'); -}; - -Table.prototype.select = function() { - // create the query and pass it off - var query = new Query(this); - if (arguments.length === 0) { - query.select.call(query, this.star()); - } else { - query.select.apply(query, arguments); - } - return query; -}; - -Table.prototype.subQuery = function(alias) { - // create the query and pass it off - var query = new Query(this); - query.type = 'SUBQUERY'; - query.alias = alias; - query.join = function(other) { - return new JoinNode('INNER', this.toNode(), other.toNode(), other); - }; - return query; -}; - -Table.prototype.insert = function() { - var query = new Query(this); - if(!arguments[0] || (util.isArray(arguments[0]) && arguments[0].length === 0)){ - query.select.call(query, this.star()); - query.where.apply(query,["1=2"]); - } else { - query.insert.apply(query, arguments); - } - return query; -}; - -Table.prototype.replace = function() { - var query = new Query(this); - if(!arguments[0] || (util.isArray(arguments[0]) && arguments[0].length === 0)){ - query.select.call(query, this.star()); - query.where.apply(query,["1=2"]); - } else { - query.replace.apply(query, arguments); - } - return query; -}; - -Table.prototype.toNode = function() { - return new TableNode(this); -}; - -Table.prototype.join = function(other) { - return new JoinNode('INNER', this.toNode(), other.toNode(), other); -}; - -Table.prototype.leftJoin = function(other) { - return new JoinNode('LEFT', this.toNode(), other.toNode()); -}; - -// auto-join tables based on column intropsection -Table.prototype.joinTo = function(other) { - return Joiner.leftJoin(this, other); -}; - -Table.prototype.as = function(alias) { - // TODO could this be cleaner? - var t = Table.define(this._initialConfig); - t.alias = alias; - return t; -}; - -// called in shorthand when not calling select -Table.prototype.__defineGetter__("nodes", function() { - return this.select(this.star()).nodes; -}); - -Table.prototype.and = function() { - var query = new Query(this); - query.where.apply(query, arguments); - return query; -}; - -Table.prototype.indexes = function() { - return new Query(this).indexes(); -}; - -var queryMethods = [ - 'alter', - 'create', - 'delete', - 'drop', - 'from', - 'limit', - 'offset', - 'or', - 'order', - 'truncate', - 'update', - 'where' -]; - -queryMethods.forEach(function (method) { - Table.prototype[method] = function () { - var query = new Query(this); - query[method].apply(query, arguments); - return query; - }; -}); - -module.exports = Table; diff --git a/lib/table.ts b/lib/table.ts new file mode 100644 index 00000000..b458b8eb --- /dev/null +++ b/lib/table.ts @@ -0,0 +1,348 @@ +import map from 'lodash/map.js'; +import fromPairs from 'lodash/fromPairs.js'; +import { Column } from './column.js'; +import { ColumnDefinition, TableDefinition } from './configTypes.js'; +import { leftJoin } from './joiner.js'; +import { ColumnNode } from './node/column.js'; +import { DropIndexNode } from './node/dropIndex.js'; +import { ForeignKeyNode } from './node/foreignKey.js'; +import { JoinNode } from './node/join.js'; +import { Node } from './node/node.js'; +import { OrderByValueNode } from './node/orderByValue.js'; +import { Query, SubQuery } from './node/query.js'; +import { TableNode } from './node/table.js'; +import { INodeable, PartialNodeable } from './nodeable.js'; +import { Sql } from './sql.js'; + +export type TableWithColumns = Table & { [Name in NonNullable]: Column }; + +export class Table implements INodeable { + get nodes(): Node[] { + return this.select(this.star()).nodes; + } + public static define(config: TableDefinition): TableWithColumns { + const table = new Table(config); + // allow hash of columns as well as array + if (config.columns && !Array.isArray(config.columns)) { + const cols = []; + + for (const key in config.columns) { + if (config.columns.hasOwnProperty(key)) { + const col = (config.columns as any)[key]; + col.name = key; + cols.push(col); + } + } + + config.columns = cols; + } + for (const col of config.columns) { + table.addColumn(col); + } + if (config.foreignKeys !== undefined) { + if (Array.isArray(config.foreignKeys)) { + for (const key of config.foreignKeys) { + table.foreignKeys.push(new ForeignKeyNode(key)); + } + } else { + table.foreignKeys.push(new ForeignKeyNode(config.foreignKeys)); + } + } + return table as TableWithColumns; + } + public columnWhiteList: boolean; + public isTemporary: boolean; + public snakeToCamel: boolean; + public columns: Column[]; + public foreignKeys: ForeignKeyNode[]; + public table: this; + public sql!: Sql; + public engine?: string; + public charset?: string; + public alias?: string; + public initialConfig: TableDefinition; + private schema?: string; + private tableName: string; + constructor(config: TableDefinition) { + this.schema = config.schema; + this.tableName = config.name; + this.initialConfig = config; + this.columnWhiteList = !!config.columnWhiteList; + this.isTemporary = !!config.isTemporary; + this.snakeToCamel = !!config.snakeToCamel; + this.columns = []; + this.foreignKeys = []; + this.table = this; + if (!config.sql) { + config.sql = new Sql(); + } + this.sql = config.sql; + this.engine = config.engine; + this.charset = config.charset; + } + public clone(config?: Partial): TableWithColumns { + return Table.define({ + columnWhiteList: !!this.columnWhiteList, + columns: this.columns, + foreignKeys: this.foreignKeys, + name: this.tableName, + schema: this.schema, + snakeToCamel: !!this.snakeToCamel, + sql: this.sql, + ...(config || {}) + } as any); + } + public createColumn(col: string | ColumnDefinition | Column): Column { + if (!(col instanceof Column)) { + if (typeof col === 'string') { + col = { name: col } as ColumnDefinition; + } + const column = new Column({ ...col, table: this }); + // Load subfields from array into an object of form name: Column + if (Array.isArray(col.subfields)) { + column.subfields = fromPairs(map(col.subfields, (subfield) => { + return [ + subfield, + new Column({ + name: subfield, + subfieldContainer: column, + table: this + }) + ]; + })); + } + return column; + } + return col; + } + public addColumn(col: string | ColumnDefinition | Column, options?: any) { + const column = this.createColumn(col); + options = { noisy: true, ...options }; + if (this.hasColumn(column)) { + if (options.noisy) { + throw new Error(`Table ${this.tableName} already has column or property by the name of ${column.name}`); + } else { + return this; + } + } else if (!!(this as any)[column.name] && process.env.NODE_ENV === 'debug') { + // eslint-disable-next-line no-console + console.log( + `Please notice that you have just defined the column "${ + column.name + }". In order to access it, you need to use "table.getColumn('${column.name}');"!` + ); + } + this.columns.push(column); + const snakeToCamel = (snakeName: string) => { + return snakeName.replace(/[\-_]([a-z])/g, (m, $1: string) => $1.toUpperCase()); + }; + const property = (column.property = column.property || (this.snakeToCamel ? snakeToCamel(column.name) : column.name)); + (this as any)[property] = (this as any)[property] || column; + return this; + } + public hasColumn(col: Column | string): boolean { + const columnName = col instanceof Column ? col.name : col; + return this.columns.some((column) => column.property === columnName || column.name === columnName); + } + public getColumn(colName: string) { + for (const col of this.columns) { + if (colName === col.property || colName === col.name) { + return col; + } + } + if (this.columnWhiteList) { + return null; + } + throw new Error(`Table ${this.tableName} does not have a column or property named ${colName}`); + } + public get(colName: string) { + return this.getColumn(colName); + } + public getSchema() { + return this.schema; + } + public setSchema(schema: string) { + this.schema = schema; + } + public getName() { + if (this.sql && this.sql.dialectName === 'mssql' && this.isTemporary) { + return `#${this.tableName}`; + } + return this.tableName; + } + public star(): Column; + public star(options: { prefix: string }): ColumnNode[]; + public star(options?: any): Column | ColumnNode[] { + options = options || {}; + if ('prefix' in options) { + return this.columns.map((column) => column.as(options.prefix + column.name)); + } + return new Column({ table: this, star: true }); + } + public count(alias?: string): ColumnNode { + const name = this.alias || this.tableName; + const col: Column = new Column({ table: this, star: true }); + // ColumnNode + return col.count(alias || name + '_count'); + } + public select(...args: any[]): Query { + // create the query and pass it off + const query = new Query(this); + if (args.length === 0) { + query.select(this.star()); + } else { + query.select(...args); + } + return query; + } + public subQuery>(alias?: string): SubQuery { + // create the query and pass it off + const query = new Query(this, true) as SubQuery; + query.columns = []; + query.alias = alias; + query.join = function(this: SubQuery, other: INodeable) { + return new JoinNode('INNER', this.toNode(), other.toNode()); + } + return query; + } + public insert(object: Column[] | Column): Query; + // eslint-disable-next-line @typescript-eslint/unified-signatures + public insert(object: PartialNodeable[] | PartialNodeable): Query; + public insert(...nodes: Column[]): Query; + public insert(...nodes: (Column[] | Column | PartialNodeable[] | PartialNodeable)[]): Query { + const query = new Query(this); + if (!nodes[0] || (Array.isArray(nodes[0]) && (nodes[0] as Column[] | PartialNodeable[]).length === 0)) { + query.select(this.star()); + query.where('1=2'); + } else { + query.insert(...nodes as any); + } + return query; + } + public replace(object: Column[] | Column): Query; + // eslint-disable-next-line @typescript-eslint/unified-signatures + public replace(object: PartialNodeable[] | PartialNodeable): Query; + public replace(...nodes: Column[]): Query; + public replace(...nodes: (Column[] | Column | PartialNodeable[] | PartialNodeable)[]): Query { + const query = new Query(this); + if (!nodes[0] || (Array.isArray(nodes[0]) && (nodes[0] as Column[] | PartialNodeable[]).length === 0)) { + query.select(this.star()); + query.where('1=2'); + } else { + query.replace(...nodes as any); + } + return query; + } + public toNode(): TableNode { + return new TableNode(this); + } + public join(other: INodeable): JoinNode { + return new JoinNode('INNER', this.toNode(), other.toNode()); + } + public leftJoin(other: INodeable): JoinNode { + return new JoinNode('LEFT', this.toNode(), other.toNode()); + } + // auto-join tables based on column intropsection + public joinTo(other: Table): JoinNode { + return leftJoin(this, other); + } + public as(alias: string): TableWithColumns { + // TODO could this be cleaner? + const t = Table.define(this.initialConfig); + t.alias = alias; + return t; + } + public and(...args: Node[]): Query { + const query = new Query(this); + query.where(...args); + return query; + } + public indexes(): IndexQuery { + return new Query(this).indexes() as IndexQuery; + } + public alter(): Query { + const query = new Query(this); + query.alter(); + return query; + } + public create(): Query { + const query = new Query(this); + query.create(); + return query; + } + // eslint-disable-next-line @typescript-eslint/unified-signatures + public delete(table: Table[] | Table | Table | Partial): Query; + public delete(): Query; + public delete(arg?: Table[] | Table | Table | Partial): Query { + const query = new Query(this); + query.delete(arg as any); + return query; + } + public drop(): Query { + const query = new Query(this); + query.drop(); + return query; + } + public from(table: Table[] | Table | Table | JoinNode): Query; + public from(...tables: Table[]): Query; + public from(...args: (Table[] | Table | Table | JoinNode)[]): Query { + const query = new Query(this); + query.from(...args as any); + return query; + } + public limit(count: unknown): Query { + const query = new Query(this); + query.limit(count); + return query; + } + public offset(count: unknown): Query { + const query = new Query(this); + query.offset(count); + return query; + } + public or(object: Partial | Node | string): Query { + const query = new Query(this); + query.or(object); + return query; + } + public order(node: INodeable[] | INodeable): Query; + public order(...nodes: INodeable[]): Query; + public order(...args: (INodeable[] | INodeable)[]): Query { + const query = new Query(this); + query.order(...args as any); + return query; + } + public truncate(): Query { + const query = new Query(this); + query.truncate(); + return query; + } + public update(object: PartialNodeable): Query { + const query = new Query(this); + query.update(object); + return query; + } + public where(object: Partial | Node[] | Node | string): Query; + public where(...nodes: Node[]): Query; + public where(...args: (Partial | Node[] | Node | string)[]): Query { + const query = new Query(this); + query.where(...args as any); + return query; + } +} + +interface IndexQuery { + create(indexName?: string): IndexCreationQuery; + drop(indexName: string): DropIndexNode; + drop(...columns: Column[]): DropIndexNode; +} + +export interface IndexCreationQuery extends Node { + ifNotExists(): IndexCreationQuery; + unique(): IndexCreationQuery; + using(name: string): IndexCreationQuery; + on(...columns: (Column | OrderByValueNode)[]): IndexCreationQuery; + withParser(parserName: string): IndexCreationQuery; + fulltext(): IndexCreationQuery; + spatial(): IndexCreationQuery; +} diff --git a/lib/tableTracker.ts b/lib/tableTracker.ts new file mode 100644 index 00000000..92617d6e --- /dev/null +++ b/lib/tableTracker.ts @@ -0,0 +1,10 @@ +import { Table } from './table.js'; + +export interface ITableTracker { + table?: Table; +} + +// eslint-disable-next-line prefer-arrow/prefer-arrow-functions +export function hasTable(o: unknown): o is Required { + return typeof o === 'object' && o !== null && 'table' in o; +} diff --git a/lib/types.d.ts b/lib/types.d.ts deleted file mode 100644 index 84fb7ab3..00000000 --- a/lib/types.d.ts +++ /dev/null @@ -1,221 +0,0 @@ - -/** - * This is an adaptation of https://github.com/doxout/anydb-sql/blob/4e4c0ff4a7f2efb7f820baaafea1f624f1ae0399/d.ts/anydb-sql.d.ts - * Whole project is MIT licensed, so, we can use it. We also feed back any - * improvements, questions, concerns. - */ -declare module "sql" { - - type SQLDialects = - | "mssql" - | "mysql" - | "oracle" - | "postgres" - | "sqlite" - ; - - interface OrderByValueNode {} - - interface Named { - name?: Name; - } - interface ColumnDefinition extends Named { - jsType?: Type; - dataType: string; - primaryKey?: boolean; - references?: { - table:string; - column: string; - onDelete?: 'restrict' | 'cascade' | 'no action' | 'set null' | 'set default'; - onUpdate?: 'restrict' | 'cascade' | 'no action' | 'set null' | 'set default'; - }; - notNull?: boolean; - unique?: boolean; - defaultValue?: Type; - } - - interface TableDefinition { - name: Name; - schema: string; - columns: {[CName in keyof Row]: ColumnDefinition}; - dialect?: SQLDialects; - isTemporary?: boolean; - foreignKeys?: { - table: string, - columns: (keyof Row)[], - refColumns: string[], - onDelete?: 'restrict' | 'cascade' | 'no action' | 'set null' | 'set default'; - onUpdate?: 'restrict' | 'cascade' | 'no action' | 'set null' | 'set default'; - } - } - - interface QueryLike { - values: any[] - text:string - } - - interface Executable { - toQuery():QueryLike; - } - - interface Queryable extends Executable { - where(...nodes:any[]):Query - delete():ModifyingQuery - select(star: Column): Query; - select(n1: Column):Query<{[N in N1]: T1}>; - select( - n1: Column, - n2: Column):Query<{[N in N1]: T1} & {[N in N2]: T2}> - select( - n1: Column, - n2: Column, - n3: Column):Query<{[N in N1]: T1} & {[N in N2]: T2} & {[N in N3]: T3}> - select(...nodesOrTables:any[]):Query - - } - - interface Query extends Executable, Queryable { - resultType: T; - - from(table:TableNode):Query - from(statement:string):Query - update(o:{[key: string]:any}):ModifyingQuery - update(o:{}):ModifyingQuery - group(...nodes:any[]):Query - order(...criteria:OrderByValueNode[]):Query - limit(l:number):Query - offset(o:number):Query - } - - interface SubQuery { - select(node:Column):SubQuery - select(...nodes: any[]):SubQuery - where(...nodes:any[]):SubQuery - from(table:TableNode):SubQuery - from(statement:string):SubQuery - group(...nodes:any[]):SubQuery - order(criteria:OrderByValueNode):SubQuery - exists():BinaryNode - notExists(): BinaryNode; - notExists(subQuery:SubQuery):BinaryNode - } - - - interface ModifyingQuery extends Executable { - returning(...nodes:any[]):Query - where(...nodes:any[]):ModifyingQuery - } - - interface TableNode { - join(table:TableNode):JoinTableNode - leftJoin(table:TableNode):JoinTableNode - } - - interface JoinTableNode extends TableNode { - on(filter:BinaryNode):TableNode - on(filter:string):TableNode - } - - interface CreateQuery extends Executable { - ifNotExists():Executable - } - interface DropQuery extends Executable { - ifExists():Executable - } - - type Columns = { - [Name in keyof T]: Column - } - type Table = TableNode & Queryable & Named & Columns & { - getName(): string; - getSchema(): string; - - literal(statement: string): any; - - create():CreateQuery - drop():DropQuery - as(name:OtherName):Table - update(o: Partial):ModifyingQuery - insert(row:T):ModifyingQuery - insert(rows:T[]):ModifyingQuery - select():Query - select(...nodes:any[]):Query - from(table:TableNode):Query - from(statement:string):Query - star():Column - subQuery():SubQuery - columns:Column[] - sql: SQL; - alter():AlterQuery; - indexes(): IndexQuery; - } - - interface AlterQuery extends Executable { - addColumn(column:Column): AlterQuery; - addColumn(name: string, options:string): AlterQuery; - dropColumn(column: Column|string): AlterQuery; - renameColumn(column: Column, newColumn: Column):AlterQuery; - renameColumn(column: Column, newName: string):AlterQuery; - renameColumn(name: string, newName: string):AlterQuery; - rename(newName: string): AlterQuery - } - interface IndexQuery { - create(): IndexCreationQuery; - create(indexName: string): IndexCreationQuery; - drop(indexName: string): Executable; - drop(...columns: Column[]): Executable - } - interface IndexCreationQuery extends Executable { - unique(): IndexCreationQuery; - using(name: string): IndexCreationQuery; - on(...columns: (Column|OrderByValueNode)[]): IndexCreationQuery; - withParser(parserName: string): IndexCreationQuery; - fulltext(): IndexCreationQuery; - spatial(): IndexCreationQuery; - } - - interface SQL { - functions: { - LOWER(c:Column):Column - } - } - - interface BinaryNode { - and(node:BinaryNode):BinaryNode - or(node:BinaryNode):BinaryNode - } - - interface Column { - name: Name - in(arr:T[]):BinaryNode - in(subQuery:SubQuery):BinaryNode - notIn(arr:T[]):BinaryNode - equals(node: T|Column):BinaryNode - notEquals(node: T|Column):BinaryNode - gte(node: T|Column):BinaryNode - lte(node: T|Column):BinaryNode - gt(node:T|Column):BinaryNode - lt(node: T|Column):BinaryNode - like(str:string):BinaryNode - multiply:{ - (node:Column):Column - (n:number):Column //todo check column names - } - isNull():BinaryNode - isNotNull():BinaryNode - //todo check column names - sum():Column - count():Column - count(name:string):Column - distinct():Column - as(name:OtherName):Column - ascending:OrderByValueNode - descending:OrderByValueNode - asc:OrderByValueNode - desc:OrderByValueNode - } - - function define(map:TableDefinition): Table; - function setDialect(dialect: SQLDialects): void; - -} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..3651bcba --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6460 @@ +{ + "name": "sql-ts", + "version": "8.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sql-ts", + "version": "8.0.0", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21", + "sliced": "~1.0.x" + }, + "devDependencies": { + "@rollup/plugin-typescript": "^12.3.0", + "@types/lodash": "^4.17.7", + "@types/mocha": "^10.0.10", + "@types/node": "^24.13.3", + "@typescript-eslint/eslint-plugin": "^8.65.0", + "@typescript-eslint/parser": "^8.65.0", + "eslint": "^9.39.5", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-import": "^2.32.0", + "eslint-plugin-jsdoc": "^63.3.2", + "eslint-plugin-prefer-arrow": "^1.2.3", + "eslint-plugin-unicorn": "^65.0.0", + "mocha": "^11.7.6", + "rollup-plugin-delete": "^3.0.2", + "rollup-plugin-dts": "^6.4.1", + "ts-node": "^10.9.2", + "tslib": "^2.8.1", + "typescript": "~6.0.3" + }, + "engines": { + "node": "^22 || ^24 || >=26" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.91.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.91.0.tgz", + "integrity": "sha512-vgqlMGNNhZxwDYbUNIHj3Hskb4R28iqdXx90ufHyt/NeuTQkeqjTDslAs9I0/GCAfbxP5BpH5WsL1R1fht5Lxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.9", + "@typescript-eslint/types": "^8.65.0", + "comment-parser": "1.4.7", + "esquery": "^1.7.0", + "jsdoc-type-pratt-parser": "~8.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@es-joy/resolve.exports": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@es-joy/resolve.exports/-/resolve.exports-1.2.0.tgz", + "integrity": "sha512-Q9hjxWI5xBM+qW2enxfe8wDKdFWMfd0Z29k5ZJnuBqD/CasY5Zryj09aCA6owbGATWz+39p5uIdaHXpopOcG8g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", + "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", + "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.3.0", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.5", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", + "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@rollup/plugin-typescript": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-12.3.0.tgz", + "integrity": "sha512-7DP0/p7y3t67+NabT9f8oTBFE6gGkto4SA6Np2oudYmZE/m1dt8RB0SjL1msMxFpLo631qjRCcBlAbq1ml/Big==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.1.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.14.0||^3.0.0||^4.0.0", + "tslib": "*", + "typescript": ">=3.7.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + }, + "tslib": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", + "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.3.tgz", + "integrity": "sha512-c0wdcekXtQvvn5Tsrk/+op/gUArrbWaFduBnTLP2l1cKLSQs4diMWjJw3m6A0DdzT8dAAX95KpkJ3qynCePbmw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.3.tgz", + "integrity": "sha512-3YjElDdWN+qXAFbJ/CzPV+0wspLqh54k/I6GfdYtEJRqg7buSgc1yPM3B+93j1M4neobtkATHZTmxK2AMVGfnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.3.tgz", + "integrity": "sha512-Pch2pFNOxxz1hTjypIdPyRTR6riiwRl84+VcN9djS680fw+Co1nAJINrdpqp7KV0NvyuU8ilZXZCjd7ykJl1GQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.3.tgz", + "integrity": "sha512-LEuncFUHFiF8t4yZVZvvZA1wk0pjAscRnsrn1EfTEmN4HXotBi2YtcnLRyaK6UbuczW7xZS5ES+81Rdz8Z0T6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.3.tgz", + "integrity": "sha512-zvBUvsQUpOWALdDsk6qbS8bXf2VxmPisuudNDrY7x0p0jBdsoZl8HsHczIOgkQiZldmcacMKtBzpoGVNeIe2bQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.3.tgz", + "integrity": "sha512-C2KmNrcSem/AMg984H/dev+si0lieQGdXdR/lYGJnuumXnFb9Y7QdiI62obFdLlxRYLBv4P0eUVIDbD4c1vVvw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.3.tgz", + "integrity": "sha512-ggXnsTAEzNQx74XpunRsiZ9aBZDsI7XIa0hm2nzR9f4WzH5/f/d73ZSDaC5ejJ8YLY4NW+V3wr0tjOaeCq8hqA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.3.tgz", + "integrity": "sha512-2vng+FlzNUhKZxtej3IUqJgbZoQk2M/dwQM20+ULV0R/E/8tr9/P6uEf2iiGIk4HL0zMKh5Jry7mUHdUOvyGgA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.3.tgz", + "integrity": "sha512-LLLFZKt4/Nraf9rxDkhiU8QVgLF4WmCkfr0L4fj0fPfIZFBib0DeiFk1hhaYKd03LFAFJcxHslhDFlNJLylf5Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.3.tgz", + "integrity": "sha512-WJkdQCvS9sWNOUBJZfQRKpZGFBztRzcowI+nndmflKgU4XY+3a420FgTOSKTsVqJbnzSxeT4vaJalpOaPo2YCQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.3.tgz", + "integrity": "sha512-PwHXCCS2n64/1Ot6rP1YEYA02MGYBcQlr8CSZZyrUG2O7NH6NklYmvr9v3Jy+5e/eDeNchc/ukmKJi9LuflMIQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.3.tgz", + "integrity": "sha512-vUjxINQu3RC8NZS3ykk1gN65gIz8pAopOq2HXuZhiIxHdx7TFvDG+jgrdSgInu1Eza4/Rfi2VzZgyIgEH4WOaw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.3.tgz", + "integrity": "sha512-wzko4aJ13+0G3kGnviCg5gnXFKd40izKsrf2uOw12US4XqprkDrmwOpeW14aSNa37V8bfPcz5Fkob6LZ3BAPmA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.3.tgz", + "integrity": "sha512-8120ue0JUMSwy11stlwnfdX3pPd+WZYGCDBwEHWtIHi6pOpZmsEF5QKB7a/UN+XFdqvobxz98kv8RTqikyCEBw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.3.tgz", + "integrity": "sha512-XLFHnR3tXMjbOCh2vtVJHmxt+995uJsTERQyseFDRA0xxMxyTZPLa3OIUlyFaO4mF/Lu0FjmWHCuPXJT1n/IOg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.3.tgz", + "integrity": "sha512-se6yXvNGMIl0f+RQzyh7XAmia8/9kplQx424wnG2w0C1oi6XgO6Y8otKhdXFHbHs88Ihavzmvh1NWjuovE76BQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.3.tgz", + "integrity": "sha512-gNoxRefktVIiGflpONuxWWXZAzIQG++z9qHO3xKwk4WdDMuQja3JHGfE1u0i3PfPDyvhypdk+WrgIJqLhGG7sg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.3.tgz", + "integrity": "sha512-V4KtWtQfAFMU7+9/A/VDps/VI8CHd3cYz0L8sgJzz8qK7eY7wI4ruFD82UYIYvW9Z4DtlTfhQcsl4XyPHW5uSg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.3.tgz", + "integrity": "sha512-LBx9LYXvj2CBkMkjLdNAWLwH0MLMin7do2VcVo9kVPibGLkY0BQQut2fv7NVqkXqZ/CrAu9LqDHVV1xHCMpCPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.3.tgz", + "integrity": "sha512-ABVf3Q0RCu7NcyCCOZQI0pJ3GuSdfSl8EXcy88QtdceIMIoCUdfhsJChZ64L9zVM2aJHjde1Bhn5uqSRcX9ySA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "peer": true + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.3.tgz", + "integrity": "sha512-+2Cy/ldweGBLlPIKsQLF8U5N44a0KDdbrk1rAjHOM9M2K+kGdIVjHLmmrZIcx+9Ny3ke/1JomCsDI1ocb11+sg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "peer": true + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.3.tgz", + "integrity": "sha512-dtZvzc8BedpSaFNy75x6uiWwAGTH+aZHDtdrqP6qk+WcLJrfti6sGje1ZJ9UxyzDLF23d/mV+PaMwuC0hL7UVA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.3.tgz", + "integrity": "sha512-Rj8Ra4noo+aYy7sKBggCx0407mws34kAb1ySyWuq5DAtFBQdkSwnsjCgPrhPe9cvgBKZIukpE+CVHvORCS93kQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.3.tgz", + "integrity": "sha512-vp7N084ew/odXn2gi/mzm9mUkQu9l6AiN6dt4IeUM2Uvm9o+cVmP+YkqbMOteLbiGgqBBlJZjIMYVCfOOIVbVQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.3.tgz", + "integrity": "sha512-MOG/3gTOn4Fwf574RVOaY61I5o6P90legkFADiTyn1hyjNydT+cerU2rLUwPdZkKKyJ+iT+K9p7WXK4LM1Ka6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sindresorhus/base62": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/base62/-/base62-1.0.0.tgz", + "integrity": "sha512-TeheYy0ILzBEI/CO55CP6zJCSdSWeRtGnHy8U8dWSUH4I68iqTsy7HkMktR4xakThc9jotkPQUXT4ITdbV7cHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/lodash": { + "version": "4.17.24", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.24.tgz", + "integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mocha": { + "version": "10.0.10", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", + "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.13.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz", + "integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.65.0.tgz", + "integrity": "sha512-IEgob78X12rHpUmtcwFsXhZdVGJtwTVP8FiCLZkR6GlYVrl2PcuB+KhCE5BlVC/eQpQnu8WXRtkHZuPar+gCRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.65.0", + "@typescript-eslint/type-utils": "8.65.0", + "@typescript-eslint/utils": "8.65.0", + "@typescript-eslint/visitor-keys": "8.65.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.65.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.65.0.tgz", + "integrity": "sha512-YjaZ7PRI5qY7ax2L3PbvX0rRyGtipAReCWs0mhhDBHjH/vl0g0BonaGXrKdKpMbIIsMIwDgbk/xzkBTyAltS5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/typescript-estree": "8.65.0", + "@typescript-eslint/utils": "8.65.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.65.0.tgz", + "integrity": "sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.65.0", + "@typescript-eslint/tsconfig-utils": "8.65.0", + "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/visitor-keys": "8.65.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.65.0.tgz", + "integrity": "sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.65.0", + "@typescript-eslint/types": "^8.65.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.65.0.tgz", + "integrity": "sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.65.0.tgz", + "integrity": "sha512-gXiwIHsYreboxeJucHKPvgwl7dXt50mF8s1/c00cP/WoVTyWKFdtfhRWwZiXYFU5H2O8vVoSLNrexFZjYS/SGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.65.0", + "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/typescript-estree": "8.65.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.65.0.tgz", + "integrity": "sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.65.0", + "@typescript-eslint/tsconfig-utils": "8.65.0", + "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/visitor-keys": "8.65.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.65.0.tgz", + "integrity": "sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.65.0", + "@typescript-eslint/types": "^8.65.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.65.0.tgz", + "integrity": "sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.65.0.tgz", + "integrity": "sha512-CZ4nMxWwgu1HEEFNkeaCptra9QCtkmKdgf3sWh1rl1trIhmxLilgTV4cwcbQ4wemnT4sWQN8CaKOmdYx+g2gMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.65.0", + "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/typescript-estree": "8.65.0", + "@typescript-eslint/visitor-keys": "8.65.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.65.0.tgz", + "integrity": "sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.65.0", + "@typescript-eslint/tsconfig-utils": "8.65.0", + "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/visitor-keys": "8.65.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.65.0.tgz", + "integrity": "sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.65.0", + "@typescript-eslint/types": "^8.65.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.65.0.tgz", + "integrity": "sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.65.0.tgz", + "integrity": "sha512-Esbl8OSYiVxBokYgWPf7VVWg/BE798wXhimnn9ML9Pt5qoDf8bfQlgjlKXR/k98+AcNzlLKYrpCcrcuZ9DZLgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/visitor-keys": "8.65.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.65.0.tgz", + "integrity": "sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.65.0.tgz", + "integrity": "sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.65.0", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.6", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.6.tgz", + "integrity": "sha512-69D/imtToCsIcAl8WBS2YaRwA4jO/j0HhU+hELqMEu9f54MoUtI6+XH5mrKU8rEFNEk/Ui1I2MK4/JkWacclGw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz", + "integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true, + "license": "ISC" + }, + "node_modules/browserslist": { + "version": "4.28.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz", + "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.44", + "caniuse-lite": "^1.0.30001806", + "electron-to-chromium": "^1.5.393", + "node-releases": "^2.0.51", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/builtin-modules": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-5.3.0.tgz", + "integrity": "sha512-hMQUl2bUFG339QygPM97E+mc8OY1IAchORZxm4a/frcYwKzozMzRVDBwHW0NjOqGElLm2O37AVQE8ikxlZHrMQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001806", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", + "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/change-case": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", + "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/comment-parser": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.7.tgz", + "integrity": "sha512-0h+uSNtQGW3D98eQt3jJ8L06Fves8hncB4V/PKdw/Qb8Hnk19VaKuTr55UNRYiSoVa7WwrFls+rh3ux9agmkeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/core-js-compat": { + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz", + "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/del": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/del/-/del-8.0.1.tgz", + "integrity": "sha512-gPqh0mKTPvaUZGAuHbrBUYKZWBNAeHG7TU3QH5EhVwPMyKvmfJaNXhcD2jTcXsJRRcffuho4vaYweu80dRrMGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "globby": "^14.0.2", + "is-glob": "^4.0.3", + "is-path-cwd": "^3.0.0", + "is-path-inside": "^4.0.0", + "p-map": "^7.0.2", + "presentable-error": "^0.0.1", + "slash": "^5.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/del/node_modules/is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/detect-indent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-7.0.2.tgz", + "integrity": "sha512-y+8xyqdGLL+6sh0tVeHcfP/QDd8gUgbasolJJpY7NgeQGSZ739bDtSiaiDgtoicy+mtYB81dKLxO9xRhCyIB3A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.398", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.398.tgz", + "integrity": "sha512-AsvhAxopJGh6museTDMIjn6JpDYOfgu4RLlygomt87MUwBUqTfd/1EiPtx10/LZE8xpTvkP2E9Gafq7lkLtodQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-abstract": { + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-abstract-get": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-abstract-get/-/es-abstract-get-1.0.0.tgz", + "integrity": "sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.2", + "is-callable": "^1.2.7", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.4.tgz", + "integrity": "sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-abstract-get": "^1.0.0", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "is-callable": "^1.2.7", + "is-date-object": "^1.1.0", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.5", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", + "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.6", + "@eslint/js": "9.39.5", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.10.tgz", + "integrity": "sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.16.1", + "resolve": "^2.0.0-next.6" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/resolve": { + "version": "2.0.0-next.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz", + "integrity": "sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.2", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.14.0.tgz", + "integrity": "sha512-W2WCRZ9Dqntd+2u8jJcVMV2PKulc6RdLgUUoh/yQr3uB6lo/ZOeGx11sv60/8S4QFFKNslAlWhr9u0Ef7ZW6Ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jsdoc": { + "version": "63.3.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-63.3.2.tgz", + "integrity": "sha512-5B3oO23iqbNJC/ru7uqIY80wmY66De1Q0+5kXQGHuLrGze/rL0Zw/YktMcqgYQ+kdHmgvY1q5TpRgl3yZMLmhQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@es-joy/jsdoccomment": "~0.91.0", + "@es-joy/resolve.exports": "1.2.0", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.7", + "debug": "^4.4.3", + "escape-string-regexp": "^4.0.0", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "html-entities": "^2.6.0", + "object-deep-merge": "^2.0.1", + "parse-imports-exports": "^0.2.4", + "semver": "^7.8.5", + "spdx-expression-parse": "^5.0.0", + "to-valid-identifier": "^1.0.0" + }, + "engines": { + "node": "^22.13.0 || >=24" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/eslint-plugin-prefer-arrow": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.3.tgz", + "integrity": "sha512-J9I5PKCOJretVuiZRGvPQxCbllxGAV/viI20JO3LYblAodofBxyMnZAJ+WGeClHgANnSJberTNoFWWjrWKBuXQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=2.0.0" + } + }, + "node_modules/eslint-plugin-unicorn": { + "version": "65.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-65.0.1.tgz", + "integrity": "sha512-daCrQrgxOoOz2uMPWB3Y3vvv/5q+ncwICI8IjoebiwtW87CaY4tAN5EEiRXTYVnf7qi1v1BGBdHOSnZLV0rx6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "@eslint-community/eslint-utils": "^4.9.1", + "change-case": "^5.4.4", + "ci-info": "^4.4.0", + "core-js-compat": "^3.49.0", + "detect-indent": "^7.0.2", + "find-up-simple": "^1.0.1", + "globals": "^17.4.0", + "indent-string": "^5.0.0", + "is-builtin-module": "^5.0.0", + "jsesc": "^3.1.0", + "pluralize": "^8.0.0", + "regjsparser": "^0.13.0", + "semver": "^7.7.4", + "strip-indent": "^4.1.1" + }, + "engines": { + "node": "^20.10.0 || >=21.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" + }, + "peerDependencies": { + "eslint": ">=9.38.0" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up-simple": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.3.tgz", + "integrity": "sha512-/zipXxyO6rGvuNGDiULY9MvEGSkb2gaG4GGH4ygMi0ZZzyMHdUZBmntJmx5x1G2VuPytCwGN4xsJP6cw+sK+vQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.2.0.tgz", + "integrity": "sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2", + "hasown": "^2.0.4", + "is-callable": "^1.2.7", + "is-document.all": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.3.tgz", + "integrity": "sha512-DRdx5neNsG/QXbniLFWi2YmC/68oeOOmKz6zOjVk6ZS1ZLXgLIKqVEc6hWsmkjBbgii0SwaBTcJ5XKj5gzY/4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "17.8.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.8.0.tgz", + "integrity": "sha512-Zz/LMDZScFmkakeL2cTHzf+PbWKdpU3uclqkZT7TjDG58j5WPt0PpA+n9uPI24fZtlw07q0OtEi84K+umsRzqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", + "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.3", + "path-type": "^6.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "license": "MIT" + }, + "node_modules/ignore": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", + "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-builtin-module": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-5.0.0.tgz", + "integrity": "sha512-f4RqJKBUe5rQkJ2eJEJBXSticB3hGbN9j0yxxMQFqIW89Jp9WYFtzfTcRlstDKVUTRzSOTLKRfO9vIztenwtxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "builtin-modules": "^5.0.0" + }, + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-document.all": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-document.all/-/is-document.all-1.0.0.tgz", + "integrity": "sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-3.0.0.tgz", + "integrity": "sha512-kyiNFFLU0Ampr6SDZitD/DwUo4Zs1nSdnygUBqsu3LooL00Qvb5j+UnvApUn/TTj1J3OuE6BTdQ5rudKmU2ZaA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/js-yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-8.0.0.tgz", + "integrity": "sha512-uQu/fXVqVaMg6gM8/E5G5+eygVcZ1NV0Z51CvqhNa2bDWxvHMl484ETr6vph4oPyC+KUcbP/w2W2pewfCiR9aQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mocha": { + "version": "11.7.6", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.6.tgz", + "integrity": "sha512-nS9xOGbw2I3cjCpxwZAEJ9xK9lmJ08vEkQvLtz4du9ZrF9UrjRpeJGiIgl2Z+Qs++pmB4ecDe48Fwsh+j+j7xA==", + "dev": true, + "license": "MIT", + "dependencies": { + "browser-stdout": "^1.3.1", + "chokidar": "^4.0.1", + "debug": "^4.3.5", + "diff": "^7.0.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^10.4.5", + "he": "^1.2.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^9.0.5", + "ms": "^2.1.3", + "picocolors": "^1.1.1", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^9.2.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1", + "yargs-unparser": "^2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/mocha/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.3.tgz", + "integrity": "sha512-DRdx5neNsG/QXbniLFWi2YmC/68oeOOmKz6zOjVk6ZS1ZLXgLIKqVEc6hWsmkjBbgii0SwaBTcJ5XKj5gzY/4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-exports-info": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.2.tgz", + "integrity": "sha512-kXs9Go0cah0qHVV2v389IXQLdLCeE1xfFtjOAF+iobu0OIoG1pje8At2vMHyaPMiPMnG/LWP50twML21eMcAag==", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.flatmap": "^1.3.3", + "es-errors": "^1.3.0", + "object.entries": "^1.1.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/node-exports-info/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/node-releases": { + "version": "2.0.51", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", + "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/object-deep-merge": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object-deep-merge/-/object-deep-merge-2.0.1.tgz", + "integrity": "sha512-aKttDKcU3pyZqKcCkDhsMn70WmZFG2JGDQLP9EcLyTSIFQRCPWLAmBZRLJnrVUrhPG1jETEEbfdgbNtJf1LyMg==", + "dev": true, + "license": "MIT" + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/own-keys": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.2.tgz", + "integrity": "sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.6.tgz", + "integrity": "sha512-I4Prw6ivkd6p8PiYR1tXASOAOBzIJwu0TB7fqaX0c/8c3QAehNYmX57EijyGGGBt3c/BIowGwV03RVBtXvHEVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-imports-exports": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", + "integrity": "sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-statements": "1.0.11" + } + }, + "node_modules/parse-statements": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/parse-statements/-/parse-statements-1.0.11.tgz", + "integrity": "sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-type": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", + "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/presentable-error": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/presentable-error/-/presentable-error-0.0.1.tgz", + "integrity": "sha512-E6rsNU1QNJgB3sjj7OANinGncFKuK+164sLXw1/CqBjj/EkXSoSdHCtWQGBNlREIGLnL7IEUEGa08YFVUbrhVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regjsparser": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.2.tgz", + "integrity": "sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reserved-identifiers": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/reserved-identifiers/-/reserved-identifiers-1.2.0.tgz", + "integrity": "sha512-yE7KUfFvaBFzGPs5H3Ops1RevfUEsDc5Iz65rOwWg4lE8HJSYtle77uul3+573457oHvBKuHYDl/xqUkKpEEdw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.3.tgz", + "integrity": "sha512-Gu0c0iH9FzgX1L1t7ByIbbS3Vmdz+6KHm/EsqmmC71gUQ82yvZRkTK6XzrFObSka91WUVdynqp6nsfilzr5k6Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.62.3", + "@rollup/rollup-android-arm64": "4.62.3", + "@rollup/rollup-darwin-arm64": "4.62.3", + "@rollup/rollup-darwin-x64": "4.62.3", + "@rollup/rollup-freebsd-arm64": "4.62.3", + "@rollup/rollup-freebsd-x64": "4.62.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.3", + "@rollup/rollup-linux-arm-musleabihf": "4.62.3", + "@rollup/rollup-linux-arm64-gnu": "4.62.3", + "@rollup/rollup-linux-arm64-musl": "4.62.3", + "@rollup/rollup-linux-loong64-gnu": "4.62.3", + "@rollup/rollup-linux-loong64-musl": "4.62.3", + "@rollup/rollup-linux-ppc64-gnu": "4.62.3", + "@rollup/rollup-linux-ppc64-musl": "4.62.3", + "@rollup/rollup-linux-riscv64-gnu": "4.62.3", + "@rollup/rollup-linux-riscv64-musl": "4.62.3", + "@rollup/rollup-linux-s390x-gnu": "4.62.3", + "@rollup/rollup-linux-x64-gnu": "4.62.3", + "@rollup/rollup-linux-x64-musl": "4.62.3", + "@rollup/rollup-openbsd-x64": "4.62.3", + "@rollup/rollup-openharmony-arm64": "4.62.3", + "@rollup/rollup-win32-arm64-msvc": "4.62.3", + "@rollup/rollup-win32-ia32-msvc": "4.62.3", + "@rollup/rollup-win32-x64-gnu": "4.62.3", + "@rollup/rollup-win32-x64-msvc": "4.62.3", + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-delete": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-delete/-/rollup-plugin-delete-3.0.2.tgz", + "integrity": "sha512-26GSi/aeYQ/hEBdG1rjEMeh+WUhiPZ3hGmSr9Ucj7mhLQ1P9j8KEgtYoybDp7OlIMj3eQjHHB9fnqhxNuVgfzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "del": "^8.0.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "rollup": "*" + } + }, + "node_modules/rollup-plugin-dts": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-6.4.1.tgz", + "integrity": "sha512-l//F3Zf7ID5GoOfLfD8kroBjQKEKpy1qfhtAdnpibFZMffPaylrg1CoDC2vGkPeTeyxUe4bVFCln2EFuL7IGGg==", + "dev": true, + "license": "LGPL-3.0-only", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "@jridgewell/sourcemap-codec": "^1.5.5", + "convert-source-map": "^2.0.0", + "magic-string": "^0.30.21" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/Swatinem" + }, + "optionalDependencies": { + "@babel/code-frame": "^7.29.0" + }, + "peerDependencies": { + "rollup": "^3.29.4 || ^4", + "typescript": "^4.5 || ^5.0 || ^6.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", + "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sliced": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", + "integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA==", + "deprecated": "Unsupported", + "license": "MIT" + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-5.0.0.tgz", + "integrity": "sha512-vngmw3Rgn+o2arXNbnZaj5UtOEBuWBfvaI+Wc8GFfykIhA5/vdK9/Sp/XkLv63dykz2rxKDvKEHupF5P0FORcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.11.tgz", + "integrity": "sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-object-atoms": "^1.1.2", + "has-property-descriptors": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.10.tgz", + "integrity": "sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-indent": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.1.1.tgz", + "integrity": "sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/to-valid-identifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-valid-identifier/-/to-valid-identifier-1.0.0.tgz", + "integrity": "sha512-41wJyvKep3yT2tyPqX/4blcfybknGB4D+oETKLs7Q76UiPqRpUJK3hr1nxelyYO0PHKVzJwlu0aCeEAsGI6rpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/base62": "^1.0.0", + "reserved-identifiers": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.8.tgz", + "integrity": "sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "for-each": "^0.3.5", + "gopd": "^1.2.0", + "is-typed-array": "^1.1.15", + "possible-typed-array-names": "^1.1.0", + "reflect.getprototypeof": "^1.0.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.22", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.22.tgz", + "integrity": "sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/workerpool": { + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", + "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json index dc250c01..c4aa8968 100644 --- a/package.json +++ b/package.json @@ -1,30 +1,66 @@ { - "author": "brianc ", - "name": "sql", - "description": "sql builder", - "version": "0.78.0", - "homepage": "https://github.com/brianc/node-sql", - "license": "MIT", - "repository": { - "type": "git", - "url": "git://github.com/brianc/node-sql.git" - }, - "main": "lib/", - "types": "lib/types.d.ts", - "scripts": { - "test": "node_modules/.bin/mocha", - "lint": "jshint lib test", - "posttest": "jshint lib test" - }, - "engines": { - "node": "*" - }, - "dependencies": { - "sliced": "0.0.x", - "lodash": "4.1.x" - }, - "devDependencies": { - "jshint": "*", - "mocha": "*" - } + "author": { + "name": "Stefan Charsley", + "email": "charsleysa@gmail.com" + }, + "name": "sql-ts", + "description": "SQL Builder", + "version": "8.0.0", + "homepage": "https://github.com/charsleysa/node-sql-ts", + "license": "MIT", + "repository": { + "type": "git", + "url": "git://github.com/charsleysa/node-sql-ts.git" + }, + "type": "module", + "exports": { + ".": { + "import": "./dist/lib.js", + "require": "./dist/lib.cjs", + "types": "./dist/lib.d.ts" + } + }, + "types": "./dist/lib.d.ts", + "scripts": { + "pretest": "eslint --ext .ts ./lib && eslint --ext .ts ./test && rollup -c && tsc -p ./test/tsconfig.json", + "test": "mocha", + "lint": "eslint --ext .ts ./lib && eslint --ext .ts ./test", + "build": "rollup -c", + "release:major": "npm run test && npm run build && npm version major -m \"chore: release\" && git push origin master --tags && npm publish", + "release:minor": "npm run test && npm run build && npm version minor -m \"chore: release\" && git push origin master --tags && npm publish", + "release:patch": "npm run test && npm run build && npm version patch -m \"chore: release\" && git push origin master --tags && npm publish" + }, + "engines": { + "node": "^22 || ^24 || >=26" + }, + "dependencies": { + "lodash": "^4.17.21", + "sliced": "~1.0.x" + }, + "devDependencies": { + "@rollup/plugin-typescript": "^12.3.0", + "@types/mocha": "^10.0.10", + "@types/lodash": "^4.17.7", + "@types/node": "^24.13.3", + "@typescript-eslint/eslint-plugin": "^8.65.0", + "@typescript-eslint/parser": "^8.65.0", + "eslint": "^9.39.5", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-import": "^2.32.0", + "eslint-plugin-jsdoc": "^63.3.2", + "eslint-plugin-prefer-arrow": "^1.2.3", + "eslint-plugin-unicorn": "^65.0.0", + "mocha": "^11.7.6", + "rollup-plugin-delete": "^3.0.2", + "rollup-plugin-dts": "^6.4.1", + "ts-node": "^10.9.2", + "tslib": "^2.8.1", + "typescript": "~6.0.3" + }, + "mocha": { + "reporter": "dot", + "ui": "tdd", + "watch-extensions": "js", + "spec": "spec/**/*.js" + } } diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 00000000..c5e077c4 --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,75 @@ +import typescript from '@rollup/plugin-typescript'; +import del from 'rollup-plugin-delete'; +import dts from 'rollup-plugin-dts'; + +export default [ + { + input: './lib/index.ts', + output: { + file: './dist/lib.js', + format: 'esm', + sourcemap: true + }, + external: [ + 'assert', + 'lodash/defaults.js', + 'lodash/flatten.js', + 'lodash/fromPairs.js', + 'lodash/isArray.js', + 'lodash/isNumber.js', + 'lodash/isFunction.js', + 'lodash/map.js', + 'lodash/padStart.js', + 'lodash/reduce.js', + 'sliced' + ], + plugins: [ + del({ + targets: './dist' + }), + typescript({ + tsconfig: './tsconfig.build.json' + }) + ] + }, + { + input: './lib/index.ts', + output: { + file: './dist/lib.cjs', + format: 'commonjs', + sourcemap: true + }, + external: [ + 'assert', + 'lodash/defaults.js', + 'lodash/flatten.js', + 'lodash/fromPairs.js', + 'lodash/isArray.js', + 'lodash/isNumber.js', + 'lodash/isFunction.js', + 'lodash/map.js', + 'lodash/padStart.js', + 'lodash/reduce.js', + 'sliced' + ], + plugins: [ + typescript({ + tsconfig: './tsconfig.build.json' + }) + ] + }, + { + input: './dist/dts/index.d.ts', + output: { + file: './dist/lib.d.ts', + format: 'es' + }, + plugins: [ + dts(), + del({ + hook: 'buildEnd', + targets: './dist/dts' + }) + ] + } +]; diff --git a/runtests.js b/runtests.js deleted file mode 100644 index ac89769b..00000000 --- a/runtests.js +++ /dev/null @@ -1,18 +0,0 @@ -var childProcess = require("child_process"); -var path = require("path"); - -var env = process.env; -env.NODE_ENV = "test"; - -var options = { - env: env -}; - -var command = path.join(".", "node_modules", ".bin", "mocha"); -if (process.platform == "win32") command += ".cmd"; -var run = childProcess.spawn(command, [], options); -run.stdout.pipe(process.stdout); -run.stderr.pipe(process.stderr); -run.on('close', function(code) { - process.exit(code); -}); diff --git a/test/binary-clause-tests.js b/test/binary-clause-tests.js deleted file mode 100644 index 10c50737..00000000 --- a/test/binary-clause-tests.js +++ /dev/null @@ -1,44 +0,0 @@ -'use strict'; - -var assert = require('assert'); -var Table = require(__dirname + '/../lib/table'); - -var Foo = Table.define({ - name: 'foo', - columns: ['baz','bar'] -}); - -test('operators', function() { - assert.equal(Foo.baz.equals(1).operator, '='); - assert.equal(Foo.baz.equal(1).operator, '='); - assert.equal(Foo.baz.notEqual(1).operator, '<>'); - assert.equal(Foo.baz.notEquals(1).operator, '<>'); - assert.equal(Foo.baz.like('asdf').operator, 'LIKE'); - assert.equal(Foo.baz.notLike('asdf').operator, 'NOT LIKE'); - assert.equal(Foo.baz.isNull().operator, 'IS NULL'); - assert.equal(Foo.baz.isNotNull().operator, 'IS NOT NULL'); - assert.equal(Foo.baz.gt(1).operator, '>'); - assert.equal(Foo.baz.gte(1).operator, '>='); - assert.equal(Foo.baz.lt(1).operator, '<'); - assert.equal(Foo.baz.lte(1).operator, '<='); - assert.equal(Foo.baz.plus(1).operator, '+'); - assert.equal(Foo.baz.minus(1).operator, '-'); - assert.equal(Foo.baz.multiply(1).operator, '*'); - assert.equal(Foo.baz.leftShift(1).operator, '<<'); - assert.equal(Foo.baz.rightShift(1).operator, '>>'); - assert.equal(Foo.baz.bitwiseAnd(1).operator, '&'); - assert.equal(Foo.baz.bitwiseNot(1).operator, '~'); - assert.equal(Foo.baz.bitwiseOr(1).operator, '|'); - assert.equal(Foo.baz.bitwiseXor(1).operator, '#'); - assert.equal(Foo.baz.divide(1).operator, '/'); - assert.equal(Foo.baz.modulo(1).operator, '%'); - assert.equal(Foo.baz.regex(1).operator, '~'); - assert.equal(Foo.baz.iregex(1).operator, '~*'); - assert.equal(Foo.baz.notRegex(1).operator, '!~'); - assert.equal(Foo.baz.notIregex(1).operator, '!~*'); - assert.equal(Foo.baz.regexp(1).operator, 'REGEXP'); - assert.equal(Foo.baz.rlike(1).operator, 'RLIKE'); - assert.equal(Foo.baz.ilike('asdf').operator, 'ILIKE'); - assert.equal(Foo.baz.notIlike('asdf').operator, 'NOT ILIKE'); - assert.equal(Foo.baz.match('asdf').operator, '@@'); -}); diff --git a/test/binary-clause-tests.ts b/test/binary-clause-tests.ts new file mode 100644 index 00000000..eafc76b1 --- /dev/null +++ b/test/binary-clause-tests.ts @@ -0,0 +1,40 @@ +import { strictEqual } from 'assert'; +import { Table } from '../dist/lib.js'; + +const Foo = Table.define<{ baz: string; bar: string }>({ + name: 'foo', + columns: ['baz', 'bar'] +}); + +test('operators', function() { + strictEqual(Foo.baz.equals(1).operator, '='); + strictEqual(Foo.baz.notEquals(1).operator, '<>'); + strictEqual(Foo.baz.like('asdf').operator, 'LIKE'); + strictEqual(Foo.baz.notLike('asdf').operator, 'NOT LIKE'); + strictEqual(Foo.baz.isNull().operator, 'IS NULL'); + strictEqual(Foo.baz.isNotNull().operator, 'IS NOT NULL'); + strictEqual(Foo.baz.gt(1).operator, '>'); + strictEqual(Foo.baz.gte(1).operator, '>='); + strictEqual(Foo.baz.lt(1).operator, '<'); + strictEqual(Foo.baz.lte(1).operator, '<='); + strictEqual(Foo.baz.plus(1).operator, '+'); + strictEqual(Foo.baz.minus(1).operator, '-'); + strictEqual(Foo.baz.multiply(1).operator, '*'); + strictEqual(Foo.baz.leftShift(1).operator, '<<'); + strictEqual(Foo.baz.rightShift(1).operator, '>>'); + strictEqual(Foo.baz.bitwiseAnd(1).operator, '&'); + strictEqual(Foo.baz.bitwiseNot(1).operator, '~'); + strictEqual(Foo.baz.bitwiseOr(1).operator, '|'); + strictEqual(Foo.baz.bitwiseXor(1).operator, '#'); + strictEqual(Foo.baz.divide(1).operator, '/'); + strictEqual(Foo.baz.modulo(1).operator, '%'); + strictEqual(Foo.baz.regex(1).operator, '~'); + strictEqual(Foo.baz.iregex(1).operator, '~*'); + strictEqual(Foo.baz.notRegex(1).operator, '!~'); + strictEqual(Foo.baz.notIregex(1).operator, '!~*'); + strictEqual(Foo.baz.regexp(1).operator, 'REGEXP'); + strictEqual(Foo.baz.rlike(1).operator, 'RLIKE'); + strictEqual(Foo.baz.ilike('asdf').operator, 'ILIKE'); + strictEqual(Foo.baz.notIlike('asdf').operator, 'NOT ILIKE'); + strictEqual(Foo.baz.match('asdf').operator, '@@'); +}); diff --git a/test/clause-definition.js b/test/clause-definition.js deleted file mode 100644 index ebbf936d..00000000 --- a/test/clause-definition.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; - -var assert = require('assert'); - -var Node = require(__dirname + '/../lib/node/'); - -var Bang = Node.define({ - type: 'SELECT' -}); - -var Boom = Node.define({ - constructor: function(n) { - Node.call(this); - this.name = n; - } -}); - -test('clause definition', function() { - var select = new Bang(); - assert.equal(select.type, 'SELECT'); - assert.equal(select.nodes.length, 0); - - var q = new Boom('hai'); - assert.equal(q.nodes.length, 0); - var q2 = new Boom('bai'); - q.nodes.push(1); - assert.equal(q.nodes.length, 1); - assert.equal(q.name, 'hai'); - assert.equal(q2.nodes.length, 0); - assert.equal(q2.name, 'bai'); -}); diff --git a/test/clause-definition.ts b/test/clause-definition.ts new file mode 100644 index 00000000..c5445fce --- /dev/null +++ b/test/clause-definition.ts @@ -0,0 +1,33 @@ +/* eslint-disable max-classes-per-file */ +import { strictEqual } from 'assert'; + +import { Node } from '../dist/lib.js'; + +class Bang extends Node { + constructor() { + super('SELECT'); + } +} + +class Boom extends Node { + name: string; + constructor(n: string) { + super('BOOM'); + this.name = n; + } +} + +test('clause definition', function() { + const select = new Bang(); + strictEqual(select.type, 'SELECT'); + strictEqual(select.nodes.length, 0); + + const q = new Boom('hai'); + strictEqual(q.nodes.length, 0); + const q2 = new Boom('bai'); + q.nodes.push(select); + strictEqual(q.nodes.length, 1); + strictEqual(q.name, 'hai'); + strictEqual(q2.nodes.length, 0); + strictEqual(q2.name, 'bai'); +}); diff --git a/test/column-tests.js b/test/column-tests.js deleted file mode 100644 index d0b95a14..00000000 --- a/test/column-tests.js +++ /dev/null @@ -1,131 +0,0 @@ -'use strict'; - -var assert = require('assert'); -var sql = require(__dirname + '/../lib'); - -describe('column', function() { - var table = sql.define({ - name: 'user', - columns: ['id', 'created', 'alias'] - }); - - it('can be accessed by property and array', function() { - assert.equal(table.created, table.columns[1], 'should be able to access created both by array and property'); - }); - - describe('toQuery()', function() { - it('works', function() { - assert.equal(table.id.toQuery().text, '"user"."id"'); - }); - - it('works with a column name of "alias"', function() { - assert.equal(table.alias.toQuery().text, '"user"."alias"'); - }); - - it('respects AS rename', function() { - assert.equal(table.id.as('userId').toQuery().text, '"user"."id" AS "userId"'); - }); - - it('respects count and distinct', function() { - assert.equal(table.id.count().distinct().as("userIdCount").toQuery().text, 'COUNT(DISTINCT("user"."id")) AS "userIdCount"'); - }); - - describe('in subquery with min', function() { - var subquery = table.subQuery('subTable').select(table.id.min().as('subId')); - var col = subquery.subId.toQuery().text; - assert.equal(col, '"subTable"."subId"'); - }); - - describe('property', function() { - var table = sql.define({ - name: 'roundtrip', - columns: { - column_name: { property: 'propertyName' } - } - }); - it('used as alias when !== column name', function() { - assert.equal(table.propertyName.toQuery().text, '"roundtrip"."column_name" AS "propertyName"'); - }); - it('uses explicit alias when !== column name', function() { - assert.equal(table.propertyName.as('alias').toQuery().text, '"roundtrip"."column_name" AS "alias"'); - }); - it('maps to column name in insert', function() { - assert.equal(table.insert({propertyName:'propVal'}).toQuery().text, 'INSERT INTO "roundtrip" ("column_name") VALUES ($1)'); - }); - it('maps to column name in update', function() { - assert.equal(table.update({propertyName:'propVal'}).toQuery().text, 'UPDATE "roundtrip" SET "column_name" = $1'); - }); - it('explicitly selected by *', function() { - assert.equal(table.select(table.star()).from(table).toQuery().text, 'SELECT "roundtrip"."column_name" AS "propertyName" FROM "roundtrip"'); - }); - }); - - describe('autoGenerate', function() { - var table = sql.define({ - name: 'ag', - columns: { - id: {autoGenerated: true}, - name: {} - } - }); - it('does not include auto generated columns in insert', function() { - assert.equal(table.insert({id:0, name:'name'}).toQuery().text,'INSERT INTO "ag" ("name") VALUES ($1)'); - }); - it('does not include auto generated columns in update', function() { - assert.equal(table.update({id:0, name:'name'}).toQuery().text,'UPDATE "ag" SET "name" = $1'); - }); - }); - - describe('white listed', function() { - var table = sql.define({ - name: 'wl', - columnWhiteList: true, - columns: ['id', 'name'] - }); - it('excludes insert properties that are not a column', function() { - assert.equal(table.insert({id:0, _private:'_private', name:'name'}).toQuery().text, 'INSERT INTO "wl" ("id", "name") VALUES ($1, $2)'); - }); - it('excludes update properties that are not a column', function() { - assert.equal(table.update({id:0, _private:'_private', name:'name'}).toQuery().text, 'UPDATE "wl" SET "id" = $1, "name" = $2'); - }); - }); - - describe('not white listed', function() { - var table = sql.define({ - name: 'wl', - columns: ['id', 'name'] - }); - it('throws for insert properties that are not a column', function() { - assert.throws(function() { table.insert({id:0, _private:'_private', name:'name'}); }, Error); - }); - it('throws for update properties that are not a column', function() { - assert.throws(function() { table.update({id:0, _private:'_private', name:'name'}); }, Error); - }); - }); - - describe('snake to camel', function() { - var table = sql.define({ - name: 'sc', - snakeToCamel: true, - columns: { - make_me_camel: {}, - not_to_camel: {property: 'not2Cam'} - } - }); - it('for snake column names with no explicit property name', function(){ - assert.equal(table.makeMeCamel.toQuery().text, '"sc"."make_me_camel" AS "makeMeCamel"'); - }); - it('but not when with explicit property name', function() { - assert.equal(table.not2Cam.toQuery().text, '"sc"."not_to_camel" AS "not2Cam"'); - }); - it('does not use property alias within CASE ... END', function() { - assert.equal(table.makeMeCamel.case([table.makeMeCamel.equals(0)],[table.makeMeCamel]).as('rename').toQuery().text, - '(CASE WHEN ("sc"."make_me_camel" = $1) THEN "sc"."make_me_camel" END) AS "rename"'); - }); - it('respects AS rename in RETURNING clause', function() { - assert.equal(table.update({makeMeCamel:0}).returning(table.makeMeCamel.as('rename')).toQuery().text, - 'UPDATE "sc" SET "make_me_camel" = $1 RETURNING "make_me_camel" AS "rename"'); - }); - }); - }); -}); diff --git a/test/column-tests.ts b/test/column-tests.ts new file mode 100644 index 00000000..dace5ff7 --- /dev/null +++ b/test/column-tests.ts @@ -0,0 +1,172 @@ +import { strictEqual, throws } from 'assert'; +import { Sql } from '../dist/lib.js'; + +const sql = new Sql(); + +suite('column', function() { + test('can be accessed by property and array', function() { + const table = sql.define<{ id: number; created: boolean; alias: string }>({ + name: 'user', + columns: ['id', 'created', 'alias'] + }); + + strictEqual(table.created, table.columns[1], 'should be able to access created both by array and property'); + }); + + suite('toQuery()', function() { + suite('basics', function() { + const table = sql.define<{ id: number; created: boolean; alias: string }>({ + name: 'user', + columns: ['id', 'created', 'alias'] + }); + + test('works', function() { + strictEqual(table.id.toQuery().text, '"user"."id"'); + }); + + test('works with a column name of "alias"', function() { + strictEqual(table.alias.toQuery().text, '"user"."alias"'); + }); + + test('respects AS rename', function() { + strictEqual(table.id.as('userId').toQuery().text, '"user"."id" AS "userId"'); + }); + + test('respects count and distinct', function() { + strictEqual( + table.id + .count() + .distinct() + .as('userIdCount') + .toQuery().text, + 'COUNT(DISTINCT("user"."id")) AS "userIdCount"' + ); + }); + + test('in subquery with min', function() { + const subquery = table.subQuery<{ subId: number }>('subTable').select(table.id.min().as('subId')); + const col = subquery.subId.toQuery().text; + strictEqual(col, '"subTable"."subId"'); + }); + }); + + suite('property', function() { + const table = sql.define<{ propertyName: string }>({ + name: 'roundtrip', + columns: { + column_name: { property: 'propertyName' } + } + }); + test('used as alias when !== column name', function() { + strictEqual(table.propertyName.toQuery().text, '"roundtrip"."column_name" AS "propertyName"'); + }); + test('uses explicit alias when !== column name', function() { + strictEqual(table.propertyName.as('alias').toQuery().text, '"roundtrip"."column_name" AS "alias"'); + }); + test('maps to column name in insert', function() { + strictEqual(table.insert({ propertyName: 'propVal' }).toQuery().text, 'INSERT INTO "roundtrip" ("column_name") VALUES ($1)'); + }); + test('maps to column name in update', function() { + strictEqual(table.update({ propertyName: 'propVal' }).toQuery().text, 'UPDATE "roundtrip" SET "column_name" = $1'); + }); + test('explicitly selected by *', function() { + strictEqual( + table + .select(table.star()) + .from(table) + .toQuery().text, + 'SELECT "roundtrip"."column_name" AS "propertyName" FROM "roundtrip"' + ); + }); + }); + + suite('autoGenerate', function() { + const table = sql.define({ + name: 'ag', + columns: { + id: { autoGenerated: true }, + name: {} + } + }); + test('does not include auto generated columns in insert', function() { + strictEqual(table.insert({ id: 0, name: 'name' }).toQuery().text, 'INSERT INTO "ag" ("name") VALUES ($1)'); + }); + test('does not include auto generated columns in update', function() { + strictEqual(table.update({ id: 0, name: 'name' }).toQuery().text, 'UPDATE "ag" SET "name" = $1'); + }); + }); + + suite('white listed', function() { + const table = sql.define({ + name: 'wl', + columnWhiteList: true, + columns: ['id', 'name'] + }); + test('excludes insert properties that are not a column', function() { + strictEqual( + table.insert({ id: 0, _private: '_private', name: 'name' }).toQuery().text, + 'INSERT INTO "wl" ("id", "name") VALUES ($1, $2)' + ); + }); + test('excludes update properties that are not a column', function() { + // for testing purposes ignore the compile-time error + // @ts-ignore + strictEqual(table.update({ id: 0, _private: '_private', name: 'name' }).toQuery().text, 'UPDATE "wl" SET "id" = $1, "name" = $2'); + }); + }); + + suite('not white listed', function() { + const table = sql.define({ + name: 'wl', + columns: ['id', 'name'] + }); + test('throws for insert properties that are not a column', function() { + throws(function() { + table.insert({ id: 0, _private: '_private', name: 'name' }); + }, Error); + }); + test('throws for update properties that are not a column', function() { + throws(function() { + // for testing purposes ignore the compile-time error + // @ts-ignore + table.update({ id: 0, _private: '_private', name: 'name' }); + }, Error); + }); + }); + + suite('snake to camel', function() { + const table = sql.define<{ makeMeCamel: number; not2Cam: string }>({ + name: 'sc', + snakeToCamel: true, + columns: { + make_me_camel: {}, + not_to_camel: { property: 'not2Cam' } + } + }); + test('for snake column names with no explicit property name', function() { + strictEqual(table.makeMeCamel.toQuery().text, '"sc"."make_me_camel" AS "makeMeCamel"'); + }); + test('but not when with explicit property name', function() { + strictEqual(table.not2Cam.toQuery().text, '"sc"."not_to_camel" AS "not2Cam"'); + }); + test('does not use property alias within CASE ... END', function() { + strictEqual( + table.makeMeCamel + .case([table.makeMeCamel.equals(0)], [table.makeMeCamel]) + .as('rename') + .toQuery().text, + '(CASE WHEN ("sc"."make_me_camel" = $1) THEN "sc"."make_me_camel" END) AS "rename"' + ); + }); + test('respects AS rename in RETURNING clause', function() { + strictEqual( + table + .update({ makeMeCamel: 0 }) + .returning(table.makeMeCamel.as('rename')) + .toQuery().text, + 'UPDATE "sc" SET "make_me_camel" = $1 RETURNING "make_me_camel" AS "rename"' + ); + }); + }); + }); +}); diff --git a/test/dialects/aggregate-tests.js b/test/dialects/aggregate-tests.js deleted file mode 100644 index 59d48d57..00000000 --- a/test/dialects/aggregate-tests.js +++ /dev/null @@ -1,477 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var post = Harness.definePostTable(); -var customerAlias = Harness.defineCustomerAliasTable(); - - -Harness.test({ - query: post.select(post.count()), - pg: { - text : 'SELECT COUNT("post".*) AS "post_count" FROM "post"', - string: 'SELECT COUNT("post".*) AS "post_count" FROM "post"' - }, - sqlite: { - text : 'SELECT COUNT("post".*) AS "post_count" FROM "post"', - string: 'SELECT COUNT("post".*) AS "post_count" FROM "post"' - }, - mysql: { - text : 'SELECT COUNT(*) AS `post_count` FROM `post`', - string: 'SELECT COUNT(*) AS `post_count` FROM `post`' - }, - mssql: { - text : 'SELECT COUNT(*) AS [post_count] FROM [post]', - string: 'SELECT COUNT(*) AS [post_count] FROM [post]' - }, - oracle: { - text : 'SELECT COUNT(*) "post_count" FROM "post"', - string: 'SELECT COUNT(*) "post_count" FROM "post"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.count('post_count')), - pg: { - text : 'SELECT COUNT("post".*) AS "post_count" FROM "post"', - string: 'SELECT COUNT("post".*) AS "post_count" FROM "post"' - }, - sqlite: { - text : 'SELECT COUNT("post".*) AS "post_count" FROM "post"', - string: 'SELECT COUNT("post".*) AS "post_count" FROM "post"' - }, - msyql: { - text : 'SELECT COUNT(*) AS `post_count` FROM `post`', - string: 'SELECT COUNT(*) AS `post_count` FROM `post`' - }, - mssql: { - text : 'SELECT COUNT(*) AS [post_count] FROM [post]', - string: 'SELECT COUNT(*) AS [post_count] FROM [post]' - }, - oracle: { - text : 'SELECT COUNT(*) "post_count" FROM "post"', - string: 'SELECT COUNT(*) "post_count" FROM "post"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.count().as('post_amount')), - pg: { - text : 'SELECT COUNT("post".*) AS "post_amount" FROM "post"', - string: 'SELECT COUNT("post".*) AS "post_amount" FROM "post"' - }, - sqlite: { - text : 'SELECT COUNT("post".*) AS "post_amount" FROM "post"', - string: 'SELECT COUNT("post".*) AS "post_amount" FROM "post"' - }, - mysql: { - text : 'SELECT COUNT(*) AS `post_amount` FROM `post`', - string: 'SELECT COUNT(*) AS `post_amount` FROM `post`' - }, - mssql: { - text : 'SELECT COUNT(*) AS [post_amount] FROM [post]', - string: 'SELECT COUNT(*) AS [post_amount] FROM [post]' - }, - oracle: { - text : 'SELECT COUNT(*) "post_amount" FROM "post"', - string: 'SELECT COUNT(*) "post_amount" FROM "post"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.content.count()), - pg: { - text : 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', - string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' - }, - sqlite: { - text : 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', - string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' - }, - mysql: { - text : 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', - string: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`' - }, - mssql: { - text : 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]', - string: 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]' - }, - oracle: { - text : 'SELECT COUNT("post"."content") "content_count" FROM "post"', - string: 'SELECT COUNT("post"."content") "content_count" FROM "post"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.content.count('content_count')), - pg: { - text : 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', - string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' - }, - sqlite: { - text : 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', - string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' - }, - mysql: { - text : 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', - string: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`' - }, - mssql: { - text : 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]', - string: 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]' - }, - oracle: { - text : 'SELECT COUNT("post"."content") "content_count" FROM "post"', - string: 'SELECT COUNT("post"."content") "content_count" FROM "post"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.content.count().as('content_count')), - pg: { - text : 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', - string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' - }, - sqlite: { - text : 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', - string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' - }, - mysql: { - text : 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', - string: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`' - }, - mssql: { - text : 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]', - string: 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]' - }, - oracle: { - text : 'SELECT COUNT("post"."content") "content_count" FROM "post"', - string: 'SELECT COUNT("post"."content") "content_count" FROM "post"' - }, - params: [] -}); - -Harness.test({ - query: customerAlias.select(customerAlias.count()), - pg: { - text : 'SELECT COUNT("customer".*) AS "customer_count" FROM "customer"', - string: 'SELECT COUNT("customer".*) AS "customer_count" FROM "customer"' - }, - sqlite: { - text : 'SELECT COUNT("customer".*) AS "customer_count" FROM "customer"', - string: 'SELECT COUNT("customer".*) AS "customer_count" FROM "customer"' - }, - mysql: { - text : 'SELECT COUNT(*) AS `customer_count` FROM `customer`', - string: 'SELECT COUNT(*) AS `customer_count` FROM `customer`' - }, - oracle: { - text : 'SELECT COUNT(*) "customer_count" FROM "customer"', - string: 'SELECT COUNT(*) "customer_count" FROM "customer"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.id.min()), - pg: { - text : 'SELECT MIN("post"."id") AS "id_min" FROM "post"', - string: 'SELECT MIN("post"."id") AS "id_min" FROM "post"' - }, - sqlite: { - text : 'SELECT MIN("post"."id") AS "id_min" FROM "post"', - string: 'SELECT MIN("post"."id") AS "id_min" FROM "post"' - }, - mysql: { - text : 'SELECT MIN(`post`.`id`) AS `id_min` FROM `post`', - string: 'SELECT MIN(`post`.`id`) AS `id_min` FROM `post`' - }, - mssql: { - text : 'SELECT MIN([post].[id]) AS [id_min] FROM [post]', - string: 'SELECT MIN([post].[id]) AS [id_min] FROM [post]' - }, - oracle: { - text : 'SELECT MIN("post"."id") "id_min" FROM "post"', - string: 'SELECT MIN("post"."id") "id_min" FROM "post"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.id.min().as('min_id')), - pg: { - text : 'SELECT MIN("post"."id") AS "min_id" FROM "post"', - string: 'SELECT MIN("post"."id") AS "min_id" FROM "post"' - }, - sqlite: { - text : 'SELECT MIN("post"."id") AS "min_id" FROM "post"', - string: 'SELECT MIN("post"."id") AS "min_id" FROM "post"' - }, - mysql: { - text : 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`', - string: 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`' - }, - mssql: { - text : 'SELECT MIN([post].[id]) AS [min_id] FROM [post]', - string: 'SELECT MIN([post].[id]) AS [min_id] FROM [post]' - }, - oracle: { - text : 'SELECT MIN("post"."id") "min_id" FROM "post"', - string: 'SELECT MIN("post"."id") "min_id" FROM "post"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.id.min('min_id')), - pg: { - text : 'SELECT MIN("post"."id") AS "min_id" FROM "post"', - string: 'SELECT MIN("post"."id") AS "min_id" FROM "post"' - }, - sqlite: { - text : 'SELECT MIN("post"."id") AS "min_id" FROM "post"', - string: 'SELECT MIN("post"."id") AS "min_id" FROM "post"' - }, - mysql: { - text : 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`', - string: 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`' - }, - mssql: { - text : 'SELECT MIN([post].[id]) AS [min_id] FROM [post]', - string: 'SELECT MIN([post].[id]) AS [min_id] FROM [post]' - }, - oracle: { - text : 'SELECT MIN("post"."id") "min_id" FROM "post"', - string: 'SELECT MIN("post"."id") "min_id" FROM "post"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.id.max()), - pg: { - text : 'SELECT MAX("post"."id") AS "id_max" FROM "post"', - string: 'SELECT MAX("post"."id") AS "id_max" FROM "post"' - }, - sqlite: { - text : 'SELECT MAX("post"."id") AS "id_max" FROM "post"', - string: 'SELECT MAX("post"."id") AS "id_max" FROM "post"' - }, - mysql: { - text : 'SELECT MAX(`post`.`id`) AS `id_max` FROM `post`', - string: 'SELECT MAX(`post`.`id`) AS `id_max` FROM `post`' - }, - mssql: { - text : 'SELECT MAX([post].[id]) AS [id_max] FROM [post]', - string: 'SELECT MAX([post].[id]) AS [id_max] FROM [post]' - }, - oracle: { - text : 'SELECT MAX("post"."id") "id_max" FROM "post"', - string: 'SELECT MAX("post"."id") "id_max" FROM "post"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.id.max().as('max_id')), - pg: { - text : 'SELECT MAX("post"."id") AS "max_id" FROM "post"', - string: 'SELECT MAX("post"."id") AS "max_id" FROM "post"' - }, - sqlite: { - text : 'SELECT MAX("post"."id") AS "max_id" FROM "post"', - string: 'SELECT MAX("post"."id") AS "max_id" FROM "post"' - }, - mysql: { - text : 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`', - string: 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`' - }, - mssql: { - text : 'SELECT MAX([post].[id]) AS [max_id] FROM [post]', - string: 'SELECT MAX([post].[id]) AS [max_id] FROM [post]' - }, - oracle: { - text : 'SELECT MAX("post"."id") "max_id" FROM "post"', - string: 'SELECT MAX("post"."id") "max_id" FROM "post"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.id.max('max_id')), - pg: { - text : 'SELECT MAX("post"."id") AS "max_id" FROM "post"', - string: 'SELECT MAX("post"."id") AS "max_id" FROM "post"' - }, - sqlite: { - text : 'SELECT MAX("post"."id") AS "max_id" FROM "post"', - string: 'SELECT MAX("post"."id") AS "max_id" FROM "post"' - }, - mysql: { - text : 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`', - string: 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`' - }, - mssql: { - text : 'SELECT MAX([post].[id]) AS [max_id] FROM [post]', - string: 'SELECT MAX([post].[id]) AS [max_id] FROM [post]' - }, - oracle: { - text : 'SELECT MAX("post"."id") "max_id" FROM "post"', - string: 'SELECT MAX("post"."id") "max_id" FROM "post"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.id.sum()), - pg: { - text : 'SELECT SUM("post"."id") AS "id_sum" FROM "post"', - string: 'SELECT SUM("post"."id") AS "id_sum" FROM "post"' - }, - sqlite: { - text : 'SELECT SUM("post"."id") AS "id_sum" FROM "post"', - string: 'SELECT SUM("post"."id") AS "id_sum" FROM "post"' - }, - mysql: { - text : 'SELECT SUM(`post`.`id`) AS `id_sum` FROM `post`', - string: 'SELECT SUM(`post`.`id`) AS `id_sum` FROM `post`' - }, - mssql: { - text : 'SELECT SUM([post].[id]) AS [id_sum] FROM [post]', - string: 'SELECT SUM([post].[id]) AS [id_sum] FROM [post]' - }, - oracle: { - text : 'SELECT SUM("post"."id") "id_sum" FROM "post"', - string: 'SELECT SUM("post"."id") "id_sum" FROM "post"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.id.sum().as('sum_id')), - pg: { - text : 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', - string: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"' - }, - sqlite: { - text : 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', - string: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"' - }, - mysql: { - text : 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`', - string: 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`' - }, - mssql: { - text : 'SELECT SUM([post].[id]) AS [sum_id] FROM [post]', - string: 'SELECT SUM([post].[id]) AS [sum_id] FROM [post]' - }, - oracle: { - text : 'SELECT SUM("post"."id") "sum_id" FROM "post"', - string: 'SELECT SUM("post"."id") "sum_id" FROM "post"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.id.sum('sum_id')), - pg: { - text : 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', - string: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"' - }, - sqlite: { - text : 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', - string: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"' - }, - mysql: { - text : 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`', - string: 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`' - }, - mssql: { - text : 'SELECT SUM([post].[id]) AS [sum_id] FROM [post]', - string: 'SELECT SUM([post].[id]) AS [sum_id] FROM [post]' - }, - oracle: { - text : 'SELECT SUM("post"."id") "sum_id" FROM "post"', - string: 'SELECT SUM("post"."id") "sum_id" FROM "post"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.id.avg()), - pg: { - text : 'SELECT AVG("post"."id") AS "id_avg" FROM "post"', - string: 'SELECT AVG("post"."id") AS "id_avg" FROM "post"' - }, - sqlite: { - text : 'SELECT AVG("post"."id") AS "id_avg" FROM "post"', - string: 'SELECT AVG("post"."id") AS "id_avg" FROM "post"' - }, - mysql: { - text : 'SELECT AVG(`post`.`id`) AS `id_avg` FROM `post`', - string: 'SELECT AVG(`post`.`id`) AS `id_avg` FROM `post`' - }, - mssql: { - text : 'SELECT AVG([post].[id]) AS [id_avg] FROM [post]', - string: 'SELECT AVG([post].[id]) AS [id_avg] FROM [post]' - }, - oracle: { - text : 'SELECT AVG("post"."id") "id_avg" FROM "post"', - string: 'SELECT AVG("post"."id") "id_avg" FROM "post"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.id.avg().as('avg_id')), - pg: { - text : 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', - string: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"' - }, - sqlite: { - text : 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', - string: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"' - }, - mysql: { - text : 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`', - string: 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`' - }, - mssql: { - text : 'SELECT AVG([post].[id]) AS [avg_id] FROM [post]', - string: 'SELECT AVG([post].[id]) AS [avg_id] FROM [post]' - }, - oracle: { - text : 'SELECT AVG("post"."id") "avg_id" FROM "post"', - string: 'SELECT AVG("post"."id") "avg_id" FROM "post"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.id.avg('avg_id')), - pg: { - text : 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', - string: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"' - }, - sqlite: { - text : 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', - string: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"' - }, - mysql: { - text : 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`', - string: 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`' - }, - mssql: { - text : 'SELECT AVG([post].[id]) AS [avg_id] FROM [post]', - string: 'SELECT AVG([post].[id]) AS [avg_id] FROM [post]' - }, - oracle: { - text : 'SELECT AVG("post"."id") "avg_id" FROM "post"', - string: 'SELECT AVG("post"."id") "avg_id" FROM "post"' - }, - params: [] -}); diff --git a/test/dialects/aggregate-tests.ts b/test/dialects/aggregate-tests.ts new file mode 100644 index 00000000..5d7bd605 --- /dev/null +++ b/test/dialects/aggregate-tests.ts @@ -0,0 +1,474 @@ +import * as Harness from './support.js'; +const customerAlias = Harness.defineCustomerAliasTable(); +const post = Harness.definePostTable(); + +Harness.test({ + query: post.select(post.count()), + pg: { + text: 'SELECT COUNT("post".*) AS "post_count" FROM "post"', + string: 'SELECT COUNT("post".*) AS "post_count" FROM "post"' + }, + sqlite: { + text: 'SELECT COUNT("post".*) AS "post_count" FROM "post"', + string: 'SELECT COUNT("post".*) AS "post_count" FROM "post"' + }, + mysql: { + text: 'SELECT COUNT(*) AS `post_count` FROM `post`', + string: 'SELECT COUNT(*) AS `post_count` FROM `post`' + }, + mssql: { + text: 'SELECT COUNT(*) AS [post_count] FROM [post]', + string: 'SELECT COUNT(*) AS [post_count] FROM [post]' + }, + oracle: { + text: 'SELECT COUNT(*) "post_count" FROM "post"', + string: 'SELECT COUNT(*) "post_count" FROM "post"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.count('post_count')), + pg: { + text: 'SELECT COUNT("post".*) AS "post_count" FROM "post"', + string: 'SELECT COUNT("post".*) AS "post_count" FROM "post"' + }, + sqlite: { + text: 'SELECT COUNT("post".*) AS "post_count" FROM "post"', + string: 'SELECT COUNT("post".*) AS "post_count" FROM "post"' + }, + msyql: { + text: 'SELECT COUNT(*) AS `post_count` FROM `post`', + string: 'SELECT COUNT(*) AS `post_count` FROM `post`' + }, + mssql: { + text: 'SELECT COUNT(*) AS [post_count] FROM [post]', + string: 'SELECT COUNT(*) AS [post_count] FROM [post]' + }, + oracle: { + text: 'SELECT COUNT(*) "post_count" FROM "post"', + string: 'SELECT COUNT(*) "post_count" FROM "post"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.count().as('post_amount')), + pg: { + text: 'SELECT COUNT("post".*) AS "post_amount" FROM "post"', + string: 'SELECT COUNT("post".*) AS "post_amount" FROM "post"' + }, + sqlite: { + text: 'SELECT COUNT("post".*) AS "post_amount" FROM "post"', + string: 'SELECT COUNT("post".*) AS "post_amount" FROM "post"' + }, + mysql: { + text: 'SELECT COUNT(*) AS `post_amount` FROM `post`', + string: 'SELECT COUNT(*) AS `post_amount` FROM `post`' + }, + mssql: { + text: 'SELECT COUNT(*) AS [post_amount] FROM [post]', + string: 'SELECT COUNT(*) AS [post_amount] FROM [post]' + }, + oracle: { + text: 'SELECT COUNT(*) "post_amount" FROM "post"', + string: 'SELECT COUNT(*) "post_amount" FROM "post"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.content.count()), + pg: { + text: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' + }, + sqlite: { + text: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' + }, + mysql: { + text: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', + string: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`' + }, + mssql: { + text: 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]', + string: 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]' + }, + oracle: { + text: 'SELECT COUNT("post"."content") "content_count" FROM "post"', + string: 'SELECT COUNT("post"."content") "content_count" FROM "post"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.content.count('content_count')), + pg: { + text: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' + }, + sqlite: { + text: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' + }, + mysql: { + text: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', + string: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`' + }, + mssql: { + text: 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]', + string: 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]' + }, + oracle: { + text: 'SELECT COUNT("post"."content") "content_count" FROM "post"', + string: 'SELECT COUNT("post"."content") "content_count" FROM "post"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.content.count().as('content_count')), + pg: { + text: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' + }, + sqlite: { + text: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' + }, + mysql: { + text: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', + string: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`' + }, + mssql: { + text: 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]', + string: 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]' + }, + oracle: { + text: 'SELECT COUNT("post"."content") "content_count" FROM "post"', + string: 'SELECT COUNT("post"."content") "content_count" FROM "post"' + }, + params: [] +}); + +Harness.test({ + query: customerAlias.select(customerAlias.count()), + pg: { + text: 'SELECT COUNT("customer".*) AS "customer_count" FROM "customer"', + string: 'SELECT COUNT("customer".*) AS "customer_count" FROM "customer"' + }, + sqlite: { + text: 'SELECT COUNT("customer".*) AS "customer_count" FROM "customer"', + string: 'SELECT COUNT("customer".*) AS "customer_count" FROM "customer"' + }, + mysql: { + text: 'SELECT COUNT(*) AS `customer_count` FROM `customer`', + string: 'SELECT COUNT(*) AS `customer_count` FROM `customer`' + }, + oracle: { + text: 'SELECT COUNT(*) "customer_count" FROM "customer"', + string: 'SELECT COUNT(*) "customer_count" FROM "customer"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.id.min()), + pg: { + text: 'SELECT MIN("post"."id") AS "id_min" FROM "post"', + string: 'SELECT MIN("post"."id") AS "id_min" FROM "post"' + }, + sqlite: { + text: 'SELECT MIN("post"."id") AS "id_min" FROM "post"', + string: 'SELECT MIN("post"."id") AS "id_min" FROM "post"' + }, + mysql: { + text: 'SELECT MIN(`post`.`id`) AS `id_min` FROM `post`', + string: 'SELECT MIN(`post`.`id`) AS `id_min` FROM `post`' + }, + mssql: { + text: 'SELECT MIN([post].[id]) AS [id_min] FROM [post]', + string: 'SELECT MIN([post].[id]) AS [id_min] FROM [post]' + }, + oracle: { + text: 'SELECT MIN("post"."id") "id_min" FROM "post"', + string: 'SELECT MIN("post"."id") "id_min" FROM "post"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.id.min().as('min_id')), + pg: { + text: 'SELECT MIN("post"."id") AS "min_id" FROM "post"', + string: 'SELECT MIN("post"."id") AS "min_id" FROM "post"' + }, + sqlite: { + text: 'SELECT MIN("post"."id") AS "min_id" FROM "post"', + string: 'SELECT MIN("post"."id") AS "min_id" FROM "post"' + }, + mysql: { + text: 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`', + string: 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`' + }, + mssql: { + text: 'SELECT MIN([post].[id]) AS [min_id] FROM [post]', + string: 'SELECT MIN([post].[id]) AS [min_id] FROM [post]' + }, + oracle: { + text: 'SELECT MIN("post"."id") "min_id" FROM "post"', + string: 'SELECT MIN("post"."id") "min_id" FROM "post"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.id.min('min_id')), + pg: { + text: 'SELECT MIN("post"."id") AS "min_id" FROM "post"', + string: 'SELECT MIN("post"."id") AS "min_id" FROM "post"' + }, + sqlite: { + text: 'SELECT MIN("post"."id") AS "min_id" FROM "post"', + string: 'SELECT MIN("post"."id") AS "min_id" FROM "post"' + }, + mysql: { + text: 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`', + string: 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`' + }, + mssql: { + text: 'SELECT MIN([post].[id]) AS [min_id] FROM [post]', + string: 'SELECT MIN([post].[id]) AS [min_id] FROM [post]' + }, + oracle: { + text: 'SELECT MIN("post"."id") "min_id" FROM "post"', + string: 'SELECT MIN("post"."id") "min_id" FROM "post"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.id.max()), + pg: { + text: 'SELECT MAX("post"."id") AS "id_max" FROM "post"', + string: 'SELECT MAX("post"."id") AS "id_max" FROM "post"' + }, + sqlite: { + text: 'SELECT MAX("post"."id") AS "id_max" FROM "post"', + string: 'SELECT MAX("post"."id") AS "id_max" FROM "post"' + }, + mysql: { + text: 'SELECT MAX(`post`.`id`) AS `id_max` FROM `post`', + string: 'SELECT MAX(`post`.`id`) AS `id_max` FROM `post`' + }, + mssql: { + text: 'SELECT MAX([post].[id]) AS [id_max] FROM [post]', + string: 'SELECT MAX([post].[id]) AS [id_max] FROM [post]' + }, + oracle: { + text: 'SELECT MAX("post"."id") "id_max" FROM "post"', + string: 'SELECT MAX("post"."id") "id_max" FROM "post"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.id.max().as('max_id')), + pg: { + text: 'SELECT MAX("post"."id") AS "max_id" FROM "post"', + string: 'SELECT MAX("post"."id") AS "max_id" FROM "post"' + }, + sqlite: { + text: 'SELECT MAX("post"."id") AS "max_id" FROM "post"', + string: 'SELECT MAX("post"."id") AS "max_id" FROM "post"' + }, + mysql: { + text: 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`', + string: 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`' + }, + mssql: { + text: 'SELECT MAX([post].[id]) AS [max_id] FROM [post]', + string: 'SELECT MAX([post].[id]) AS [max_id] FROM [post]' + }, + oracle: { + text: 'SELECT MAX("post"."id") "max_id" FROM "post"', + string: 'SELECT MAX("post"."id") "max_id" FROM "post"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.id.max('max_id')), + pg: { + text: 'SELECT MAX("post"."id") AS "max_id" FROM "post"', + string: 'SELECT MAX("post"."id") AS "max_id" FROM "post"' + }, + sqlite: { + text: 'SELECT MAX("post"."id") AS "max_id" FROM "post"', + string: 'SELECT MAX("post"."id") AS "max_id" FROM "post"' + }, + mysql: { + text: 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`', + string: 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`' + }, + mssql: { + text: 'SELECT MAX([post].[id]) AS [max_id] FROM [post]', + string: 'SELECT MAX([post].[id]) AS [max_id] FROM [post]' + }, + oracle: { + text: 'SELECT MAX("post"."id") "max_id" FROM "post"', + string: 'SELECT MAX("post"."id") "max_id" FROM "post"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.id.sum()), + pg: { + text: 'SELECT SUM("post"."id") AS "id_sum" FROM "post"', + string: 'SELECT SUM("post"."id") AS "id_sum" FROM "post"' + }, + sqlite: { + text: 'SELECT SUM("post"."id") AS "id_sum" FROM "post"', + string: 'SELECT SUM("post"."id") AS "id_sum" FROM "post"' + }, + mysql: { + text: 'SELECT SUM(`post`.`id`) AS `id_sum` FROM `post`', + string: 'SELECT SUM(`post`.`id`) AS `id_sum` FROM `post`' + }, + mssql: { + text: 'SELECT SUM([post].[id]) AS [id_sum] FROM [post]', + string: 'SELECT SUM([post].[id]) AS [id_sum] FROM [post]' + }, + oracle: { + text: 'SELECT SUM("post"."id") "id_sum" FROM "post"', + string: 'SELECT SUM("post"."id") "id_sum" FROM "post"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.id.sum().as('sum_id')), + pg: { + text: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', + string: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"' + }, + sqlite: { + text: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', + string: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"' + }, + mysql: { + text: 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`', + string: 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`' + }, + mssql: { + text: 'SELECT SUM([post].[id]) AS [sum_id] FROM [post]', + string: 'SELECT SUM([post].[id]) AS [sum_id] FROM [post]' + }, + oracle: { + text: 'SELECT SUM("post"."id") "sum_id" FROM "post"', + string: 'SELECT SUM("post"."id") "sum_id" FROM "post"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.id.sum('sum_id')), + pg: { + text: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', + string: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"' + }, + sqlite: { + text: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', + string: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"' + }, + mysql: { + text: 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`', + string: 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`' + }, + mssql: { + text: 'SELECT SUM([post].[id]) AS [sum_id] FROM [post]', + string: 'SELECT SUM([post].[id]) AS [sum_id] FROM [post]' + }, + oracle: { + text: 'SELECT SUM("post"."id") "sum_id" FROM "post"', + string: 'SELECT SUM("post"."id") "sum_id" FROM "post"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.id.avg()), + pg: { + text: 'SELECT AVG("post"."id") AS "id_avg" FROM "post"', + string: 'SELECT AVG("post"."id") AS "id_avg" FROM "post"' + }, + sqlite: { + text: 'SELECT AVG("post"."id") AS "id_avg" FROM "post"', + string: 'SELECT AVG("post"."id") AS "id_avg" FROM "post"' + }, + mysql: { + text: 'SELECT AVG(`post`.`id`) AS `id_avg` FROM `post`', + string: 'SELECT AVG(`post`.`id`) AS `id_avg` FROM `post`' + }, + mssql: { + text: 'SELECT AVG([post].[id]) AS [id_avg] FROM [post]', + string: 'SELECT AVG([post].[id]) AS [id_avg] FROM [post]' + }, + oracle: { + text: 'SELECT AVG("post"."id") "id_avg" FROM "post"', + string: 'SELECT AVG("post"."id") "id_avg" FROM "post"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.id.avg().as('avg_id')), + pg: { + text: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', + string: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"' + }, + sqlite: { + text: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', + string: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"' + }, + mysql: { + text: 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`', + string: 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`' + }, + mssql: { + text: 'SELECT AVG([post].[id]) AS [avg_id] FROM [post]', + string: 'SELECT AVG([post].[id]) AS [avg_id] FROM [post]' + }, + oracle: { + text: 'SELECT AVG("post"."id") "avg_id" FROM "post"', + string: 'SELECT AVG("post"."id") "avg_id" FROM "post"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.id.avg('avg_id')), + pg: { + text: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', + string: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"' + }, + sqlite: { + text: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', + string: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"' + }, + mysql: { + text: 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`', + string: 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`' + }, + mssql: { + text: 'SELECT AVG([post].[id]) AS [avg_id] FROM [post]', + string: 'SELECT AVG([post].[id]) AS [avg_id] FROM [post]' + }, + oracle: { + text: 'SELECT AVG("post"."id") "avg_id" FROM "post"', + string: 'SELECT AVG("post"."id") "avg_id" FROM "post"' + }, + params: [] +}); diff --git a/test/dialects/alias-tests.js b/test/dialects/alias-tests.js deleted file mode 100644 index 32db9308..00000000 --- a/test/dialects/alias-tests.js +++ /dev/null @@ -1,122 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var customer = Harness.defineCustomerTable(); -var Sql = require('../../lib').setDialect('postgres'); - -Harness.test({ - query: customer.select(customer.name.isNull().as('nameIsNull')), - pg: { - text : 'SELECT ("customer"."name" IS NULL) AS "nameIsNull" FROM "customer"', - string: 'SELECT ("customer"."name" IS NULL) AS "nameIsNull" FROM "customer"' - }, - sqlite: { - text : 'SELECT ("customer"."name" IS NULL) AS "nameIsNull" FROM "customer"', - string: 'SELECT ("customer"."name" IS NULL) AS "nameIsNull" FROM "customer"' - }, - mysql: { - text : 'SELECT (`customer`.`name` IS NULL) AS `nameIsNull` FROM `customer`', - string: 'SELECT (`customer`.`name` IS NULL) AS `nameIsNull` FROM `customer`' - }, - mssql: { - text : 'SELECT ([customer].[name] IS NULL) AS [nameIsNull] FROM [customer]', - string: 'SELECT ([customer].[name] IS NULL) AS [nameIsNull] FROM [customer]' - }, - oracle: { - text : 'SELECT ("customer"."name" IS NULL) "nameIsNull" FROM "customer"', - string: 'SELECT ("customer"."name" IS NULL) "nameIsNull" FROM "customer"' - }, - params: [] -}); - -Harness.test({ - query: customer.select(customer.name.plus(customer.age).as('nameAndAge')).where(customer.age.gt(10).and(customer.age.lt(20))), - pg: { - text : 'SELECT ("customer"."name" + "customer"."age") AS "nameAndAge" FROM "customer" WHERE (("customer"."age" > $1) AND ("customer"."age" < $2))', - string: 'SELECT ("customer"."name" + "customer"."age") AS "nameAndAge" FROM "customer" WHERE (("customer"."age" > 10) AND ("customer"."age" < 20))' - }, - sqlite: { - text : 'SELECT ("customer"."name" + "customer"."age") AS "nameAndAge" FROM "customer" WHERE (("customer"."age" > $1) AND ("customer"."age" < $2))', - string: 'SELECT ("customer"."name" + "customer"."age") AS "nameAndAge" FROM "customer" WHERE (("customer"."age" > 10) AND ("customer"."age" < 20))' - }, - mysql: { - text : 'SELECT (`customer`.`name` + `customer`.`age`) AS `nameAndAge` FROM `customer` WHERE ((`customer`.`age` > ?) AND (`customer`.`age` < ?))', - string: 'SELECT (`customer`.`name` + `customer`.`age`) AS `nameAndAge` FROM `customer` WHERE ((`customer`.`age` > 10) AND (`customer`.`age` < 20))' - }, - mssql: { - text : 'SELECT ([customer].[name] + [customer].[age]) AS [nameAndAge] FROM [customer] WHERE (([customer].[age] > @1) AND ([customer].[age] < @2))', - string: 'SELECT ([customer].[name] + [customer].[age]) AS [nameAndAge] FROM [customer] WHERE (([customer].[age] > 10) AND ([customer].[age] < 20))' - }, - oracle: { - text : 'SELECT ("customer"."name" + "customer"."age") "nameAndAge" FROM "customer" WHERE (("customer"."age" > :1) AND ("customer"."age" < :2))', - string: 'SELECT ("customer"."name" + "customer"."age") "nameAndAge" FROM "customer" WHERE (("customer"."age" > 10) AND ("customer"."age" < 20))' - }, - params: [10, 20] -}); - -Harness.test({ - query: customer.select(customer.age.between(10, 20).as('ageBetween')), - pg: { - text : 'SELECT ("customer"."age" BETWEEN $1 AND $2) AS "ageBetween" FROM "customer"', - string: 'SELECT ("customer"."age" BETWEEN 10 AND 20) AS "ageBetween" FROM "customer"' - }, - sqlite: { - text : 'SELECT ("customer"."age" BETWEEN $1 AND $2) AS "ageBetween" FROM "customer"', - string: 'SELECT ("customer"."age" BETWEEN 10 AND 20) AS "ageBetween" FROM "customer"' - }, - mysql: { - text : 'SELECT (`customer`.`age` BETWEEN ? AND ?) AS `ageBetween` FROM `customer`', - string: 'SELECT (`customer`.`age` BETWEEN 10 AND 20) AS `ageBetween` FROM `customer`' - }, - mssql: { - text : 'SELECT ([customer].[age] BETWEEN @1 AND @2) AS [ageBetween] FROM [customer]', - string: 'SELECT ([customer].[age] BETWEEN 10 AND 20) AS [ageBetween] FROM [customer]' - }, - oracle: { - text : 'SELECT ("customer"."age" BETWEEN :1 AND :2) "ageBetween" FROM "customer"', - string: 'SELECT ("customer"."age" BETWEEN 10 AND 20) "ageBetween" FROM "customer"' - }, - params: [10, 20] -}); - -Harness.test({ - query: customer.select(Sql.functions.ROUND(customer.age.as('ageBetween'), 2)), - pg: { - text : 'SELECT ROUND("customer"."age", $1) FROM "customer"', - string: 'SELECT ROUND("customer"."age", 2) FROM "customer"' - }, - sqlite: { - text : 'SELECT ROUND("customer"."age", $1) FROM "customer"', - string: 'SELECT ROUND("customer"."age", 2) FROM "customer"' - }, - mysql: { - text : 'SELECT ROUND(`customer`.`age`, ?) FROM `customer`', - string: 'SELECT ROUND(`customer`.`age`, 2) FROM `customer`' - }, - mssql: { - text : 'SELECT ROUND([customer].[age], @1) FROM [customer]', - string: 'SELECT ROUND([customer].[age], 2) FROM [customer]' - }, - oracle: { - text : 'SELECT ROUND("customer"."age", :1) FROM "customer"', - string: 'SELECT ROUND("customer"."age", 2) FROM "customer"' - }, - params: [2] -}); - -Harness.test({ - query: customer.select(customer.age.notBetween(10, 20).as('ageNotBetween')), - pg: { - text : 'SELECT ("customer"."age" NOT BETWEEN $1 AND $2) AS "ageNotBetween" FROM "customer"', - string: 'SELECT ("customer"."age" NOT BETWEEN 10 AND 20) AS "ageNotBetween" FROM "customer"' - }, - sqlite: { - text : 'SELECT ("customer"."age" NOT BETWEEN $1 AND $2) AS "ageNotBetween" FROM "customer"', - string: 'SELECT ("customer"."age" NOT BETWEEN 10 AND 20) AS "ageNotBetween" FROM "customer"' - }, - mysql: { - text : 'SELECT (`customer`.`age` NOT BETWEEN ? AND ?) AS `ageNotBetween` FROM `customer`', - string: 'SELECT (`customer`.`age` NOT BETWEEN 10 AND 20) AS `ageNotBetween` FROM `customer`' - }, - params: [10, 20] -}); diff --git a/test/dialects/alias-tests.ts b/test/dialects/alias-tests.ts new file mode 100644 index 00000000..d010eafa --- /dev/null +++ b/test/dialects/alias-tests.ts @@ -0,0 +1,131 @@ +import * as Harness from './support.js'; +import { Sql } from '../../dist/lib.js'; +const customer = Harness.defineCustomerTable(); +const instance = new Sql('postgres'); + +Harness.test({ + query: customer.select(customer.name.isNull().as('nameIsNull')), + pg: { + text: 'SELECT ("customer"."name" IS NULL) AS "nameIsNull" FROM "customer"', + string: 'SELECT ("customer"."name" IS NULL) AS "nameIsNull" FROM "customer"' + }, + sqlite: { + text: 'SELECT ("customer"."name" IS NULL) AS "nameIsNull" FROM "customer"', + string: 'SELECT ("customer"."name" IS NULL) AS "nameIsNull" FROM "customer"' + }, + mysql: { + text: 'SELECT (`customer`.`name` IS NULL) AS `nameIsNull` FROM `customer`', + string: 'SELECT (`customer`.`name` IS NULL) AS `nameIsNull` FROM `customer`' + }, + mssql: { + text: 'SELECT ([customer].[name] IS NULL) AS [nameIsNull] FROM [customer]', + string: 'SELECT ([customer].[name] IS NULL) AS [nameIsNull] FROM [customer]' + }, + oracle: { + text: 'SELECT ("customer"."name" IS NULL) "nameIsNull" FROM "customer"', + string: 'SELECT ("customer"."name" IS NULL) "nameIsNull" FROM "customer"' + }, + params: [] +}); + +Harness.test({ + query: customer.select(customer.name.plus(customer.age).as('nameAndAge')).where(customer.age.gt(10).and(customer.age.lt(20))), + pg: { + text: + 'SELECT ("customer"."name" + "customer"."age") AS "nameAndAge" FROM "customer" WHERE (("customer"."age" > $1) AND ("customer"."age" < $2))', + string: + 'SELECT ("customer"."name" + "customer"."age") AS "nameAndAge" FROM "customer" WHERE (("customer"."age" > 10) AND ("customer"."age" < 20))' + }, + sqlite: { + text: + 'SELECT ("customer"."name" + "customer"."age") AS "nameAndAge" FROM "customer" WHERE (("customer"."age" > $1) AND ("customer"."age" < $2))', + string: + 'SELECT ("customer"."name" + "customer"."age") AS "nameAndAge" FROM "customer" WHERE (("customer"."age" > 10) AND ("customer"."age" < 20))' + }, + mysql: { + text: + 'SELECT (`customer`.`name` + `customer`.`age`) AS `nameAndAge` FROM `customer` WHERE ((`customer`.`age` > ?) AND (`customer`.`age` < ?))', + string: + 'SELECT (`customer`.`name` + `customer`.`age`) AS `nameAndAge` FROM `customer` WHERE ((`customer`.`age` > 10) AND (`customer`.`age` < 20))' + }, + mssql: { + text: + 'SELECT ([customer].[name] + [customer].[age]) AS [nameAndAge] FROM [customer] WHERE (([customer].[age] > @1) AND ([customer].[age] < @2))', + string: + 'SELECT ([customer].[name] + [customer].[age]) AS [nameAndAge] FROM [customer] WHERE (([customer].[age] > 10) AND ([customer].[age] < 20))' + }, + oracle: { + text: + 'SELECT ("customer"."name" + "customer"."age") "nameAndAge" FROM "customer" WHERE (("customer"."age" > :1) AND ("customer"."age" < :2))', + string: + 'SELECT ("customer"."name" + "customer"."age") "nameAndAge" FROM "customer" WHERE (("customer"."age" > 10) AND ("customer"."age" < 20))' + }, + params: [10, 20] +}); + +Harness.test({ + query: customer.select(customer.age.between(10, 20).as('ageBetween')), + pg: { + text: 'SELECT ("customer"."age" BETWEEN $1 AND $2) AS "ageBetween" FROM "customer"', + string: 'SELECT ("customer"."age" BETWEEN 10 AND 20) AS "ageBetween" FROM "customer"' + }, + sqlite: { + text: 'SELECT ("customer"."age" BETWEEN $1 AND $2) AS "ageBetween" FROM "customer"', + string: 'SELECT ("customer"."age" BETWEEN 10 AND 20) AS "ageBetween" FROM "customer"' + }, + mysql: { + text: 'SELECT (`customer`.`age` BETWEEN ? AND ?) AS `ageBetween` FROM `customer`', + string: 'SELECT (`customer`.`age` BETWEEN 10 AND 20) AS `ageBetween` FROM `customer`' + }, + mssql: { + text: 'SELECT ([customer].[age] BETWEEN @1 AND @2) AS [ageBetween] FROM [customer]', + string: 'SELECT ([customer].[age] BETWEEN 10 AND 20) AS [ageBetween] FROM [customer]' + }, + oracle: { + text: 'SELECT ("customer"."age" BETWEEN :1 AND :2) "ageBetween" FROM "customer"', + string: 'SELECT ("customer"."age" BETWEEN 10 AND 20) "ageBetween" FROM "customer"' + }, + params: [10, 20] +}); + +Harness.test({ + query: customer.select(instance.functions.ROUND(customer.age.as('ageBetween'), 2)), + pg: { + text: 'SELECT ROUND("customer"."age", $1) FROM "customer"', + string: 'SELECT ROUND("customer"."age", 2) FROM "customer"' + }, + sqlite: { + text: 'SELECT ROUND("customer"."age", $1) FROM "customer"', + string: 'SELECT ROUND("customer"."age", 2) FROM "customer"' + }, + mysql: { + text: 'SELECT ROUND(`customer`.`age`, ?) FROM `customer`', + string: 'SELECT ROUND(`customer`.`age`, 2) FROM `customer`' + }, + mssql: { + text: 'SELECT ROUND([customer].[age], @1) FROM [customer]', + string: 'SELECT ROUND([customer].[age], 2) FROM [customer]' + }, + oracle: { + text: 'SELECT ROUND("customer"."age", :1) FROM "customer"', + string: 'SELECT ROUND("customer"."age", 2) FROM "customer"' + }, + params: [2] +}); + +Harness.test({ + query: customer.select(customer.age.notBetween(10, 20).as('ageNotBetween')), + pg: { + text: 'SELECT ("customer"."age" NOT BETWEEN $1 AND $2) AS "ageNotBetween" FROM "customer"', + string: 'SELECT ("customer"."age" NOT BETWEEN 10 AND 20) AS "ageNotBetween" FROM "customer"' + }, + sqlite: { + text: 'SELECT ("customer"."age" NOT BETWEEN $1 AND $2) AS "ageNotBetween" FROM "customer"', + string: 'SELECT ("customer"."age" NOT BETWEEN 10 AND 20) AS "ageNotBetween" FROM "customer"' + }, + mysql: { + text: 'SELECT (`customer`.`age` NOT BETWEEN ? AND ?) AS `ageNotBetween` FROM `customer`', + string: 'SELECT (`customer`.`age` NOT BETWEEN 10 AND 20) AS `ageNotBetween` FROM `customer`' + }, + params: [10, 20] +}); diff --git a/test/dialects/alter-table-tests.js b/test/dialects/alter-table-tests.js deleted file mode 100644 index d050da3d..00000000 --- a/test/dialects/alter-table-tests.js +++ /dev/null @@ -1,338 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var post = Harness.definePostTable(); -var Table = require(__dirname + '/../../lib/table'); - -Harness.test({ - query: post.alter().dropColumn(post.content), - pg: { - text : 'ALTER TABLE "post" DROP COLUMN "content"', - string: 'ALTER TABLE "post" DROP COLUMN "content"' - }, - sqlite: { - text : 'Sqlite cannot drop columns', - throws: true - }, - mysql: { - text : 'ALTER TABLE `post` DROP COLUMN `content`', - string: 'ALTER TABLE `post` DROP COLUMN `content`' - }, - mssql: { - text : 'ALTER TABLE [post] DROP COLUMN [content]', - string: 'ALTER TABLE [post] DROP COLUMN [content]' - }, - oracle: { - text : 'ALTER TABLE "post" DROP ("content")', - string: 'ALTER TABLE "post" DROP ("content")' - }, - params: [] -}); - -Harness.test({ - query: post.alter().dropColumn(post.content).dropColumn(post.userId), - pg: { - text : 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"', - string: 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"' - }, - sqlite: { - text : 'Sqlite cannot drop columns', - throws: true - }, - mysql: { - text : 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`', - string: 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`' - }, - mssql: { - text : 'ALTER TABLE [post] DROP COLUMN [content], [userId]', - string: 'ALTER TABLE [post] DROP COLUMN [content], [userId]' - }, - oracle: { - text : 'ALTER TABLE "post" DROP ("content", "userId")', - string: 'ALTER TABLE "post" DROP ("content", "userId")' - }, - params: [] -}); - -Harness.test({ - query: post.alter().dropColumn('content').dropColumn('userId'), - pg: { - text : 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"', - string: 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"' - }, - sqlite: { - text : 'Sqlite cannot drop columns', - throws: true - }, - mysql: { - text : 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`', - string: 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`' - }, - mssql: { - text : 'ALTER TABLE [post] DROP COLUMN [content], [userId]', - string: 'ALTER TABLE [post] DROP COLUMN [content], [userId]' - }, - oracle: { - text : 'ALTER TABLE "post" DROP ("content", "userId")', - string: 'ALTER TABLE "post" DROP ("content", "userId")' - }, - params: [] -}); - -Harness.test({ - query: post.alter().rename('posts'), - pg: { - text : 'ALTER TABLE "post" RENAME TO "posts"', - string: 'ALTER TABLE "post" RENAME TO "posts"' - }, - sqlite: { - text : 'ALTER TABLE "post" RENAME TO "posts"', - string: 'ALTER TABLE "post" RENAME TO "posts"' - }, - mysql: { - text : 'ALTER TABLE `post` RENAME TO `posts`', - string: 'ALTER TABLE `post` RENAME TO `posts`' - }, - mssql: { - text : 'EXEC sp_rename [post], [posts]', - string: 'EXEC sp_rename [post], [posts]' - }, - params: [] -}); - -var group = Table.define({ - name: 'group', - columns: [{ - name: 'id', - dataType: 'varchar(100)' - }, { - name: 'userId', - dataType: 'varchar(100)' - } - ] -}); - -Harness.test({ - query: group.alter().addColumn(group.id), - pg: { - text : 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)', - string: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)' - }, - sqlite: { - text : 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)', - string: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)' - }, - mysql: { - text : 'ALTER TABLE `group` ADD COLUMN `id` varchar(100)', - string: 'ALTER TABLE `group` ADD COLUMN `id` varchar(100)' - }, - mssql: { - text : 'ALTER TABLE [group] ADD [id] varchar(100)', - string: 'ALTER TABLE [group] ADD [id] varchar(100)' - }, - oracle: { - text : 'ALTER TABLE "group" ADD ("id" varchar(100))', - string: 'ALTER TABLE "group" ADD ("id" varchar(100))' - }, - params: [] -}); - -Harness.test({ - query: group.alter().addColumn(group.id).addColumn(group.userId), - pg: { - text : 'ALTER TABLE "group" ADD COLUMN "id" varchar(100), ADD COLUMN "userId" varchar(100)', - string: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100), ADD COLUMN "userId" varchar(100)' - }, - sqlite: { - text : 'Sqlite cannot add more than one column at a time', - throws: true - }, - mysql: { - text : 'ALTER TABLE `group` ADD COLUMN `id` varchar(100), ADD COLUMN `userId` varchar(100)', - string: 'ALTER TABLE `group` ADD COLUMN `id` varchar(100), ADD COLUMN `userId` varchar(100)' - }, - mssql: { - text : 'ALTER TABLE [group] ADD [id] varchar(100), [userId] varchar(100)', - string: 'ALTER TABLE [group] ADD [id] varchar(100), [userId] varchar(100)' - }, - oracle: { - text : 'ALTER TABLE "group" ADD ("id" varchar(100), "userId" varchar(100))', - string: 'ALTER TABLE "group" ADD ("id" varchar(100), "userId" varchar(100))' - }, - params: [] -}); - -Harness.test({ - query: group.alter().addColumn('id', 'varchar(100)').addColumn('userId', 'varchar(100)'), - pg: { - text : 'ALTER TABLE "group" ADD COLUMN "id" varchar(100), ADD COLUMN "userId" varchar(100)', - string: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100), ADD COLUMN "userId" varchar(100)' - }, - sqlite: { - text : 'Sqlite cannot add more than one column at a time', - throws: true - }, - mysql: { - text : 'ALTER TABLE `group` ADD COLUMN `id` varchar(100), ADD COLUMN `userId` varchar(100)', - string: 'ALTER TABLE `group` ADD COLUMN `id` varchar(100), ADD COLUMN `userId` varchar(100)' - }, - mssql: { - text : 'ALTER TABLE [group] ADD [id] varchar(100), [userId] varchar(100)', - string: 'ALTER TABLE [group] ADD [id] varchar(100), [userId] varchar(100)' - }, - oracle: { - text : 'ALTER TABLE "group" ADD ("id" varchar(100), "userId" varchar(100))', - string: 'ALTER TABLE "group" ADD ("id" varchar(100), "userId" varchar(100))' - }, - params: [] -}); - -Harness.test({ - query: group.alter().renameColumn('userId', 'newUserId'), - pg: { - text : 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"', - string: 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"' - }, - mysql: { - text : 'Mysql requires data type for renaming a column', - throws: true - }, - sqlite: { - text : 'Sqlite cannot rename columns', - throws: true - }, - mssql: { - text : 'EXEC sp_rename \'[group].[userId]\', [newUserId], \'COLUMN\'', - string: 'EXEC sp_rename \'[group].[userId]\', [newUserId], \'COLUMN\'' - }, - params: [] -}); - -Harness.test({ - query: group.alter().renameColumn(group.userId, 'newUserId'), - pg: { - text : 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"', - string: 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"' - }, - sqlite: { - text : 'Sqlite cannot rename columns', - throws: true - }, - mysql: { - text : 'ALTER TABLE `group` CHANGE COLUMN `userId` `newUserId` varchar(100)', - string: 'ALTER TABLE `group` CHANGE COLUMN `userId` `newUserId` varchar(100)' - }, - mssql: { - text : 'EXEC sp_rename \'[group].[userId]\', [newUserId], \'COLUMN\'', - string: 'EXEC sp_rename \'[group].[userId]\', [newUserId], \'COLUMN\'' - }, - params: [] -}); - -Harness.test({ - query: group.alter().renameColumn('userId', group.id), - pg: { - text : 'ALTER TABLE "group" RENAME COLUMN "userId" TO "id"', - string: 'ALTER TABLE "group" RENAME COLUMN "userId" TO "id"' - }, - sqlite: { - text : 'Sqlite cannot rename columns', - throws: true - }, - mysql: { - text : 'ALTER TABLE `group` CHANGE COLUMN `userId` `id` varchar(100)', - string: 'ALTER TABLE `group` CHANGE COLUMN `userId` `id` varchar(100)' - }, - mssql: { - text : 'EXEC sp_rename \'[group].[userId]\', [id], \'COLUMN\'', - string: 'EXEC sp_rename \'[group].[userId]\', [id], \'COLUMN\'' - }, - params: [] -}); - -var UserWithSignature = Table.define({ - name: 'UserWithSignature', - columns: [{ - name: 'Signature', - dataType: "VARCHAR(255) NOT NULL DEFAULT 'Signature'" - } - ] -}); - -Harness.test({ - query: UserWithSignature.alter().renameColumn(UserWithSignature.get('Signature'), 'sig'), - pg: { - text : 'ALTER TABLE "UserWithSignature" RENAME COLUMN "Signature" TO "sig"', - string: 'ALTER TABLE "UserWithSignature" RENAME COLUMN "Signature" TO "sig"' - }, - mysql: { - text : 'ALTER TABLE `UserWithSignature` CHANGE COLUMN `Signature` `sig` VARCHAR(255) NOT NULL DEFAULT \'Signature\'', - string: 'ALTER TABLE `UserWithSignature` CHANGE COLUMN `Signature` `sig` VARCHAR(255) NOT NULL DEFAULT \'Signature\'' - }, - sqlite: { - text : 'Sqlite cannot rename columns', - throws: true - }, - mssql: { - text : 'EXEC sp_rename \'[UserWithSignature].[Signature]\', [sig], \'COLUMN\'', - string: 'EXEC sp_rename \'[UserWithSignature].[Signature]\', [sig], \'COLUMN\'' - } -}); - -var post = Table.define({ - name: 'post', - columns: [{ - name: 'userId', - dataType: 'int', - references: { - table: 'user', - column: 'id' - } - }, { - name: 'picture', - dataType: 'varchar(100)', - references: {} - }] -}); - -Harness.test({ - query: post.alter().addColumn(post.userId), - pg: { - text : 'ALTER TABLE "post" ADD COLUMN "userId" int REFERENCES "user"("id")', - string: 'ALTER TABLE "post" ADD COLUMN "userId" int REFERENCES "user"("id")' - }, - sqlite: { - text : 'ALTER TABLE "post" ADD COLUMN "userId" int REFERENCES "user"("id")', - string: 'ALTER TABLE "post" ADD COLUMN "userId" int REFERENCES "user"("id")' - }, - mysql: { - text : 'ALTER TABLE `post` ADD COLUMN `userId` int REFERENCES `user`(`id`)', - string: 'ALTER TABLE `post` ADD COLUMN `userId` int REFERENCES `user`(`id`)' - }, - oracle: { - text : 'ALTER TABLE "post" ADD ("userId" int REFERENCES "user"("id"))', - string: 'ALTER TABLE "post" ADD ("userId" int REFERENCES "user"("id"))' - }, - params: [] -}); - -Harness.test({ - query: post.alter().addColumn(post.picture), - pg: { - text : 'ALTER TABLE "post" ADD COLUMN "picture" varchar(100)', - string: 'ALTER TABLE "post" ADD COLUMN "picture" varchar(100)' - }, - sqlite: { - text : 'ALTER TABLE "post" ADD COLUMN "picture" varchar(100)', - string: 'ALTER TABLE "post" ADD COLUMN "picture" varchar(100)' - }, - mysql: { - text : 'ALTER TABLE `post` ADD COLUMN `picture` varchar(100)', - string: 'ALTER TABLE `post` ADD COLUMN `picture` varchar(100)' - }, - oracle: { - text : 'ALTER TABLE "post" ADD ("picture" varchar(100))', - string: 'ALTER TABLE "post" ADD ("picture" varchar(100))' - }, - params: [] -}); diff --git a/test/dialects/alter-table-tests.ts b/test/dialects/alter-table-tests.ts new file mode 100644 index 00000000..e4bbf186 --- /dev/null +++ b/test/dialects/alter-table-tests.ts @@ -0,0 +1,354 @@ +import * as Harness from './support.js'; +import { Table } from '../../dist/lib.js'; +const post = Harness.definePostTable(); + +Harness.test({ + query: post.alter().dropColumn(post.content), + pg: { + text: 'ALTER TABLE "post" DROP COLUMN "content"', + string: 'ALTER TABLE "post" DROP COLUMN "content"' + }, + sqlite: { + text: 'Sqlite cannot drop columns', + throws: true + }, + mysql: { + text: 'ALTER TABLE `post` DROP COLUMN `content`', + string: 'ALTER TABLE `post` DROP COLUMN `content`' + }, + mssql: { + text: 'ALTER TABLE [post] DROP COLUMN [content]', + string: 'ALTER TABLE [post] DROP COLUMN [content]' + }, + oracle: { + text: 'ALTER TABLE "post" DROP ("content")', + string: 'ALTER TABLE "post" DROP ("content")' + }, + params: [] +}); + +Harness.test({ + query: post + .alter() + .dropColumn(post.content) + .dropColumn(post.userId), + pg: { + text: 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"', + string: 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"' + }, + sqlite: { + text: 'Sqlite cannot drop columns', + throws: true + }, + mysql: { + text: 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`', + string: 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`' + }, + mssql: { + text: 'ALTER TABLE [post] DROP COLUMN [content], [userId]', + string: 'ALTER TABLE [post] DROP COLUMN [content], [userId]' + }, + oracle: { + text: 'ALTER TABLE "post" DROP ("content", "userId")', + string: 'ALTER TABLE "post" DROP ("content", "userId")' + }, + params: [] +}); + +Harness.test({ + query: post + .alter() + .dropColumn('content') + .dropColumn('userId'), + pg: { + text: 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"', + string: 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"' + }, + sqlite: { + text: 'Sqlite cannot drop columns', + throws: true + }, + mysql: { + text: 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`', + string: 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`' + }, + mssql: { + text: 'ALTER TABLE [post] DROP COLUMN [content], [userId]', + string: 'ALTER TABLE [post] DROP COLUMN [content], [userId]' + }, + oracle: { + text: 'ALTER TABLE "post" DROP ("content", "userId")', + string: 'ALTER TABLE "post" DROP ("content", "userId")' + }, + params: [] +}); + +Harness.test({ + query: post.alter().rename('posts'), + pg: { + text: 'ALTER TABLE "post" RENAME TO "posts"', + string: 'ALTER TABLE "post" RENAME TO "posts"' + }, + sqlite: { + text: 'ALTER TABLE "post" RENAME TO "posts"', + string: 'ALTER TABLE "post" RENAME TO "posts"' + }, + mysql: { + text: 'ALTER TABLE `post` RENAME TO `posts`', + string: 'ALTER TABLE `post` RENAME TO `posts`' + }, + mssql: { + text: 'EXEC sp_rename [post], [posts]', + string: 'EXEC sp_rename [post], [posts]' + }, + params: [] +}); + +const group = Table.define<{ id: string; userId: string }>({ + name: 'group', + columns: [ + { + name: 'id', + dataType: 'varchar(100)' + }, + { + name: 'userId', + dataType: 'varchar(100)' + } + ] +}); + +Harness.test({ + query: group.alter().addColumn(group.id), + pg: { + text: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)', + string: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)' + }, + sqlite: { + text: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)', + string: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)' + }, + mysql: { + text: 'ALTER TABLE `group` ADD COLUMN `id` varchar(100)', + string: 'ALTER TABLE `group` ADD COLUMN `id` varchar(100)' + }, + mssql: { + text: 'ALTER TABLE [group] ADD [id] varchar(100)', + string: 'ALTER TABLE [group] ADD [id] varchar(100)' + }, + oracle: { + text: 'ALTER TABLE "group" ADD ("id" varchar(100))', + string: 'ALTER TABLE "group" ADD ("id" varchar(100))' + }, + params: [] +}); + +Harness.test({ + query: group + .alter() + .addColumn(group.id) + .addColumn(group.userId), + pg: { + text: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100), ADD COLUMN "userId" varchar(100)', + string: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100), ADD COLUMN "userId" varchar(100)' + }, + sqlite: { + text: 'Sqlite cannot add more than one column at a time', + throws: true + }, + mysql: { + text: 'ALTER TABLE `group` ADD COLUMN `id` varchar(100), ADD COLUMN `userId` varchar(100)', + string: 'ALTER TABLE `group` ADD COLUMN `id` varchar(100), ADD COLUMN `userId` varchar(100)' + }, + mssql: { + text: 'ALTER TABLE [group] ADD [id] varchar(100), [userId] varchar(100)', + string: 'ALTER TABLE [group] ADD [id] varchar(100), [userId] varchar(100)' + }, + oracle: { + text: 'ALTER TABLE "group" ADD ("id" varchar(100), "userId" varchar(100))', + string: 'ALTER TABLE "group" ADD ("id" varchar(100), "userId" varchar(100))' + }, + params: [] +}); + +Harness.test({ + query: group + .alter() + .addColumn('id', 'varchar(100)') + .addColumn('userId', 'varchar(100)'), + pg: { + text: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100), ADD COLUMN "userId" varchar(100)', + string: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100), ADD COLUMN "userId" varchar(100)' + }, + sqlite: { + text: 'Sqlite cannot add more than one column at a time', + throws: true + }, + mysql: { + text: 'ALTER TABLE `group` ADD COLUMN `id` varchar(100), ADD COLUMN `userId` varchar(100)', + string: 'ALTER TABLE `group` ADD COLUMN `id` varchar(100), ADD COLUMN `userId` varchar(100)' + }, + mssql: { + text: 'ALTER TABLE [group] ADD [id] varchar(100), [userId] varchar(100)', + string: 'ALTER TABLE [group] ADD [id] varchar(100), [userId] varchar(100)' + }, + oracle: { + text: 'ALTER TABLE "group" ADD ("id" varchar(100), "userId" varchar(100))', + string: 'ALTER TABLE "group" ADD ("id" varchar(100), "userId" varchar(100))' + }, + params: [] +}); + +Harness.test({ + query: group.alter().renameColumn('userId', 'newUserId'), + pg: { + text: 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"', + string: 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"' + }, + mysql: { + text: 'Mysql requires data type for renaming a column', + throws: true + }, + sqlite: { + text: 'Sqlite cannot rename columns', + throws: true + }, + mssql: { + text: "EXEC sp_rename '[group].[userId]', [newUserId], 'COLUMN'", + string: "EXEC sp_rename '[group].[userId]', [newUserId], 'COLUMN'" + }, + params: [] +}); + +Harness.test({ + query: group.alter().renameColumn(group.userId, 'newUserId'), + pg: { + text: 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"', + string: 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"' + }, + sqlite: { + text: 'Sqlite cannot rename columns', + throws: true + }, + mysql: { + text: 'ALTER TABLE `group` CHANGE COLUMN `userId` `newUserId` varchar(100)', + string: 'ALTER TABLE `group` CHANGE COLUMN `userId` `newUserId` varchar(100)' + }, + mssql: { + text: "EXEC sp_rename '[group].[userId]', [newUserId], 'COLUMN'", + string: "EXEC sp_rename '[group].[userId]', [newUserId], 'COLUMN'" + }, + params: [] +}); + +Harness.test({ + query: group.alter().renameColumn('userId', group.id), + pg: { + text: 'ALTER TABLE "group" RENAME COLUMN "userId" TO "id"', + string: 'ALTER TABLE "group" RENAME COLUMN "userId" TO "id"' + }, + sqlite: { + text: 'Sqlite cannot rename columns', + throws: true + }, + mysql: { + text: 'ALTER TABLE `group` CHANGE COLUMN `userId` `id` varchar(100)', + string: 'ALTER TABLE `group` CHANGE COLUMN `userId` `id` varchar(100)' + }, + mssql: { + text: "EXEC sp_rename '[group].[userId]', [id], 'COLUMN'", + string: "EXEC sp_rename '[group].[userId]', [id], 'COLUMN'" + }, + params: [] +}); + +const UserWithSignature = Table.define<{ Signature: string }>({ + name: 'UserWithSignature', + columns: [ + { + name: 'Signature', + dataType: "VARCHAR(255) NOT NULL DEFAULT 'Signature'" + } + ] +}); + +Harness.test({ + query: UserWithSignature.alter().renameColumn(UserWithSignature.get('Signature')!, 'sig'), + pg: { + text: 'ALTER TABLE "UserWithSignature" RENAME COLUMN "Signature" TO "sig"', + string: 'ALTER TABLE "UserWithSignature" RENAME COLUMN "Signature" TO "sig"' + }, + mysql: { + text: "ALTER TABLE `UserWithSignature` CHANGE COLUMN `Signature` `sig` VARCHAR(255) NOT NULL DEFAULT 'Signature'", + string: "ALTER TABLE `UserWithSignature` CHANGE COLUMN `Signature` `sig` VARCHAR(255) NOT NULL DEFAULT 'Signature'" + }, + sqlite: { + text: 'Sqlite cannot rename columns', + throws: true + }, + mssql: { + text: "EXEC sp_rename '[UserWithSignature].[Signature]', [sig], 'COLUMN'", + string: "EXEC sp_rename '[UserWithSignature].[Signature]', [sig], 'COLUMN'" + } +}); + +const post2 = Table.define<{ userId: number; picture: string }>({ + name: 'post', + columns: [ + { + name: 'userId', + dataType: 'int', + references: { + table: 'user', + column: 'id' + } + }, + { + name: 'picture', + dataType: 'varchar(100)', + references: {} + } + ] +}); + +Harness.test({ + query: post2.alter().addColumn(post2.userId), + pg: { + text: 'ALTER TABLE "post" ADD COLUMN "userId" int REFERENCES "user"("id")', + string: 'ALTER TABLE "post" ADD COLUMN "userId" int REFERENCES "user"("id")' + }, + sqlite: { + text: 'ALTER TABLE "post" ADD COLUMN "userId" int REFERENCES "user"("id")', + string: 'ALTER TABLE "post" ADD COLUMN "userId" int REFERENCES "user"("id")' + }, + mysql: { + text: 'ALTER TABLE `post` ADD COLUMN `userId` int REFERENCES `user`(`id`)', + string: 'ALTER TABLE `post` ADD COLUMN `userId` int REFERENCES `user`(`id`)' + }, + oracle: { + text: 'ALTER TABLE "post" ADD ("userId" int REFERENCES "user"("id"))', + string: 'ALTER TABLE "post" ADD ("userId" int REFERENCES "user"("id"))' + }, + params: [] +}); + +Harness.test({ + query: post2.alter().addColumn(post2.picture), + pg: { + text: 'ALTER TABLE "post" ADD COLUMN "picture" varchar(100)', + string: 'ALTER TABLE "post" ADD COLUMN "picture" varchar(100)' + }, + sqlite: { + text: 'ALTER TABLE "post" ADD COLUMN "picture" varchar(100)', + string: 'ALTER TABLE "post" ADD COLUMN "picture" varchar(100)' + }, + mysql: { + text: 'ALTER TABLE `post` ADD COLUMN `picture` varchar(100)', + string: 'ALTER TABLE `post` ADD COLUMN `picture` varchar(100)' + }, + oracle: { + text: 'ALTER TABLE "post" ADD ("picture" varchar(100))', + string: 'ALTER TABLE "post" ADD ("picture" varchar(100))' + }, + params: [] +}); diff --git a/test/dialects/array-tests.js b/test/dialects/array-tests.js deleted file mode 100644 index f4191400..00000000 --- a/test/dialects/array-tests.js +++ /dev/null @@ -1,96 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var post = Harness.definePostTable(); -var Sql = require('../../lib'); - -// Array columns -Harness.test({ - query: post.update({ - tags: post.tags.concat(Sql.array('nodejs')) - }), - pg: { - text : 'UPDATE "post" SET "tags" = ("post"."tags" || ARRAY[$1])', - string: 'UPDATE "post" SET "tags" = ("post"."tags" || ARRAY[\'nodejs\'])' - }, - params: ['nodejs'] -}); - -Harness.test({ - query: post.select( - post.tags.contains(Sql.array('nodejs', 'js')) - ), - pg: { - text : 'SELECT ("post"."tags" @> ARRAY[$1, $2]) FROM "post"', - string: 'SELECT ("post"."tags" @> ARRAY[\'nodejs\', \'js\']) FROM "post"' - }, - params: ['nodejs', 'js'] -}); - -Harness.test({ - query: post.select( - post.tags.containedBy(Sql.array('nodejs', 'js')) - ), - pg: { - text : 'SELECT ("post"."tags" <@ ARRAY[$1, $2]) FROM "post"', - string: 'SELECT ("post"."tags" <@ ARRAY[\'nodejs\', \'js\']) FROM "post"' - }, - params: ['nodejs', 'js'] -}); - -Harness.test({ - query: post.select( - post.tags.overlap(Sql.array('nodejs', 'js')) - ), - pg: { - text : 'SELECT ("post"."tags" && ARRAY[$1, $2]) FROM "post"', - string: 'SELECT ("post"."tags" && ARRAY[\'nodejs\', \'js\']) FROM "post"' - }, - params: ['nodejs', 'js'] -}); - -Harness.test({ - query: post.select(post.tags.slice(2,3)), - pg: { - text : 'SELECT ("post"."tags")[$1:$2] FROM "post"', - string: 'SELECT ("post"."tags")[2:3] FROM "post"' - }, - params: [2, 3] -}); - -Harness.test({ - query: post.select(post.tags.at(2)), - pg: { - text : 'SELECT ("post"."tags")[$1] FROM "post"', - string: 'SELECT ("post"."tags")[2] FROM "post"' - }, - params: [2] -}); - -// Array literals -Harness.test({ - query: post.select(Sql.array(1,2,3)), - pg: { - text : 'SELECT ARRAY[$1, $2, $3] FROM "post"', - string: 'SELECT ARRAY[1, 2, 3] FROM "post"' - }, - params: [1, 2, 3] -}); - -Harness.test({ - query: post.select(Sql.array(1,2,3).slice(2,3)), - pg: { - text : 'SELECT (ARRAY[$1, $2, $3])[$4:$5] FROM "post"', - string: 'SELECT (ARRAY[1, 2, 3])[2:3] FROM "post"' - }, - params: [1,2,3,2,3] -}); - -Harness.test({ - query: post.select(Sql.array(1,2,3).at(2)), - pg: { - text : 'SELECT (ARRAY[$1, $2, $3])[$4] FROM "post"', - string: 'SELECT (ARRAY[1, 2, 3])[2] FROM "post"' - }, - params: [1,2,3,2] -}); diff --git a/test/dialects/array-tests.ts b/test/dialects/array-tests.ts new file mode 100644 index 00000000..528e6b03 --- /dev/null +++ b/test/dialects/array-tests.ts @@ -0,0 +1,98 @@ +import * as Harness from './support.js'; +import { Sql } from '../../dist/lib.js'; +const post = Harness.definePostTable(); +const instance = new Sql('postgres'); + +// Array columns +Harness.test({ + query: post.update({ + tags: post.tags.concat(instance.array('nodejs')) + }), + pg: { + text: 'UPDATE "post" SET "tags" = ("post"."tags" || ARRAY[$1])', + string: 'UPDATE "post" SET "tags" = ("post"."tags" || ARRAY[\'nodejs\'])' + }, + params: ['nodejs'] +}); + +Harness.test({ + query: post.select(post.tags.contains(instance.array('nodejs', 'js'))), + pg: { + text: 'SELECT ("post"."tags" @> ARRAY[$1, $2]) FROM "post"', + string: 'SELECT ("post"."tags" @> ARRAY[\'nodejs\', \'js\']) FROM "post"' + }, + params: ['nodejs', 'js'] +}); + +Harness.test({ + query: post.select(post.tags.containedBy(instance.array('nodejs', 'js'))), + pg: { + text: 'SELECT ("post"."tags" <@ ARRAY[$1, $2]) FROM "post"', + string: 'SELECT ("post"."tags" <@ ARRAY[\'nodejs\', \'js\']) FROM "post"' + }, + params: ['nodejs', 'js'] +}); + +Harness.test({ + query: post.select(post.tags.overlap(instance.array('nodejs', 'js'))), + pg: { + text: 'SELECT ("post"."tags" && ARRAY[$1, $2]) FROM "post"', + string: 'SELECT ("post"."tags" && ARRAY[\'nodejs\', \'js\']) FROM "post"' + }, + params: ['nodejs', 'js'] +}); + +Harness.test({ + query: post.select(post.tags.slice(2, 3)), + pg: { + text: 'SELECT ("post"."tags")[$1:$2] FROM "post"', + string: 'SELECT ("post"."tags")[2:3] FROM "post"' + }, + params: [2, 3] +}); + +Harness.test({ + query: post.select(post.tags.at(2)), + pg: { + text: 'SELECT ("post"."tags")[$1] FROM "post"', + string: 'SELECT ("post"."tags")[2] FROM "post"' + }, + params: [2] +}); + +Harness.test({ + query: post.select(post.tags.overlap(instance.parameter(['nodejs', 'js']))), + pg: { + text: 'SELECT ("post"."tags" && $1) FROM "post"', + string: 'SELECT ("post"."tags" && \'{"nodejs","js"}\') FROM "post"' + }, + params: [['nodejs', 'js']] +}); + +// Array literals +Harness.test({ + query: post.select(instance.array(1, 2, 3)), + pg: { + text: 'SELECT ARRAY[$1, $2, $3] FROM "post"', + string: 'SELECT ARRAY[1, 2, 3] FROM "post"' + }, + params: [1, 2, 3] +}); + +Harness.test({ + query: post.select(instance.array(1, 2, 3).slice(2, 3)), + pg: { + text: 'SELECT (ARRAY[$1, $2, $3])[$4:$5] FROM "post"', + string: 'SELECT (ARRAY[1, 2, 3])[2:3] FROM "post"' + }, + params: [1, 2, 3, 2, 3] +}); + +Harness.test({ + query: post.select(instance.array(1, 2, 3).at(2)), + pg: { + text: 'SELECT (ARRAY[$1, $2, $3])[$4] FROM "post"', + string: 'SELECT (ARRAY[1, 2, 3])[2] FROM "post"' + }, + params: [1, 2, 3, 2] +}); diff --git a/test/dialects/as-of-tests.ts b/test/dialects/as-of-tests.ts new file mode 100644 index 00000000..7f409657 --- /dev/null +++ b/test/dialects/as-of-tests.ts @@ -0,0 +1,32 @@ +import * as Harness from './support.js'; +import { Sql } from '../../dist/lib.js'; +const post = Harness.definePostTable(); +const user = Harness.defineUserTable(); +const instance = new Sql('postgres'); + +Harness.test({ + query: user + .select(user.star()) + .from(user) + .asOf(instance.functions.FOLLOWER_READ_TIMESTAMP()), + pg: { + text: 'SELECT "user".* FROM "user" AS OF SYSTEM TIME FOLLOWER_READ_TIMESTAMP()', + string: 'SELECT "user".* FROM "user" AS OF SYSTEM TIME FOLLOWER_READ_TIMESTAMP()' + }, + oracle: { + text: 'SELECT "user".* FROM "user" AS OF TIMESTAMP FOLLOWER_READ_TIMESTAMP()', + string: 'SELECT "user".* FROM "user" AS OF TIMESTAMP FOLLOWER_READ_TIMESTAMP()' + } +}); + +Harness.test({ + query: user.select(user.star()).from([user, post]).asOf('\'-10s\''), + pg: { + text: 'SELECT "user".* FROM "user" , "post" AS OF SYSTEM TIME \'-10s\'', + string: 'SELECT "user".* FROM "user" , "post" AS OF SYSTEM TIME \'-10s\'' + }, + oracle: { + text: 'SELECT "user".* FROM "user" , "post" AS OF TIMESTAMP \'-10s\'', + string: 'SELECT "user".* FROM "user" , "post" AS OF TIMESTAMP \'-10s\'' + } +}); diff --git a/test/dialects/binary-clause-tests.js b/test/dialects/binary-clause-tests.js deleted file mode 100644 index 69c355fe..00000000 --- a/test/dialects/binary-clause-tests.js +++ /dev/null @@ -1,103 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var customer = Harness.defineCustomerTable(); -var customerAlias = Harness.defineCustomerAliasTable(); -var post = Harness.definePostTable(); - - -Harness.test({ - query: customer.select(customer.name.plus(customer.age)), - pg: { - text : 'SELECT ("customer"."name" + "customer"."age") FROM "customer"', - string: 'SELECT ("customer"."name" + "customer"."age") FROM "customer"' - }, - sqlite: { - text : 'SELECT ("customer"."name" + "customer"."age") FROM "customer"', - string: 'SELECT ("customer"."name" + "customer"."age") FROM "customer"' - }, - mysql: { - text : 'SELECT (`customer`.`name` + `customer`.`age`) FROM `customer`', - string: 'SELECT (`customer`.`name` + `customer`.`age`) FROM `customer`' - }, - mssql: { - text : 'SELECT ([customer].[name] + [customer].[age]) FROM [customer]', - string: 'SELECT ([customer].[name] + [customer].[age]) FROM [customer]' - }, - oracle: { - text : 'SELECT ("customer"."name" + "customer"."age") FROM "customer"', - string: 'SELECT ("customer"."name" + "customer"."age") FROM "customer"' - }, - params: [] -}); - -Harness.test({ - query: customerAlias.select(customerAlias.name_alias.plus(customerAlias.age_alias)), - pg: { - text : 'SELECT ("customer"."name" + "customer"."age") FROM "customer"', - string: 'SELECT ("customer"."name" + "customer"."age") FROM "customer"' - }, - sqlite: { - text : 'SELECT ("customer"."name" + "customer"."age") FROM "customer"', - string: 'SELECT ("customer"."name" + "customer"."age") FROM "customer"' - }, - mysql: { - text : 'SELECT (`customer`.`name` + `customer`.`age`) FROM `customer`', - string: 'SELECT (`customer`.`name` + `customer`.`age`) FROM `customer`' - }, - mssql: { - text : 'SELECT ([customer].[name] + [customer].[age]) FROM [customer]', - string: 'SELECT ([customer].[name] + [customer].[age]) FROM [customer]' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.content.plus('!')).where(post.userId. in (customer.subQuery().select(customer.id))), - pg: { - text : 'SELECT ("post"."content" + $1) FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer"))', - string: 'SELECT ("post"."content" + \'!\') FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer"))' - }, - sqlite: { - text : 'SELECT ("post"."content" + $1) FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer"))', - string: 'SELECT ("post"."content" + \'!\') FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer"))' - }, - mysql: { - text : 'SELECT (`post`.`content` + ?) FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer`))', - string: 'SELECT (`post`.`content` + \'!\') FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer`))' - }, - mssql: { - text : 'SELECT ([post].[content] + @1) FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer]))', - string: 'SELECT ([post].[content] + \'!\') FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer]))' - }, - oracle: { - text : 'SELECT ("post"."content" + :1) FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer"))', - string: 'SELECT ("post"."content" + \'!\') FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer"))' - }, - params: ['!'] -}); - -Harness.test({ - query: post.select(post.id.plus(': ').plus(post.content)).where(post.userId.notIn(customer.subQuery().select(customer.id))), - pg: { - text : 'SELECT (("post"."id" + $1) + "post"."content") FROM "post" WHERE ("post"."userId" NOT IN (SELECT "customer"."id" FROM "customer"))', - string: 'SELECT (("post"."id" + \': \') + "post"."content") FROM "post" WHERE ("post"."userId" NOT IN (SELECT "customer"."id" FROM "customer"))' - }, - sqlite: { - text : 'SELECT (("post"."id" + $1) + "post"."content") FROM "post" WHERE ("post"."userId" NOT IN (SELECT "customer"."id" FROM "customer"))', - string: 'SELECT (("post"."id" + \': \') + "post"."content") FROM "post" WHERE ("post"."userId" NOT IN (SELECT "customer"."id" FROM "customer"))' - }, - mysql: { - text : 'SELECT ((`post`.`id` + ?) + `post`.`content`) FROM `post` WHERE (`post`.`userId` NOT IN (SELECT `customer`.`id` FROM `customer`))', - string: 'SELECT ((`post`.`id` + \': \') + `post`.`content`) FROM `post` WHERE (`post`.`userId` NOT IN (SELECT `customer`.`id` FROM `customer`))' - }, - mssql: { - text : 'SELECT (([post].[id] + @1) + [post].[content]) FROM [post] WHERE ([post].[userId] NOT IN (SELECT [customer].[id] FROM [customer]))', - string: 'SELECT (([post].[id] + \': \') + [post].[content]) FROM [post] WHERE ([post].[userId] NOT IN (SELECT [customer].[id] FROM [customer]))' - }, - oracle: { - text : 'SELECT (("post"."id" + :1) + "post"."content") FROM "post" WHERE ("post"."userId" NOT IN (SELECT "customer"."id" FROM "customer"))', - string: 'SELECT (("post"."id" + \': \') + "post"."content") FROM "post" WHERE ("post"."userId" NOT IN (SELECT "customer"."id" FROM "customer"))' - }, - params: [': '] -}); diff --git a/test/dialects/binary-clause-tests.ts b/test/dialects/binary-clause-tests.ts new file mode 100644 index 00000000..fa33a494 --- /dev/null +++ b/test/dialects/binary-clause-tests.ts @@ -0,0 +1,110 @@ +import * as Harness from './support.js'; +const customer = Harness.defineCustomerTable(); +const customerAlias = Harness.defineCustomerAliasTable(); +const post = Harness.definePostTable(); + +Harness.test({ + query: customer.select(customer.name.plus(customer.age)), + pg: { + text: 'SELECT ("customer"."name" + "customer"."age") FROM "customer"', + string: 'SELECT ("customer"."name" + "customer"."age") FROM "customer"' + }, + sqlite: { + text: 'SELECT ("customer"."name" + "customer"."age") FROM "customer"', + string: 'SELECT ("customer"."name" + "customer"."age") FROM "customer"' + }, + mysql: { + text: 'SELECT (`customer`.`name` + `customer`.`age`) FROM `customer`', + string: 'SELECT (`customer`.`name` + `customer`.`age`) FROM `customer`' + }, + mssql: { + text: 'SELECT ([customer].[name] + [customer].[age]) FROM [customer]', + string: 'SELECT ([customer].[name] + [customer].[age]) FROM [customer]' + }, + oracle: { + text: 'SELECT ("customer"."name" + "customer"."age") FROM "customer"', + string: 'SELECT ("customer"."name" + "customer"."age") FROM "customer"' + }, + params: [] +}); + +Harness.test({ + query: customerAlias.select(customerAlias.name_alias.plus(customerAlias.age_alias)), + pg: { + text: 'SELECT ("customer"."name" + "customer"."age") FROM "customer"', + string: 'SELECT ("customer"."name" + "customer"."age") FROM "customer"' + }, + sqlite: { + text: 'SELECT ("customer"."name" + "customer"."age") FROM "customer"', + string: 'SELECT ("customer"."name" + "customer"."age") FROM "customer"' + }, + mysql: { + text: 'SELECT (`customer`.`name` + `customer`.`age`) FROM `customer`', + string: 'SELECT (`customer`.`name` + `customer`.`age`) FROM `customer`' + }, + mssql: { + text: 'SELECT ([customer].[name] + [customer].[age]) FROM [customer]', + string: 'SELECT ([customer].[name] + [customer].[age]) FROM [customer]' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.content.plus('!')).where(post.userId.in(customer.subQuery().select(customer.id))), + pg: { + text: 'SELECT ("post"."content" + $1) FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer"))', + string: 'SELECT ("post"."content" + \'!\') FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer"))' + }, + sqlite: { + text: 'SELECT ("post"."content" + $1) FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer"))', + string: 'SELECT ("post"."content" + \'!\') FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer"))' + }, + mysql: { + text: 'SELECT (`post`.`content` + ?) FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer`))', + string: "SELECT (`post`.`content` + '!') FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer`))" + }, + mssql: { + text: 'SELECT ([post].[content] + @1) FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer]))', + string: "SELECT ([post].[content] + '!') FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer]))" + }, + oracle: { + text: 'SELECT ("post"."content" + :1) FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer"))', + string: 'SELECT ("post"."content" + \'!\') FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer"))' + }, + params: ['!'] +}); + +Harness.test({ + query: post.select(post.id.plus(': ').plus(post.content)).where(post.userId.notIn(customer.subQuery().select(customer.id))), + pg: { + text: + 'SELECT (("post"."id" + $1) + "post"."content") FROM "post" WHERE ("post"."userId" NOT IN (SELECT "customer"."id" FROM "customer"))', + string: + 'SELECT (("post"."id" + \': \') + "post"."content") FROM "post" WHERE ("post"."userId" NOT IN (SELECT "customer"."id" FROM "customer"))' + }, + sqlite: { + text: + 'SELECT (("post"."id" + $1) + "post"."content") FROM "post" WHERE ("post"."userId" NOT IN (SELECT "customer"."id" FROM "customer"))', + string: + 'SELECT (("post"."id" + \': \') + "post"."content") FROM "post" WHERE ("post"."userId" NOT IN (SELECT "customer"."id" FROM "customer"))' + }, + mysql: { + text: + 'SELECT ((`post`.`id` + ?) + `post`.`content`) FROM `post` WHERE (`post`.`userId` NOT IN (SELECT `customer`.`id` FROM `customer`))', + string: + "SELECT ((`post`.`id` + ': ') + `post`.`content`) FROM `post` WHERE (`post`.`userId` NOT IN (SELECT `customer`.`id` FROM `customer`))" + }, + mssql: { + text: + 'SELECT (([post].[id] + @1) + [post].[content]) FROM [post] WHERE ([post].[userId] NOT IN (SELECT [customer].[id] FROM [customer]))', + string: + "SELECT (([post].[id] + ': ') + [post].[content]) FROM [post] WHERE ([post].[userId] NOT IN (SELECT [customer].[id] FROM [customer]))" + }, + oracle: { + text: + 'SELECT (("post"."id" + :1) + "post"."content") FROM "post" WHERE ("post"."userId" NOT IN (SELECT "customer"."id" FROM "customer"))', + string: + 'SELECT (("post"."id" + \': \') + "post"."content") FROM "post" WHERE ("post"."userId" NOT IN (SELECT "customer"."id" FROM "customer"))' + }, + params: [': '] +}); diff --git a/test/dialects/case-tests.js b/test/dialects/case-tests.js deleted file mode 100644 index f492a4f5..00000000 --- a/test/dialects/case-tests.js +++ /dev/null @@ -1,222 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var customer = Harness.defineCustomerTable(); - -// Check case expression with primary when expressions and else branch. -Harness.test({ - query: customer.select(customer.age.case([true, false], [0, 1], 2)), - pg: { - text : 'SELECT (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE $5 END) FROM "customer"', - string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) FROM "customer"' - }, - sqlite: { - text : 'SELECT (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE $5 END) FROM "customer"', - string: 'SELECT (CASE WHEN 1 THEN 0 WHEN 0 THEN 1 ELSE 2 END) FROM "customer"' - }, - mysql: { - text : 'SELECT (CASE WHEN ? THEN ? WHEN ? THEN ? ELSE ? END) FROM `customer`', - string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) FROM `customer`' - }, - mssql: { - text : 'SELECT (CASE WHEN 1=1 THEN @1 WHEN 0=1 THEN @2 ELSE @3 END) FROM [customer]', - string: 'SELECT (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE 2 END) FROM [customer]', - params: [0, 1, 2] - }, - oracle: { - text : 'SELECT (CASE WHEN 1=1 THEN :1 WHEN 0=1 THEN :2 ELSE :3 END) FROM "customer"', - string: 'SELECT (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE 2 END) FROM "customer"', - params: [0, 1, 2] - }, - params: [true, 0, false, 1, 2] -}); - -// Check case expression as a subexpression. -Harness.test({ - query: customer.select(customer.age.plus(customer.age.case([true, false], [0, 1], 2))), - pg: { - text : 'SELECT ("customer"."age" + (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE $5 END)) FROM "customer"', - string: 'SELECT ("customer"."age" + (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END)) FROM "customer"' - }, - sqlite: { - text : 'SELECT ("customer"."age" + (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE $5 END)) FROM "customer"', - string: 'SELECT ("customer"."age" + (CASE WHEN 1 THEN 0 WHEN 0 THEN 1 ELSE 2 END)) FROM "customer"' - }, - mysql: { - text : 'SELECT (`customer`.`age` + (CASE WHEN ? THEN ? WHEN ? THEN ? ELSE ? END)) FROM `customer`', - string: 'SELECT (`customer`.`age` + (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END)) FROM `customer`' - }, - mssql: { - text : 'SELECT ([customer].[age] + (CASE WHEN 1=1 THEN @1 WHEN 0=1 THEN @2 ELSE @3 END)) FROM [customer]', - string: 'SELECT ([customer].[age] + (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE 2 END)) FROM [customer]', - params: [0, 1, 2] - }, - oracle: { - text : 'SELECT ("customer"."age" + (CASE WHEN 1=1 THEN :1 WHEN 0=1 THEN :2 ELSE :3 END)) FROM "customer"', - string: 'SELECT ("customer"."age" + (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE 2 END)) FROM "customer"', - params: [0, 1, 2] - }, - params: [true, 0, false, 1, 2] -}); - -// Check case expression as subexpression on the left. -Harness.test({ - query: customer.select(customer.age.case([true, false], [0, 1], 2).plus(3)), - pg: { - text : 'SELECT ((CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE $5 END) + $6) FROM "customer"', - string: 'SELECT ((CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) + 3) FROM "customer"', - }, - sqlite: { - text : 'SELECT ((CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE $5 END) + $6) FROM "customer"', - string: 'SELECT ((CASE WHEN 1 THEN 0 WHEN 0 THEN 1 ELSE 2 END) + 3) FROM "customer"' - }, - mysql: { - text : 'SELECT ((CASE WHEN ? THEN ? WHEN ? THEN ? ELSE ? END) + ?) FROM `customer`', - string: 'SELECT ((CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) + 3) FROM `customer`' - }, - mssql: { - text : 'SELECT ((CASE WHEN 1=1 THEN @1 WHEN 0=1 THEN @2 ELSE @3 END) + @4) FROM [customer]', - string: 'SELECT ((CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE 2 END) + 3) FROM [customer]', - params: [0, 1, 2, 3] - }, - oracle: { - text : 'SELECT ((CASE WHEN 1=1 THEN :1 WHEN 0=1 THEN :2 ELSE :3 END) + :4) FROM "customer"', - string: 'SELECT ((CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE 2 END) + 3) FROM "customer"', - params: [0, 1, 2, 3] - }, - params: [true, 0, false, 1, 2, 3] -}); - -// Check case expression with primary when expressions and compound else expression. -Harness.test({ - query: customer.select(customer.age.case([true, false], [0, 1], customer.age.between(10, 20))), - pg: { - text : 'SELECT (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE ("customer"."age" BETWEEN $5 AND $6) END) FROM "customer"', - string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE ("customer"."age" BETWEEN 10 AND 20) END) FROM "customer"', - }, - sqlite: { - text : 'SELECT (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE ("customer"."age" BETWEEN $5 AND $6) END) FROM "customer"', - string: 'SELECT (CASE WHEN 1 THEN 0 WHEN 0 THEN 1 ELSE ("customer"."age" BETWEEN 10 AND 20) END) FROM "customer"' - }, - mysql: { - text : 'SELECT (CASE WHEN ? THEN ? WHEN ? THEN ? ELSE (`customer`.`age` BETWEEN ? AND ?) END) FROM `customer`', - string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE (`customer`.`age` BETWEEN 10 AND 20) END) FROM `customer`' - }, - mssql: { - text : 'SELECT (CASE WHEN 1=1 THEN @1 WHEN 0=1 THEN @2 ELSE ([customer].[age] BETWEEN @3 AND @4) END) FROM [customer]', - string: 'SELECT (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE ([customer].[age] BETWEEN 10 AND 20) END) FROM [customer]', - params: [0, 1, 10, 20] - }, - oracle: { - text : 'SELECT (CASE WHEN 1=1 THEN :1 WHEN 0=1 THEN :2 ELSE ("customer"."age" BETWEEN :3 AND :4) END) FROM "customer"', - string: 'SELECT (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE ("customer"."age" BETWEEN 10 AND 20) END) FROM "customer"', - params: [0, 1, 10, 20] - }, - params: [true, 0, false, 1, 10, 20] -}); - -// Check case expression with primary when expressions without else branch. -Harness.test({ - query: customer.select(customer.age.case([true, false], [0, 1])), - pg: { - text : 'SELECT (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 END) FROM "customer"', - string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 END) FROM "customer"', - }, - sqlite: { - text : 'SELECT (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 END) FROM "customer"', - string: 'SELECT (CASE WHEN 1 THEN 0 WHEN 0 THEN 1 END) FROM "customer"' - }, - mysql: { - text : 'SELECT (CASE WHEN ? THEN ? WHEN ? THEN ? END) FROM `customer`', - string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 END) FROM `customer`' - }, - mssql: { - text : 'SELECT (CASE WHEN 1=1 THEN @1 WHEN 0=1 THEN @2 END) FROM [customer]', - string: 'SELECT (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 END) FROM [customer]', - params: [0, 1] - }, - oracle: { - text : 'SELECT (CASE WHEN 1=1 THEN :1 WHEN 0=1 THEN :2 END) FROM "customer"', - string: 'SELECT (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 END) FROM "customer"', - params: [0, 1] - }, - params: [true, 0, false, 1] -}); - -// Check case expression with compound when expressions and else branch. -Harness.test({ - query: customer.select(customer.age.case([customer.age.in([10, 20, 30]), customer.age.lte(60)], [0, 1], 2)), - pg: { - text : 'SELECT (CASE WHEN ("customer"."age" IN ($1, $2, $3)) THEN $4 WHEN ("customer"."age" <= $5) THEN $6 ELSE $7 END) FROM "customer"', - string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN 0 WHEN ("customer"."age" <= 60) THEN 1 ELSE 2 END) FROM "customer"' - }, - sqlite: { - text : 'SELECT (CASE WHEN ("customer"."age" IN ($1, $2, $3)) THEN $4 WHEN ("customer"."age" <= $5) THEN $6 ELSE $7 END) FROM "customer"', - string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN 0 WHEN ("customer"."age" <= 60) THEN 1 ELSE 2 END) FROM "customer"' - }, - mysql: { - text : 'SELECT (CASE WHEN (`customer`.`age` IN (?, ?, ?)) THEN ? WHEN (`customer`.`age` <= ?) THEN ? ELSE ? END) FROM `customer`', - string: 'SELECT (CASE WHEN (`customer`.`age` IN (10, 20, 30)) THEN 0 WHEN (`customer`.`age` <= 60) THEN 1 ELSE 2 END) FROM `customer`' - }, - mssql: { - text : 'SELECT (CASE WHEN ([customer].[age] IN (@1, @2, @3)) THEN @4 WHEN ([customer].[age] <= @5) THEN @6 ELSE @7 END) FROM [customer]', - string: 'SELECT (CASE WHEN ([customer].[age] IN (10, 20, 30)) THEN 0 WHEN ([customer].[age] <= 60) THEN 1 ELSE 2 END) FROM [customer]' - }, - oracle: { - text : 'SELECT (CASE WHEN ("customer"."age" IN (:1, :2, :3)) THEN :4 WHEN ("customer"."age" <= :5) THEN :6 ELSE :7 END) FROM "customer"', - string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN 0 WHEN ("customer"."age" <= 60) THEN 1 ELSE 2 END) FROM "customer"' - }, - params: [10, 20, 30, 0, 60, 1, 2] -}); - -// Check case expression without else branch. -Harness.test({ - query: customer.select(customer.age.case([customer.age.in([10, 20, 30]), customer.age.lte(60)], [0, 1])), - pg: { - text : 'SELECT (CASE WHEN ("customer"."age" IN ($1, $2, $3)) THEN $4 WHEN ("customer"."age" <= $5) THEN $6 END) FROM "customer"', - string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN 0 WHEN ("customer"."age" <= 60) THEN 1 END) FROM "customer"' - }, - sqlite: { - text : 'SELECT (CASE WHEN ("customer"."age" IN ($1, $2, $3)) THEN $4 WHEN ("customer"."age" <= $5) THEN $6 END) FROM "customer"', - string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN 0 WHEN ("customer"."age" <= 60) THEN 1 END) FROM "customer"' - }, - mysql: { - text : 'SELECT (CASE WHEN (`customer`.`age` IN (?, ?, ?)) THEN ? WHEN (`customer`.`age` <= ?) THEN ? END) FROM `customer`', - string: 'SELECT (CASE WHEN (`customer`.`age` IN (10, 20, 30)) THEN 0 WHEN (`customer`.`age` <= 60) THEN 1 END) FROM `customer`' - }, - mssql: { - text : 'SELECT (CASE WHEN ([customer].[age] IN (@1, @2, @3)) THEN @4 WHEN ([customer].[age] <= @5) THEN @6 END) FROM [customer]', - string: 'SELECT (CASE WHEN ([customer].[age] IN (10, 20, 30)) THEN 0 WHEN ([customer].[age] <= 60) THEN 1 END) FROM [customer]' - }, - oracle: { - text : 'SELECT (CASE WHEN ("customer"."age" IN (:1, :2, :3)) THEN :4 WHEN ("customer"."age" <= :5) THEN :6 END) FROM "customer"', - string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN 0 WHEN ("customer"."age" <= 60) THEN 1 END) FROM "customer"' - }, - params: [10, 20, 30, 0, 60, 1] -}); - -// Check case expression with compound then expressions. -Harness.test({ - query: customer.select(customer.age.case([customer.age.in([10, 20, 30]), customer.age.lte(60)], [customer.age.plus(5), customer.age.minus(1)])), - pg: { - text : 'SELECT (CASE WHEN ("customer"."age" IN ($1, $2, $3)) THEN ("customer"."age" + $4) WHEN ("customer"."age" <= $5) THEN ("customer"."age" - $6) END) FROM "customer"', - string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN ("customer"."age" + 5) WHEN ("customer"."age" <= 60) THEN ("customer"."age" - 1) END) FROM "customer"' - }, - sqlite: { - text : 'SELECT (CASE WHEN ("customer"."age" IN ($1, $2, $3)) THEN ("customer"."age" + $4) WHEN ("customer"."age" <= $5) THEN ("customer"."age" - $6) END) FROM "customer"', - string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN ("customer"."age" + 5) WHEN ("customer"."age" <= 60) THEN ("customer"."age" - 1) END) FROM "customer"' - }, - mysql: { - text : 'SELECT (CASE WHEN (`customer`.`age` IN (?, ?, ?)) THEN (`customer`.`age` + ?) WHEN (`customer`.`age` <= ?) THEN (`customer`.`age` - ?) END) FROM `customer`', - string: 'SELECT (CASE WHEN (`customer`.`age` IN (10, 20, 30)) THEN (`customer`.`age` + 5) WHEN (`customer`.`age` <= 60) THEN (`customer`.`age` - 1) END) FROM `customer`' - }, - mssql: { - text : 'SELECT (CASE WHEN ([customer].[age] IN (@1, @2, @3)) THEN ([customer].[age] + @4) WHEN ([customer].[age] <= @5) THEN ([customer].[age] - @6) END) FROM [customer]', - string: 'SELECT (CASE WHEN ([customer].[age] IN (10, 20, 30)) THEN ([customer].[age] + 5) WHEN ([customer].[age] <= 60) THEN ([customer].[age] - 1) END) FROM [customer]' - }, - oracle: { - text : 'SELECT (CASE WHEN ("customer"."age" IN (:1, :2, :3)) THEN ("customer"."age" + :4) WHEN ("customer"."age" <= :5) THEN ("customer"."age" - :6) END) FROM "customer"', - string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN ("customer"."age" + 5) WHEN ("customer"."age" <= 60) THEN ("customer"."age" - 1) END) FROM "customer"' - }, - params: [10, 20, 30, 5, 60, 1] -}); diff --git a/test/dialects/case-tests.ts b/test/dialects/case-tests.ts new file mode 100644 index 00000000..19b41b60 --- /dev/null +++ b/test/dialects/case-tests.ts @@ -0,0 +1,241 @@ +import * as Harness from './support.js'; +const customer = Harness.defineCustomerTable(); + +// Check case expression with primary when expressions and else branch. +Harness.test({ + query: customer.select(customer.age.case([true, false], [0, 1], 2)), + pg: { + text: 'SELECT (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE $5 END) FROM "customer"', + string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) FROM "customer"' + }, + sqlite: { + text: 'SELECT (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE $5 END) FROM "customer"', + string: 'SELECT (CASE WHEN 1 THEN 0 WHEN 0 THEN 1 ELSE 2 END) FROM "customer"' + }, + mysql: { + text: 'SELECT (CASE WHEN ? THEN ? WHEN ? THEN ? ELSE ? END) FROM `customer`', + string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) FROM `customer`' + }, + mssql: { + text: 'SELECT (CASE WHEN 1=1 THEN @1 WHEN 0=1 THEN @2 ELSE @3 END) FROM [customer]', + string: 'SELECT (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE 2 END) FROM [customer]', + params: [0, 1, 2] + }, + oracle: { + text: 'SELECT (CASE WHEN 1=1 THEN :1 WHEN 0=1 THEN :2 ELSE :3 END) FROM "customer"', + string: 'SELECT (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE 2 END) FROM "customer"', + params: [0, 1, 2] + }, + params: [true, 0, false, 1, 2] +}); + +// Check case expression as a subexpression. +Harness.test({ + query: customer.select(customer.age.plus(customer.age.case([true, false], [0, 1], 2))), + pg: { + text: 'SELECT ("customer"."age" + (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE $5 END)) FROM "customer"', + string: 'SELECT ("customer"."age" + (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END)) FROM "customer"' + }, + sqlite: { + text: 'SELECT ("customer"."age" + (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE $5 END)) FROM "customer"', + string: 'SELECT ("customer"."age" + (CASE WHEN 1 THEN 0 WHEN 0 THEN 1 ELSE 2 END)) FROM "customer"' + }, + mysql: { + text: 'SELECT (`customer`.`age` + (CASE WHEN ? THEN ? WHEN ? THEN ? ELSE ? END)) FROM `customer`', + string: 'SELECT (`customer`.`age` + (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END)) FROM `customer`' + }, + mssql: { + text: 'SELECT ([customer].[age] + (CASE WHEN 1=1 THEN @1 WHEN 0=1 THEN @2 ELSE @3 END)) FROM [customer]', + string: 'SELECT ([customer].[age] + (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE 2 END)) FROM [customer]', + params: [0, 1, 2] + }, + oracle: { + text: 'SELECT ("customer"."age" + (CASE WHEN 1=1 THEN :1 WHEN 0=1 THEN :2 ELSE :3 END)) FROM "customer"', + string: 'SELECT ("customer"."age" + (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE 2 END)) FROM "customer"', + params: [0, 1, 2] + }, + params: [true, 0, false, 1, 2] +}); + +// Check case expression as subexpression on the left. +Harness.test({ + query: customer.select(customer.age.case([true, false], [0, 1], 2).plus(3)), + pg: { + text: 'SELECT ((CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE $5 END) + $6) FROM "customer"', + string: 'SELECT ((CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) + 3) FROM "customer"' + }, + sqlite: { + text: 'SELECT ((CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE $5 END) + $6) FROM "customer"', + string: 'SELECT ((CASE WHEN 1 THEN 0 WHEN 0 THEN 1 ELSE 2 END) + 3) FROM "customer"' + }, + mysql: { + text: 'SELECT ((CASE WHEN ? THEN ? WHEN ? THEN ? ELSE ? END) + ?) FROM `customer`', + string: 'SELECT ((CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) + 3) FROM `customer`' + }, + mssql: { + text: 'SELECT ((CASE WHEN 1=1 THEN @1 WHEN 0=1 THEN @2 ELSE @3 END) + @4) FROM [customer]', + string: 'SELECT ((CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE 2 END) + 3) FROM [customer]', + params: [0, 1, 2, 3] + }, + oracle: { + text: 'SELECT ((CASE WHEN 1=1 THEN :1 WHEN 0=1 THEN :2 ELSE :3 END) + :4) FROM "customer"', + string: 'SELECT ((CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE 2 END) + 3) FROM "customer"', + params: [0, 1, 2, 3] + }, + params: [true, 0, false, 1, 2, 3] +}); + +// Check case expression with primary when expressions and compound else expression. +Harness.test({ + query: customer.select(customer.age.case([true, false], [0, 1], customer.age.between(10, 20))), + pg: { + text: 'SELECT (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE ("customer"."age" BETWEEN $5 AND $6) END) FROM "customer"', + string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE ("customer"."age" BETWEEN 10 AND 20) END) FROM "customer"' + }, + sqlite: { + text: 'SELECT (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE ("customer"."age" BETWEEN $5 AND $6) END) FROM "customer"', + string: 'SELECT (CASE WHEN 1 THEN 0 WHEN 0 THEN 1 ELSE ("customer"."age" BETWEEN 10 AND 20) END) FROM "customer"' + }, + mysql: { + text: 'SELECT (CASE WHEN ? THEN ? WHEN ? THEN ? ELSE (`customer`.`age` BETWEEN ? AND ?) END) FROM `customer`', + string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE (`customer`.`age` BETWEEN 10 AND 20) END) FROM `customer`' + }, + mssql: { + text: 'SELECT (CASE WHEN 1=1 THEN @1 WHEN 0=1 THEN @2 ELSE ([customer].[age] BETWEEN @3 AND @4) END) FROM [customer]', + string: 'SELECT (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE ([customer].[age] BETWEEN 10 AND 20) END) FROM [customer]', + params: [0, 1, 10, 20] + }, + oracle: { + text: 'SELECT (CASE WHEN 1=1 THEN :1 WHEN 0=1 THEN :2 ELSE ("customer"."age" BETWEEN :3 AND :4) END) FROM "customer"', + string: 'SELECT (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE ("customer"."age" BETWEEN 10 AND 20) END) FROM "customer"', + params: [0, 1, 10, 20] + }, + params: [true, 0, false, 1, 10, 20] +}); + +// Check case expression with primary when expressions without else branch. +Harness.test({ + query: customer.select(customer.age.case([true, false], [0, 1])), + pg: { + text: 'SELECT (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 END) FROM "customer"', + string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 END) FROM "customer"' + }, + sqlite: { + text: 'SELECT (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 END) FROM "customer"', + string: 'SELECT (CASE WHEN 1 THEN 0 WHEN 0 THEN 1 END) FROM "customer"' + }, + mysql: { + text: 'SELECT (CASE WHEN ? THEN ? WHEN ? THEN ? END) FROM `customer`', + string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 END) FROM `customer`' + }, + mssql: { + text: 'SELECT (CASE WHEN 1=1 THEN @1 WHEN 0=1 THEN @2 END) FROM [customer]', + string: 'SELECT (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 END) FROM [customer]', + params: [0, 1] + }, + oracle: { + text: 'SELECT (CASE WHEN 1=1 THEN :1 WHEN 0=1 THEN :2 END) FROM "customer"', + string: 'SELECT (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 END) FROM "customer"', + params: [0, 1] + }, + params: [true, 0, false, 1] +}); + +// Check case expression with compound when expressions and else branch. +Harness.test({ + query: customer.select(customer.age.case([customer.age.in([10, 20, 30]), customer.age.lte(60)], [0, 1], 2)), + pg: { + text: + 'SELECT (CASE WHEN ("customer"."age" IN ($1, $2, $3)) THEN $4 WHEN ("customer"."age" <= $5) THEN $6 ELSE $7 END) FROM "customer"', + string: + 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN 0 WHEN ("customer"."age" <= 60) THEN 1 ELSE 2 END) FROM "customer"' + }, + sqlite: { + text: + 'SELECT (CASE WHEN ("customer"."age" IN ($1, $2, $3)) THEN $4 WHEN ("customer"."age" <= $5) THEN $6 ELSE $7 END) FROM "customer"', + string: + 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN 0 WHEN ("customer"."age" <= 60) THEN 1 ELSE 2 END) FROM "customer"' + }, + mysql: { + text: 'SELECT (CASE WHEN (`customer`.`age` IN (?, ?, ?)) THEN ? WHEN (`customer`.`age` <= ?) THEN ? ELSE ? END) FROM `customer`', + string: + 'SELECT (CASE WHEN (`customer`.`age` IN (10, 20, 30)) THEN 0 WHEN (`customer`.`age` <= 60) THEN 1 ELSE 2 END) FROM `customer`' + }, + mssql: { + text: + 'SELECT (CASE WHEN ([customer].[age] IN (@1, @2, @3)) THEN @4 WHEN ([customer].[age] <= @5) THEN @6 ELSE @7 END) FROM [customer]', + string: + 'SELECT (CASE WHEN ([customer].[age] IN (10, 20, 30)) THEN 0 WHEN ([customer].[age] <= 60) THEN 1 ELSE 2 END) FROM [customer]' + }, + oracle: { + text: + 'SELECT (CASE WHEN ("customer"."age" IN (:1, :2, :3)) THEN :4 WHEN ("customer"."age" <= :5) THEN :6 ELSE :7 END) FROM "customer"', + string: + 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN 0 WHEN ("customer"."age" <= 60) THEN 1 ELSE 2 END) FROM "customer"' + }, + params: [10, 20, 30, 0, 60, 1, 2] +}); + +// Check case expression without else branch. +Harness.test({ + query: customer.select(customer.age.case([customer.age.in([10, 20, 30]), customer.age.lte(60)], [0, 1])), + pg: { + text: 'SELECT (CASE WHEN ("customer"."age" IN ($1, $2, $3)) THEN $4 WHEN ("customer"."age" <= $5) THEN $6 END) FROM "customer"', + string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN 0 WHEN ("customer"."age" <= 60) THEN 1 END) FROM "customer"' + }, + sqlite: { + text: 'SELECT (CASE WHEN ("customer"."age" IN ($1, $2, $3)) THEN $4 WHEN ("customer"."age" <= $5) THEN $6 END) FROM "customer"', + string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN 0 WHEN ("customer"."age" <= 60) THEN 1 END) FROM "customer"' + }, + mysql: { + text: 'SELECT (CASE WHEN (`customer`.`age` IN (?, ?, ?)) THEN ? WHEN (`customer`.`age` <= ?) THEN ? END) FROM `customer`', + string: 'SELECT (CASE WHEN (`customer`.`age` IN (10, 20, 30)) THEN 0 WHEN (`customer`.`age` <= 60) THEN 1 END) FROM `customer`' + }, + mssql: { + text: 'SELECT (CASE WHEN ([customer].[age] IN (@1, @2, @3)) THEN @4 WHEN ([customer].[age] <= @5) THEN @6 END) FROM [customer]', + string: 'SELECT (CASE WHEN ([customer].[age] IN (10, 20, 30)) THEN 0 WHEN ([customer].[age] <= 60) THEN 1 END) FROM [customer]' + }, + oracle: { + text: 'SELECT (CASE WHEN ("customer"."age" IN (:1, :2, :3)) THEN :4 WHEN ("customer"."age" <= :5) THEN :6 END) FROM "customer"', + string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN 0 WHEN ("customer"."age" <= 60) THEN 1 END) FROM "customer"' + }, + params: [10, 20, 30, 0, 60, 1] +}); + +// Check case expression with compound then expressions. +Harness.test({ + query: customer.select( + customer.age.case([customer.age.in([10, 20, 30]), customer.age.lte(60)], [customer.age.plus(5), customer.age.minus(1)]) + ), + pg: { + text: + 'SELECT (CASE WHEN ("customer"."age" IN ($1, $2, $3)) THEN ("customer"."age" + $4) WHEN ("customer"."age" <= $5) THEN ("customer"."age" - $6) END) FROM "customer"', + string: + 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN ("customer"."age" + 5) WHEN ("customer"."age" <= 60) THEN ("customer"."age" - 1) END) FROM "customer"' + }, + sqlite: { + text: + 'SELECT (CASE WHEN ("customer"."age" IN ($1, $2, $3)) THEN ("customer"."age" + $4) WHEN ("customer"."age" <= $5) THEN ("customer"."age" - $6) END) FROM "customer"', + string: + 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN ("customer"."age" + 5) WHEN ("customer"."age" <= 60) THEN ("customer"."age" - 1) END) FROM "customer"' + }, + mysql: { + text: + 'SELECT (CASE WHEN (`customer`.`age` IN (?, ?, ?)) THEN (`customer`.`age` + ?) WHEN (`customer`.`age` <= ?) THEN (`customer`.`age` - ?) END) FROM `customer`', + string: + 'SELECT (CASE WHEN (`customer`.`age` IN (10, 20, 30)) THEN (`customer`.`age` + 5) WHEN (`customer`.`age` <= 60) THEN (`customer`.`age` - 1) END) FROM `customer`' + }, + mssql: { + text: + 'SELECT (CASE WHEN ([customer].[age] IN (@1, @2, @3)) THEN ([customer].[age] + @4) WHEN ([customer].[age] <= @5) THEN ([customer].[age] - @6) END) FROM [customer]', + string: + 'SELECT (CASE WHEN ([customer].[age] IN (10, 20, 30)) THEN ([customer].[age] + 5) WHEN ([customer].[age] <= 60) THEN ([customer].[age] - 1) END) FROM [customer]' + }, + oracle: { + text: + 'SELECT (CASE WHEN ("customer"."age" IN (:1, :2, :3)) THEN ("customer"."age" + :4) WHEN ("customer"."age" <= :5) THEN ("customer"."age" - :6) END) FROM "customer"', + string: + 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN ("customer"."age" + 5) WHEN ("customer"."age" <= 60) THEN ("customer"."age" - 1) END) FROM "customer"' + }, + params: [10, 20, 30, 5, 60, 1] +}); diff --git a/test/dialects/cast-tests.js b/test/dialects/cast-tests.js deleted file mode 100644 index 2295d720..00000000 --- a/test/dialects/cast-tests.js +++ /dev/null @@ -1,314 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var customer = Harness.defineCustomerTable(); -var customerAlias = Harness.defineCustomerAliasTable(); - -// Cast columns. -Harness.test({ - query: customer.select(customer.age.cast('int')), - pg: { - text : 'SELECT CAST("customer"."age" AS int) FROM "customer"', - string: 'SELECT CAST("customer"."age" AS int) FROM "customer"' - }, - sqlite: { - text : 'SELECT CAST("customer"."age" AS int) FROM "customer"', - string: 'SELECT CAST("customer"."age" AS int) FROM "customer"' - }, - mysql: { - text : 'SELECT CAST(`customer`.`age` AS int) FROM `customer`', - string: 'SELECT CAST(`customer`.`age` AS int) FROM `customer`' - }, - mssql: { - text : 'SELECT CAST([customer].[age] AS int) FROM [customer]', - string: 'SELECT CAST([customer].[age] AS int) FROM [customer]' - }, - oracle: { - text : 'SELECT CAST("customer"."age" AS int) FROM "customer"', - string: 'SELECT CAST("customer"."age" AS int) FROM "customer"' - }, - params: [] -}); - -Harness.test({ - query: customer.select(customer.name.cast('varchar(10)')), - pg: { - text : 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"', - string: 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"' - }, - sqlite: { - text : 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"', - string: 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"' - }, - mysql: { - text : 'SELECT CAST(`customer`.`name` AS varchar(10)) FROM `customer`', - string: 'SELECT CAST(`customer`.`name` AS varchar(10)) FROM `customer`' - }, - mssql: { - text : 'SELECT CAST([customer].[name] AS varchar(10)) FROM [customer]', - string: 'SELECT CAST([customer].[name] AS varchar(10)) FROM [customer]' - }, - oracle: { - text : 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"', - string: 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"' - }, - params: [] -}); - -// Cast binary expressions. -Harness.test({ - query: customer.select(customer.name.plus(customer.age).cast('varchar(15)')), - pg: { - text : 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"', - string: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"' - }, - sqlite: { - text : 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"', - string: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"' - }, - mysql: { - text : 'SELECT CAST((`customer`.`name` + `customer`.`age`) AS varchar(15)) FROM `customer`', - string: 'SELECT CAST((`customer`.`name` + `customer`.`age`) AS varchar(15)) FROM `customer`' - }, - mssql: { - text : 'SELECT CAST(([customer].[name] + [customer].[age]) AS varchar(15)) FROM [customer]', - string: 'SELECT CAST(([customer].[name] + [customer].[age]) AS varchar(15)) FROM [customer]' - }, - oracle: { - text : 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"', - string: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"' - }, - params: [] -}); - -// Cast cast expressions. -Harness.test({ - query: customer.select(customer.name.cast('varchar(15)').cast('varchar(10)')), - pg: { - text : 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"', - string: 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"' - }, - sqlite: { - text : 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"', - string: 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"' - }, - mysql: { - text : 'SELECT CAST(CAST(`customer`.`name` AS varchar(15)) AS varchar(10)) FROM `customer`', - string: 'SELECT CAST(CAST(`customer`.`name` AS varchar(15)) AS varchar(10)) FROM `customer`' - }, - mssql: { - text : 'SELECT CAST(CAST([customer].[name] AS varchar(15)) AS varchar(10)) FROM [customer]', - string: 'SELECT CAST(CAST([customer].[name] AS varchar(15)) AS varchar(10)) FROM [customer]' - }, - oracle: { - text : 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"', - string: 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"' - }, - params: [] -}); - -// Cast in WHERE. -Harness.test({ - query: customer.select(customer.name).where(customer.age.cast('int').plus(100).equals(150)), - pg: { - text : 'SELECT "customer"."name" FROM "customer" WHERE ((CAST("customer"."age" AS int) + $1) = $2)', - string: 'SELECT "customer"."name" FROM "customer" WHERE ((CAST("customer"."age" AS int) + 100) = 150)' - }, - sqlite: { - text : 'SELECT "customer"."name" FROM "customer" WHERE ((CAST("customer"."age" AS int) + $1) = $2)', - string: 'SELECT "customer"."name" FROM "customer" WHERE ((CAST("customer"."age" AS int) + 100) = 150)' - }, - mysql: { - text : 'SELECT `customer`.`name` FROM `customer` WHERE ((CAST(`customer`.`age` AS int) + ?) = ?)', - string: 'SELECT `customer`.`name` FROM `customer` WHERE ((CAST(`customer`.`age` AS int) + 100) = 150)' - }, - mssql: { - text : 'SELECT [customer].[name] FROM [customer] WHERE ((CAST([customer].[age] AS int) + @1) = @2)', - string: 'SELECT [customer].[name] FROM [customer] WHERE ((CAST([customer].[age] AS int) + 100) = 150)' - }, - oracle: { - text : 'SELECT "customer"."name" FROM "customer" WHERE ((CAST("customer"."age" AS int) + :1) = :2)', - string: 'SELECT "customer"."name" FROM "customer" WHERE ((CAST("customer"."age" AS int) + 100) = 150)' - }, - params: [100, 150] -}); - -// Alias cast. -Harness.test({ - query: customer.select(customer.age.cast('int').as('age_int')), - pg: { - text : 'SELECT CAST("customer"."age" AS int) AS "age_int" FROM "customer"', - string: 'SELECT CAST("customer"."age" AS int) AS "age_int" FROM "customer"' - }, - sqlite: { - text : 'SELECT CAST("customer"."age" AS int) AS "age_int" FROM "customer"', - string: 'SELECT CAST("customer"."age" AS int) AS "age_int" FROM "customer"' - }, - mysql: { - text : 'SELECT CAST(`customer`.`age` AS int) AS `age_int` FROM `customer`', - string: 'SELECT CAST(`customer`.`age` AS int) AS `age_int` FROM `customer`' - }, - mssql: { - text : 'SELECT CAST([customer].[age] AS int) AS [age_int] FROM [customer]', - string: 'SELECT CAST([customer].[age] AS int) AS [age_int] FROM [customer]' - }, - oracle: { - text : 'SELECT CAST("customer"."age" AS int) "age_int" FROM "customer"', - string: 'SELECT CAST("customer"."age" AS int) "age_int" FROM "customer"' - }, - params: [] -}); - -// Cast Aliased columns. -Harness.test({ - query: customerAlias.select(customerAlias.age_alias.cast('int')), - pg: { - text : 'SELECT CAST("customer"."age" AS int) FROM "customer"', - string: 'SELECT CAST("customer"."age" AS int) FROM "customer"' - }, - sqlite: { - text : 'SELECT CAST("customer"."age" AS int) FROM "customer"', - string: 'SELECT CAST("customer"."age" AS int) FROM "customer"' - }, - mysql: { - text : 'SELECT CAST(`customer`.`age` AS int) FROM `customer`', - string: 'SELECT CAST(`customer`.`age` AS int) FROM `customer`' - }, - mssql: { - text : 'SELECT CAST([customer].[age] AS int) FROM [customer]', - string: 'SELECT CAST([customer].[age] AS int) FROM [customer]' - }, - oracle: { - text : 'SELECT CAST("customer"."age" AS int) FROM "customer"', - string: 'SELECT CAST("customer"."age" AS int) FROM "customer"' - }, - params: [] -}); - -Harness.test({ - query: customerAlias.select(customerAlias.name_alias.cast('varchar(10)')), - pg: { - text : 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"', - string: 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"' - }, - sqlite: { - text : 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"', - string: 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"' - }, - mysql: { - text : 'SELECT CAST(`customer`.`name` AS varchar(10)) FROM `customer`', - string: 'SELECT CAST(`customer`.`name` AS varchar(10)) FROM `customer`' - }, - mssql: { - text : 'SELECT CAST([customer].[name] AS varchar(10)) FROM [customer]', - string: 'SELECT CAST([customer].[name] AS varchar(10)) FROM [customer]' - }, - oracle: { - text : 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"', - string: 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"' - }, - params: [] -}); -// Cast binary expressions for Aliased Column. -Harness.test({ - query: customerAlias.select(customerAlias.name_alias.plus(customerAlias.age_alias).cast('varchar(15)')), - pg: { - text : 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"', - string: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"' - }, - sqlite: { - text : 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"', - string: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"' - }, - mysql: { - text : 'SELECT CAST((`customer`.`name` + `customer`.`age`) AS varchar(15)) FROM `customer`', - string: 'SELECT CAST((`customer`.`name` + `customer`.`age`) AS varchar(15)) FROM `customer`' - }, - mssql: { - text : 'SELECT CAST(([customer].[name] + [customer].[age]) AS varchar(15)) FROM [customer]', - string: 'SELECT CAST(([customer].[name] + [customer].[age]) AS varchar(15)) FROM [customer]' - }, - oracle: { - text : 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"', - string: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"' - }, - params: [] -}); - -// Cast cast expressions for aliased columns. -Harness.test({ - query: customerAlias.select(customerAlias.name_alias.cast('varchar(15)').cast('varchar(10)')), - pg: { - text : 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"', - string: 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"' - }, - sqlite: { - text : 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"', - string: 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"' - }, - mysql: { - text : 'SELECT CAST(CAST(`customer`.`name` AS varchar(15)) AS varchar(10)) FROM `customer`', - string: 'SELECT CAST(CAST(`customer`.`name` AS varchar(15)) AS varchar(10)) FROM `customer`' - }, - mssql: { - text : 'SELECT CAST(CAST([customer].[name] AS varchar(15)) AS varchar(10)) FROM [customer]', - string: 'SELECT CAST(CAST([customer].[name] AS varchar(15)) AS varchar(10)) FROM [customer]' - }, - oracle: { - text : 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"', - string: 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"' - }, - params: [] -}); - -// Cast in WHERE for aliased columns. -Harness.test({ - query: customerAlias.select(customerAlias.name_alias).where(customerAlias.age_alias.cast('int').plus(100).equals(150)), - pg: { - text : 'SELECT "customer"."name" AS "name_alias" FROM "customer" WHERE ((CAST("customer"."age" AS int) + $1) = $2)', - string: 'SELECT "customer"."name" AS "name_alias" FROM "customer" WHERE ((CAST("customer"."age" AS int) + 100) = 150)' - }, - sqlite: { - text : 'SELECT "customer"."name" AS "name_alias" FROM "customer" WHERE ((CAST("customer"."age" AS int) + $1) = $2)', - string: 'SELECT "customer"."name" AS "name_alias" FROM "customer" WHERE ((CAST("customer"."age" AS int) + 100) = 150)' - }, - mysql: { - text : 'SELECT `customer`.`name` AS `name_alias` FROM `customer` WHERE ((CAST(`customer`.`age` AS int) + ?) = ?)', - string: 'SELECT `customer`.`name` AS `name_alias` FROM `customer` WHERE ((CAST(`customer`.`age` AS int) + 100) = 150)' - }, - mssql: { - text : 'SELECT [customer].[name] AS [name_alias] FROM [customer] WHERE ((CAST([customer].[age] AS int) + @1) = @2)', - string: 'SELECT [customer].[name] AS [name_alias] FROM [customer] WHERE ((CAST([customer].[age] AS int) + 100) = 150)' - }, - oracle: { - text : 'SELECT "customer"."name" "name_alias" FROM "customer" WHERE ((CAST("customer"."age" AS int) + :1) = :2)', - string: 'SELECT "customer"."name" "name_alias" FROM "customer" WHERE ((CAST("customer"."age" AS int) + 100) = 150)' - }, - params: [100, 150] -}); - -// Alias cast. -Harness.test({ - query: customerAlias.select(customerAlias.age_alias.cast('int').as('age_int')), - pg: { - text : 'SELECT CAST("customer"."age" AS int) AS "age_int" FROM "customer"', - string: 'SELECT CAST("customer"."age" AS int) AS "age_int" FROM "customer"' - }, - sqlite: { - text : 'SELECT CAST("customer"."age" AS int) AS "age_int" FROM "customer"', - string: 'SELECT CAST("customer"."age" AS int) AS "age_int" FROM "customer"' - }, - mysql: { - text : 'SELECT CAST(`customer`.`age` AS int) AS `age_int` FROM `customer`', - string: 'SELECT CAST(`customer`.`age` AS int) AS `age_int` FROM `customer`' - }, - mssql: { - text : 'SELECT CAST([customer].[age] AS int) AS [age_int] FROM [customer]', - string: 'SELECT CAST([customer].[age] AS int) AS [age_int] FROM [customer]' - }, - oracle: { - text : 'SELECT CAST("customer"."age" AS int) "age_int" FROM "customer"', - string: 'SELECT CAST("customer"."age" AS int) "age_int" FROM "customer"' - }, - params: [] -}); diff --git a/test/dialects/cast-tests.ts b/test/dialects/cast-tests.ts new file mode 100644 index 00000000..70fabcfe --- /dev/null +++ b/test/dialects/cast-tests.ts @@ -0,0 +1,322 @@ +import * as Harness from './support.js'; +const customer = Harness.defineCustomerTable(); +const customerAlias = Harness.defineCustomerAliasTable(); + +// Cast columns. +Harness.test({ + query: customer.select(customer.age.cast('int')), + pg: { + text: 'SELECT CAST("customer"."age" AS int) FROM "customer"', + string: 'SELECT CAST("customer"."age" AS int) FROM "customer"' + }, + sqlite: { + text: 'SELECT CAST("customer"."age" AS int) FROM "customer"', + string: 'SELECT CAST("customer"."age" AS int) FROM "customer"' + }, + mysql: { + text: 'SELECT CAST(`customer`.`age` AS int) FROM `customer`', + string: 'SELECT CAST(`customer`.`age` AS int) FROM `customer`' + }, + mssql: { + text: 'SELECT CAST([customer].[age] AS int) FROM [customer]', + string: 'SELECT CAST([customer].[age] AS int) FROM [customer]' + }, + oracle: { + text: 'SELECT CAST("customer"."age" AS int) FROM "customer"', + string: 'SELECT CAST("customer"."age" AS int) FROM "customer"' + }, + params: [] +}); + +Harness.test({ + query: customer.select(customer.name.cast('varchar(10)')), + pg: { + text: 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"', + string: 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"' + }, + sqlite: { + text: 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"', + string: 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"' + }, + mysql: { + text: 'SELECT CAST(`customer`.`name` AS varchar(10)) FROM `customer`', + string: 'SELECT CAST(`customer`.`name` AS varchar(10)) FROM `customer`' + }, + mssql: { + text: 'SELECT CAST([customer].[name] AS varchar(10)) FROM [customer]', + string: 'SELECT CAST([customer].[name] AS varchar(10)) FROM [customer]' + }, + oracle: { + text: 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"', + string: 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"' + }, + params: [] +}); + +// Cast binary expressions. +Harness.test({ + query: customer.select(customer.name.plus(customer.age).cast('varchar(15)')), + pg: { + text: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"', + string: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"' + }, + sqlite: { + text: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"', + string: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"' + }, + mysql: { + text: 'SELECT CAST((`customer`.`name` + `customer`.`age`) AS varchar(15)) FROM `customer`', + string: 'SELECT CAST((`customer`.`name` + `customer`.`age`) AS varchar(15)) FROM `customer`' + }, + mssql: { + text: 'SELECT CAST(([customer].[name] + [customer].[age]) AS varchar(15)) FROM [customer]', + string: 'SELECT CAST(([customer].[name] + [customer].[age]) AS varchar(15)) FROM [customer]' + }, + oracle: { + text: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"', + string: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"' + }, + params: [] +}); + +// Cast cast expressions. +Harness.test({ + query: customer.select(customer.name.cast('varchar(15)').cast('varchar(10)')), + pg: { + text: 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"', + string: 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"' + }, + sqlite: { + text: 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"', + string: 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"' + }, + mysql: { + text: 'SELECT CAST(CAST(`customer`.`name` AS varchar(15)) AS varchar(10)) FROM `customer`', + string: 'SELECT CAST(CAST(`customer`.`name` AS varchar(15)) AS varchar(10)) FROM `customer`' + }, + mssql: { + text: 'SELECT CAST(CAST([customer].[name] AS varchar(15)) AS varchar(10)) FROM [customer]', + string: 'SELECT CAST(CAST([customer].[name] AS varchar(15)) AS varchar(10)) FROM [customer]' + }, + oracle: { + text: 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"', + string: 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"' + }, + params: [] +}); + +// Cast in WHERE. +Harness.test({ + query: customer.select(customer.name).where( + customer.age + .cast('int') + .plus(100) + .equals(150) + ), + pg: { + text: 'SELECT "customer"."name" FROM "customer" WHERE ((CAST("customer"."age" AS int) + $1) = $2)', + string: 'SELECT "customer"."name" FROM "customer" WHERE ((CAST("customer"."age" AS int) + 100) = 150)' + }, + sqlite: { + text: 'SELECT "customer"."name" FROM "customer" WHERE ((CAST("customer"."age" AS int) + $1) = $2)', + string: 'SELECT "customer"."name" FROM "customer" WHERE ((CAST("customer"."age" AS int) + 100) = 150)' + }, + mysql: { + text: 'SELECT `customer`.`name` FROM `customer` WHERE ((CAST(`customer`.`age` AS int) + ?) = ?)', + string: 'SELECT `customer`.`name` FROM `customer` WHERE ((CAST(`customer`.`age` AS int) + 100) = 150)' + }, + mssql: { + text: 'SELECT [customer].[name] FROM [customer] WHERE ((CAST([customer].[age] AS int) + @1) = @2)', + string: 'SELECT [customer].[name] FROM [customer] WHERE ((CAST([customer].[age] AS int) + 100) = 150)' + }, + oracle: { + text: 'SELECT "customer"."name" FROM "customer" WHERE ((CAST("customer"."age" AS int) + :1) = :2)', + string: 'SELECT "customer"."name" FROM "customer" WHERE ((CAST("customer"."age" AS int) + 100) = 150)' + }, + params: [100, 150] +}); + +// Alias cast. +Harness.test({ + query: customer.select(customer.age.cast('int').as('age_int')), + pg: { + text: 'SELECT CAST("customer"."age" AS int) AS "age_int" FROM "customer"', + string: 'SELECT CAST("customer"."age" AS int) AS "age_int" FROM "customer"' + }, + sqlite: { + text: 'SELECT CAST("customer"."age" AS int) AS "age_int" FROM "customer"', + string: 'SELECT CAST("customer"."age" AS int) AS "age_int" FROM "customer"' + }, + mysql: { + text: 'SELECT CAST(`customer`.`age` AS int) AS `age_int` FROM `customer`', + string: 'SELECT CAST(`customer`.`age` AS int) AS `age_int` FROM `customer`' + }, + mssql: { + text: 'SELECT CAST([customer].[age] AS int) AS [age_int] FROM [customer]', + string: 'SELECT CAST([customer].[age] AS int) AS [age_int] FROM [customer]' + }, + oracle: { + text: 'SELECT CAST("customer"."age" AS int) "age_int" FROM "customer"', + string: 'SELECT CAST("customer"."age" AS int) "age_int" FROM "customer"' + }, + params: [] +}); + +// Cast Aliased columns. +Harness.test({ + query: customerAlias.select(customerAlias.age_alias.cast('int')), + pg: { + text: 'SELECT CAST("customer"."age" AS int) FROM "customer"', + string: 'SELECT CAST("customer"."age" AS int) FROM "customer"' + }, + sqlite: { + text: 'SELECT CAST("customer"."age" AS int) FROM "customer"', + string: 'SELECT CAST("customer"."age" AS int) FROM "customer"' + }, + mysql: { + text: 'SELECT CAST(`customer`.`age` AS int) FROM `customer`', + string: 'SELECT CAST(`customer`.`age` AS int) FROM `customer`' + }, + mssql: { + text: 'SELECT CAST([customer].[age] AS int) FROM [customer]', + string: 'SELECT CAST([customer].[age] AS int) FROM [customer]' + }, + oracle: { + text: 'SELECT CAST("customer"."age" AS int) FROM "customer"', + string: 'SELECT CAST("customer"."age" AS int) FROM "customer"' + }, + params: [] +}); + +Harness.test({ + query: customerAlias.select(customerAlias.name_alias.cast('varchar(10)')), + pg: { + text: 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"', + string: 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"' + }, + sqlite: { + text: 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"', + string: 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"' + }, + mysql: { + text: 'SELECT CAST(`customer`.`name` AS varchar(10)) FROM `customer`', + string: 'SELECT CAST(`customer`.`name` AS varchar(10)) FROM `customer`' + }, + mssql: { + text: 'SELECT CAST([customer].[name] AS varchar(10)) FROM [customer]', + string: 'SELECT CAST([customer].[name] AS varchar(10)) FROM [customer]' + }, + oracle: { + text: 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"', + string: 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"' + }, + params: [] +}); +// Cast binary expressions for Aliased Column. +Harness.test({ + query: customerAlias.select(customerAlias.name_alias.plus(customerAlias.age_alias).cast('varchar(15)')), + pg: { + text: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"', + string: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"' + }, + sqlite: { + text: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"', + string: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"' + }, + mysql: { + text: 'SELECT CAST((`customer`.`name` + `customer`.`age`) AS varchar(15)) FROM `customer`', + string: 'SELECT CAST((`customer`.`name` + `customer`.`age`) AS varchar(15)) FROM `customer`' + }, + mssql: { + text: 'SELECT CAST(([customer].[name] + [customer].[age]) AS varchar(15)) FROM [customer]', + string: 'SELECT CAST(([customer].[name] + [customer].[age]) AS varchar(15)) FROM [customer]' + }, + oracle: { + text: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"', + string: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"' + }, + params: [] +}); + +// Cast cast expressions for aliased columns. +Harness.test({ + query: customerAlias.select(customerAlias.name_alias.cast('varchar(15)').cast('varchar(10)')), + pg: { + text: 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"', + string: 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"' + }, + sqlite: { + text: 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"', + string: 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"' + }, + mysql: { + text: 'SELECT CAST(CAST(`customer`.`name` AS varchar(15)) AS varchar(10)) FROM `customer`', + string: 'SELECT CAST(CAST(`customer`.`name` AS varchar(15)) AS varchar(10)) FROM `customer`' + }, + mssql: { + text: 'SELECT CAST(CAST([customer].[name] AS varchar(15)) AS varchar(10)) FROM [customer]', + string: 'SELECT CAST(CAST([customer].[name] AS varchar(15)) AS varchar(10)) FROM [customer]' + }, + oracle: { + text: 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"', + string: 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"' + }, + params: [] +}); + +// Cast in WHERE for aliased columns. +Harness.test({ + query: customerAlias.select(customerAlias.name_alias).where( + customerAlias.age_alias + .cast('int') + .plus(100) + .equals(150) + ), + pg: { + text: 'SELECT "customer"."name" AS "name_alias" FROM "customer" WHERE ((CAST("customer"."age" AS int) + $1) = $2)', + string: 'SELECT "customer"."name" AS "name_alias" FROM "customer" WHERE ((CAST("customer"."age" AS int) + 100) = 150)' + }, + sqlite: { + text: 'SELECT "customer"."name" AS "name_alias" FROM "customer" WHERE ((CAST("customer"."age" AS int) + $1) = $2)', + string: 'SELECT "customer"."name" AS "name_alias" FROM "customer" WHERE ((CAST("customer"."age" AS int) + 100) = 150)' + }, + mysql: { + text: 'SELECT `customer`.`name` AS `name_alias` FROM `customer` WHERE ((CAST(`customer`.`age` AS int) + ?) = ?)', + string: 'SELECT `customer`.`name` AS `name_alias` FROM `customer` WHERE ((CAST(`customer`.`age` AS int) + 100) = 150)' + }, + mssql: { + text: 'SELECT [customer].[name] AS [name_alias] FROM [customer] WHERE ((CAST([customer].[age] AS int) + @1) = @2)', + string: 'SELECT [customer].[name] AS [name_alias] FROM [customer] WHERE ((CAST([customer].[age] AS int) + 100) = 150)' + }, + oracle: { + text: 'SELECT "customer"."name" "name_alias" FROM "customer" WHERE ((CAST("customer"."age" AS int) + :1) = :2)', + string: 'SELECT "customer"."name" "name_alias" FROM "customer" WHERE ((CAST("customer"."age" AS int) + 100) = 150)' + }, + params: [100, 150] +}); + +// Alias cast. +Harness.test({ + query: customerAlias.select(customerAlias.age_alias.cast('int').as('age_int')), + pg: { + text: 'SELECT CAST("customer"."age" AS int) AS "age_int" FROM "customer"', + string: 'SELECT CAST("customer"."age" AS int) AS "age_int" FROM "customer"' + }, + sqlite: { + text: 'SELECT CAST("customer"."age" AS int) AS "age_int" FROM "customer"', + string: 'SELECT CAST("customer"."age" AS int) AS "age_int" FROM "customer"' + }, + mysql: { + text: 'SELECT CAST(`customer`.`age` AS int) AS `age_int` FROM `customer`', + string: 'SELECT CAST(`customer`.`age` AS int) AS `age_int` FROM `customer`' + }, + mssql: { + text: 'SELECT CAST([customer].[age] AS int) AS [age_int] FROM [customer]', + string: 'SELECT CAST([customer].[age] AS int) AS [age_int] FROM [customer]' + }, + oracle: { + text: 'SELECT CAST("customer"."age" AS int) "age_int" FROM "customer"', + string: 'SELECT CAST("customer"."age" AS int) "age_int" FROM "customer"' + }, + params: [] +}); diff --git a/test/dialects/clause-ordering-tests.js b/test/dialects/clause-ordering-tests.js deleted file mode 100644 index 83d2d28e..00000000 --- a/test/dialects/clause-ordering-tests.js +++ /dev/null @@ -1,118 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var user = Harness.defineUserTable(); -var post = Harness.definePostTable(); - -// FROM - SELECT -Harness.test({ - query: user.from(user.join(post).on(user.id.equals(post.userId))).select(user.name, post.content), - pg: { - text : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', - string: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' - }, - sqlite: { - text : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', - string: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' - }, - mysql: { - text : 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)', - string: 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' - }, - mssql: { - text : 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId])', - string: 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId])' - }, - oracle: { - text : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', - string: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' - }, - params: [] -}); - -// WHERE - FROM - SELECT -Harness.test({ - query: user.where({ - name: '' - }).from(user).select(user.id), - pg: { - text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', - string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'\')' - }, - sqlite: { - text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', - string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'\')' - }, - mysql: { - text : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', - string: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = \'\')' - }, - mssql: { - text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = @1)', - string: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = \'\')' - }, - oracle: { - text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = :1)', - string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'\')' - }, - params: [''] -}); - -// SELECT - FROM - WHERE -Harness.test({ - query: user - .select(user.name, post.content) - .from(user.join(post).on(user.id.equals(post.userId))) - .where({ - name: '' - }), - pg: { - text : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("user"."name" = $1)', - string: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("user"."name" = \'\')' - }, - sqlite: { - text : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("user"."name" = $1)', - string: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("user"."name" = \'\')' - }, - mysql: { - text : 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`user`.`name` = ?)', - string: 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`user`.`name` = \'\')' - }, - mssql: { - text : 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) WHERE ([user].[name] = @1)', - string: 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) WHERE ([user].[name] = \'\')' - }, - oracle: { - text : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("user"."name" = :1)', - string: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("user"."name" = \'\')' - }, - params: [''] -}); - -// SELECT - FROM - WHERE -Harness.test({ - query: user.select(user.id).from(user).where({ - name: '' - }), - pg: { - text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', - string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'\')' - }, - sqlite: { - text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', - string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'\')' - }, - mysql: { - text : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', - string: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = \'\')' - }, - mssql: { - text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = @1)', - string: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = \'\')' - }, - oracle: { - text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = :1)', - string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'\')' - }, - params: [''] -}); diff --git a/test/dialects/clause-ordering-tests.ts b/test/dialects/clause-ordering-tests.ts new file mode 100644 index 00000000..8ac50cce --- /dev/null +++ b/test/dialects/clause-ordering-tests.ts @@ -0,0 +1,132 @@ +import * as Harness from './support.js'; +const post = Harness.definePostTable(); +const user = Harness.defineUserTable(); + +// FROM - SELECT +Harness.test({ + query: user.from(user.join(post).on(user.id.equals(post.userId))).select(user.name, post.content), + pg: { + text: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + string: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' + }, + sqlite: { + text: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + string: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' + }, + mysql: { + text: 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)', + string: 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' + }, + mssql: { + text: 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId])', + string: 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId])' + }, + oracle: { + text: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + string: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' + }, + params: [] +}); + +// WHERE - FROM - SELECT +Harness.test({ + query: user + .where({ + name: '' + }) + .from(user) + .select(user.id), + pg: { + text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'\')' + }, + sqlite: { + text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'\')' + }, + mysql: { + text: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', + string: "SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = '')" + }, + mssql: { + text: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = @1)', + string: "SELECT [user].[id] FROM [user] WHERE ([user].[name] = '')" + }, + oracle: { + text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = :1)', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'\')' + }, + params: [''] +}); + +// SELECT - FROM - WHERE +Harness.test({ + query: user + .select(user.name, post.content) + .from(user.join(post).on(user.id.equals(post.userId))) + .where({ + name: '' + }), + pg: { + text: + 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("user"."name" = $1)', + string: + 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("user"."name" = \'\')' + }, + sqlite: { + text: + 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("user"."name" = $1)', + string: + 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("user"."name" = \'\')' + }, + mysql: { + text: + 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`user`.`name` = ?)', + string: + "SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`user`.`name` = '')" + }, + mssql: { + text: + 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) WHERE ([user].[name] = @1)', + string: + "SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) WHERE ([user].[name] = '')" + }, + oracle: { + text: + 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("user"."name" = :1)', + string: + 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("user"."name" = \'\')' + }, + params: [''] +}); + +// SELECT - FROM - WHERE +Harness.test({ + query: user + .select(user.id) + .from(user) + .where({ + name: '' + }), + pg: { + text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'\')' + }, + sqlite: { + text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'\')' + }, + mysql: { + text: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', + string: "SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = '')" + }, + mssql: { + text: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = @1)', + string: "SELECT [user].[id] FROM [user] WHERE ([user].[name] = '')" + }, + oracle: { + text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = :1)', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'\')' + }, + params: [''] +}); diff --git a/test/dialects/create-table-tests.js b/test/dialects/create-table-tests.js deleted file mode 100644 index b1150617..00000000 --- a/test/dialects/create-table-tests.js +++ /dev/null @@ -1,761 +0,0 @@ -'use strict'; - -var Table = require(__dirname + '/../../lib/table'); -var Harness = require('./support'); - -var group = Table.define({ - name: 'group', - columns: [{ - name: 'id', - dataType: 'varchar(100)' - }, { - name: 'user_id', - dataType: 'varchar(100)' - } - ] -}); - -Harness.test({ - query: group.create(), - pg: { - text : 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))', - string: 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))' - }, - sqlite: { - text : 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))', - string: 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))' - }, - mysql: { - text : 'CREATE TABLE `group` (`id` varchar(100), `user_id` varchar(100))', - string: 'CREATE TABLE `group` (`id` varchar(100), `user_id` varchar(100))' - }, - mssql: { - text : 'CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100))', - string: 'CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100))' - }, - oracle: { - text : 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))', - string: 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))' - }, - params: [] -}); - -Harness.test({ - query: group.create().ifNotExists(), - pg: { - text : 'CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100), "user_id" varchar(100))', - string: 'CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100), "user_id" varchar(100))' - }, - sqlite: { - text : 'CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100), "user_id" varchar(100))', - string: 'CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100), "user_id" varchar(100))' - }, - mysql: { - text : 'CREATE TABLE IF NOT EXISTS `group` (`id` varchar(100), `user_id` varchar(100))', - string: 'CREATE TABLE IF NOT EXISTS `group` (`id` varchar(100), `user_id` varchar(100))' - }, - mssql: { - text : 'IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = \'group\') BEGIN CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100)) END', - string: 'IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = \'group\') BEGIN CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100)) END' - }, - oracle: { - text : 'BEGIN EXECUTE IMMEDIATE \'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))\'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -955 THEN RAISE; END IF; END;', - string: 'BEGIN EXECUTE IMMEDIATE \'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))\'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -955 THEN RAISE; END IF; END;' - }, - params: [] -}); - -Harness.test({ - query: Table.define({ - name: 'user', - columns: [{ - name: 'id', - dataType: 'varchar(100)' - } - ], - engine: 'InnoDB' - }).create(), - pg: { - text : 'CREATE TABLE "user" ("id" varchar(100))', - string: 'CREATE TABLE "user" ("id" varchar(100))' - }, - sqlite: { - text : 'CREATE TABLE "user" ("id" varchar(100))', - string: 'CREATE TABLE "user" ("id" varchar(100))' - }, - mysql: { - text : 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=InnoDB', - string: 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=InnoDB' - }, - mssql: { - text : 'CREATE TABLE [user] ([id] varchar(100))', - string: 'CREATE TABLE [user] ([id] varchar(100))' - }, - oracle: { - text : 'CREATE TABLE "user" ("id" varchar(100))', - string: 'CREATE TABLE "user" ("id" varchar(100))' - } -}); - -Harness.test({ - query: Table.define({ - name: 'user', - columns: [{ - name: 'id', - dataType: 'varchar(100)' - } - ], - charset: 'latin1' - }).create(), - pg: { - text : 'CREATE TABLE "user" ("id" varchar(100))', - string: 'CREATE TABLE "user" ("id" varchar(100))' - }, - sqlite: { - text : 'CREATE TABLE "user" ("id" varchar(100))', - string: 'CREATE TABLE "user" ("id" varchar(100))' - }, - mysql: { - text : 'CREATE TABLE `user` (`id` varchar(100)) DEFAULT CHARSET=latin1', - string: 'CREATE TABLE `user` (`id` varchar(100)) DEFAULT CHARSET=latin1' - }, - mssql: { - text : 'CREATE TABLE [user] ([id] varchar(100))', - string: 'CREATE TABLE [user] ([id] varchar(100))' - }, - oracle: { - text : 'CREATE TABLE "user" ("id" varchar(100))', - string: 'CREATE TABLE "user" ("id" varchar(100))' - } -}); - -Harness.test({ - query: Table.define({ - name: 'user', - columns: [{ - name: 'id', - dataType: 'varchar(100)' - } - ], - engine: 'MyISAM', - charset: 'latin1' - }).create(), - pg: { - text : 'CREATE TABLE "user" ("id" varchar(100))', - string: 'CREATE TABLE "user" ("id" varchar(100))' - }, - sqlite: { - text : 'CREATE TABLE "user" ("id" varchar(100))', - string: 'CREATE TABLE "user" ("id" varchar(100))' - }, - mysql: { - text : 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=MyISAM DEFAULT CHARSET=latin1', - string: 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=MyISAM DEFAULT CHARSET=latin1' - }, - mssql: { - text : 'CREATE TABLE [user] ([id] varchar(100))', - string: 'CREATE TABLE [user] ([id] varchar(100))' - }, - oracle: { - text : 'CREATE TABLE "user" ("id" varchar(100))', - string: 'CREATE TABLE "user" ("id" varchar(100))' - } -}); - -Harness.test({ - query: Table.define({ - name: 'user', - columns: [{ - name: 'id', - dataType: 'int', - primaryKey: true - }] - }).create(), - pg: { - text : 'CREATE TABLE "user" ("id" int PRIMARY KEY)', - string: 'CREATE TABLE "user" ("id" int PRIMARY KEY)' - }, - sqlite: { - text : 'CREATE TABLE "user" ("id" int PRIMARY KEY)', - string: 'CREATE TABLE "user" ("id" int PRIMARY KEY)' - }, - mysql: { - text : 'CREATE TABLE `user` (`id` int PRIMARY KEY)', - string: 'CREATE TABLE `user` (`id` int PRIMARY KEY)' - }, - mssql: { - text : 'CREATE TABLE [user] ([id] int PRIMARY KEY)', - string: 'CREATE TABLE [user] ([id] int PRIMARY KEY)' - }, - oracle: { - text : 'CREATE TABLE "user" ("id" int PRIMARY KEY)', - string: 'CREATE TABLE "user" ("id" int PRIMARY KEY)' - } -}); - -Harness.test({ - query: Table.define({ - name: 'user', - columns: [{ - name: 'id', - dataType: 'int', - notNull: true - }] - }).create(), - pg: { - text : 'CREATE TABLE "user" ("id" int NOT NULL)', - string: 'CREATE TABLE "user" ("id" int NOT NULL)' - }, - sqlite: { - text : 'CREATE TABLE "user" ("id" int NOT NULL)', - string: 'CREATE TABLE "user" ("id" int NOT NULL)' - }, - mysql: { - text : 'CREATE TABLE `user` (`id` int NOT NULL)', - string: 'CREATE TABLE `user` (`id` int NOT NULL)' - }, - oracle: { - text : 'CREATE TABLE "user" ("id" int NOT NULL)', - string: 'CREATE TABLE "user" ("id" int NOT NULL)' - } -}); - -Harness.test({ - query: Table.define({ - name: 'user', - columns: [{ - name: 'id', - dataType: 'int', - primaryKey: true, - notNull: true - }] - }).create(), - pg: { - text : 'CREATE TABLE "user" ("id" int PRIMARY KEY)', - string: 'CREATE TABLE "user" ("id" int PRIMARY KEY)' - }, - sqlite: { - text : 'CREATE TABLE "user" ("id" int PRIMARY KEY)', - string: 'CREATE TABLE "user" ("id" int PRIMARY KEY)' - }, - mysql: { - text : 'CREATE TABLE `user` (`id` int PRIMARY KEY)', - string: 'CREATE TABLE `user` (`id` int PRIMARY KEY)' - }, - oracle: { - text : 'CREATE TABLE "user" ("id" int PRIMARY KEY)', - string: 'CREATE TABLE "user" ("id" int PRIMARY KEY)' - } -}); - -Harness.test({ - query: Table.define({ - name: 'user', - columns: [{ - name: 'id', - dataType: 'int', - primaryKey: true, - notNull: true - }, { - name: 'posts', - dataType: 'int', - notNull: true, - defaultValue: 0 - }] - }).create(), - pg: { - text : 'CREATE TABLE "user" ("id" int PRIMARY KEY, "posts" int NOT NULL DEFAULT 0)', - string: 'CREATE TABLE "user" ("id" int PRIMARY KEY, "posts" int NOT NULL DEFAULT 0)' - }, - sqlite: { - text : 'CREATE TABLE "user" ("id" int PRIMARY KEY, "posts" int NOT NULL DEFAULT 0)', - string: 'CREATE TABLE "user" ("id" int PRIMARY KEY, "posts" int NOT NULL DEFAULT 0)' - }, - mysql: { - text : 'CREATE TABLE `user` (`id` int PRIMARY KEY, `posts` int NOT NULL DEFAULT 0)', - string: 'CREATE TABLE `user` (`id` int PRIMARY KEY, `posts` int NOT NULL DEFAULT 0)' - }, - oracle: { - text : 'CREATE TABLE "user" ("id" int PRIMARY KEY, "posts" int NOT NULL DEFAULT 0)', - string: 'CREATE TABLE "user" ("id" int PRIMARY KEY, "posts" int NOT NULL DEFAULT 0)' - } -}); - -Harness.test({ - query: Table.define({ - name: 'post', - columns: [{ - name: 'userId', - dataType: 'int', - references: { - table: 'user', - column: 'id', - onDelete: 'restrict', - onUpdate: 'set null' - } - }] - }).create(), - pg: { - text : 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id") ON DELETE RESTRICT ON UPDATE SET NULL)', - string: 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id") ON DELETE RESTRICT ON UPDATE SET NULL)' - }, - sqlite: { - text : 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id") ON DELETE RESTRICT ON UPDATE SET NULL)', - string: 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id") ON DELETE RESTRICT ON UPDATE SET NULL)' - }, - mysql: { - text : 'CREATE TABLE `post` (`userId` int REFERENCES `user`(`id`) ON DELETE RESTRICT ON UPDATE SET NULL)', - string: 'CREATE TABLE `post` (`userId` int REFERENCES `user`(`id`) ON DELETE RESTRICT ON UPDATE SET NULL)' - }, - oracle: { - text : 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id") ON DELETE RESTRICT ON UPDATE SET NULL)', - string: 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id") ON DELETE RESTRICT ON UPDATE SET NULL)' - }, - params: [] -}); - -Harness.test({ - query: Table.define({ - name: 'picture', - columns: [{ - name: 'userId', - dataType: 'int', - references: { - table: 'user', - column: 'id' - } - }, { - name: 'caption', - dataType: 'varchar(100)', - references: {} - }] - }).create(), - pg: { - text : 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id"), "caption" varchar(100))', - string: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id"), "caption" varchar(100))' - }, - sqlite: { - text : 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id"), "caption" varchar(100))', - string: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id"), "caption" varchar(100))' - }, - mysql: { - text : 'CREATE TABLE `picture` (`userId` int REFERENCES `user`(`id`), `caption` varchar(100))', - string: 'CREATE TABLE `picture` (`userId` int REFERENCES `user`(`id`), `caption` varchar(100))' - }, - oracle: { - text : 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id"), "caption" varchar(100))', - string: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id"), "caption" varchar(100))' - }, - params: [] -}); - -Harness.test({ - query: Table.define({ - name: 'picture', - columns: [{ - name: 'userId', - dataType: 'int', - references: { - table: 'user', - column: 'id', - onDelete: 'cascade' - } - }] - }).create(), - pg: { - text : 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id") ON DELETE CASCADE)', - string: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id") ON DELETE CASCADE)' - }, - sqlite: { - text : 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id") ON DELETE CASCADE)', - string: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id") ON DELETE CASCADE)' - }, - mysql: { - text : 'CREATE TABLE `picture` (`userId` int REFERENCES `user`(`id`) ON DELETE CASCADE)', - string: 'CREATE TABLE `picture` (`userId` int REFERENCES `user`(`id`) ON DELETE CASCADE)' - }, - oracle: { - text : 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id") ON DELETE CASCADE)', - string: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id") ON DELETE CASCADE)' - }, - params: [] -}); - -Harness.test({ - query: Table.define({ - name: 'post', - columns: [{ - name: 'userId', - dataType: 'int', - references: 'user' - }] - }).create(), - pg: { - text : 'references is not a object for column userId (REFERENCES statements within CREATE TABLE and ADD COLUMN statements require refrences to be expressed as an object)', - throws: true - }, - sqlite: { - text : 'references is not a object for column userId (REFERENCES statements within CREATE TABLE and ADD COLUMN statements require refrences to be expressed as an object)', - throws: true - }, - mysql: { - text : 'references is not a object for column userId (REFERENCES statements within CREATE TABLE and ADD COLUMN statements require refrences to be expressed as an object)', - throws: true - }, - oracle: { - text : 'references is not a object for column userId (REFERENCES statements within CREATE TABLE and ADD COLUMN statements require refrences to be expressed as an object)', - throws: true - }, - params: [] -}); - -Harness.test({ - query: Table.define({ - name: 'membership', - columns: { - group_id: { dataType: 'int', primaryKey: true}, - user_id: { dataType: 'int', primaryKey: true}, - desc: { dataType: 'varchar'} - } - }).create(), - pg: { - text : 'CREATE TABLE "membership" ("group_id" int, "user_id" int, "desc" varchar, PRIMARY KEY ("group_id", "user_id"))', - string: 'CREATE TABLE "membership" ("group_id" int, "user_id" int, "desc" varchar, PRIMARY KEY ("group_id", "user_id"))', - }, - sqlite: { - text : 'CREATE TABLE "membership" ("group_id" int, "user_id" int, "desc" varchar, PRIMARY KEY ("group_id", "user_id"))', - string: 'CREATE TABLE "membership" ("group_id" int, "user_id" int, "desc" varchar, PRIMARY KEY ("group_id", "user_id"))', - }, - mysql: { - text : 'CREATE TABLE `membership` (`group_id` int, `user_id` int, `desc` varchar, PRIMARY KEY (`group_id`, `user_id`))', - string: 'CREATE TABLE `membership` (`group_id` int, `user_id` int, `desc` varchar, PRIMARY KEY (`group_id`, `user_id`))', - } -}); - -// TEMPORARY TABLE TESTS - -// This tests explicitly setting the isTemporary flag to false, as opposed to all the test above here which have it -// as undefined. -Harness.test({ - query: Table.define({ - name: 'post', - columns: [{ - name: 'id', - dataType: 'int' - }], - isTemporary:false - }).create(), - pg: { - text : 'CREATE TABLE "post" ("id" int)', - string: 'CREATE TABLE "post" ("id" int)' - }, - sqlite: { - text : 'CREATE TABLE "post" ("id" int)', - string: 'CREATE TABLE "post" ("id" int)' - }, - mysql: { - text : 'CREATE TABLE `post` (`id` int)', - string: 'CREATE TABLE `post` (`id` int)' - }, - mssql: { - text : 'CREATE TABLE [post] ([id] int)', - string: 'CREATE TABLE [post] ([id] int)' - }, - oracle: { - text : 'CREATE TABLE "post" ("id" int)', - string: 'CREATE TABLE "post" ("id" int)' - }, - params: [] -}); - -Harness.test({ - query: Table.define({ - name: 'post', - columns: [{ - name: 'id', - dataType: 'int' - }], - isTemporary:true - }).create(), - pg: { - text : 'CREATE TEMPORARY TABLE "post" ("id" int)', - string: 'CREATE TEMPORARY TABLE "post" ("id" int)' - }, - sqlite: { - text : 'CREATE TEMPORARY TABLE "post" ("id" int)', - string: 'CREATE TEMPORARY TABLE "post" ("id" int)' - }, - mysql: { - text : 'CREATE TEMPORARY TABLE `post` (`id` int)', - string: 'CREATE TEMPORARY TABLE `post` (`id` int)' - }, - //mssql: { - // text : 'CREATE TABLE [#post] ([id] int)', - // string: 'CREATE TABLE [#post] ([id] int)' - //}, - params: [] -}); - -var users = Table.define({ - name: 'users', - columns: { - id: { - primaryKey: true, - dataType: 'int', - references: { - table: "entity", - column: "id", - constraint: "DEFERRABLE INITIALLY DEFERRED" - } - } - } -}); - -Harness.test({ - query: users.create(), - pg: { - text: 'CREATE TABLE "users" ("id" int PRIMARY KEY REFERENCES "entity"("id") DEFERRABLE INITIALLY DEFERRED)', - string: 'CREATE TABLE "users" ("id" int PRIMARY KEY REFERENCES "entity"("id") DEFERRABLE INITIALLY DEFERRED)' - }, - sqlite: { - text: 'CREATE TABLE "users" ("id" int PRIMARY KEY REFERENCES "entity"("id") DEFERRABLE INITIALLY DEFERRED)', - string: 'CREATE TABLE "users" ("id" int PRIMARY KEY REFERENCES "entity"("id") DEFERRABLE INITIALLY DEFERRED)' - }, - mysql: { - text: 'CREATE TABLE `users` (`id` int PRIMARY KEY REFERENCES `entity`(`id`) DEFERRABLE INITIALLY DEFERRED)', - string: 'CREATE TABLE `users` (`id` int PRIMARY KEY REFERENCES `entity`(`id`) DEFERRABLE INITIALLY DEFERRED)' - }, - mssql: { - text: 'CREATE TABLE [users] ([id] int PRIMARY KEY REFERENCES [entity]([id]) DEFERRABLE INITIALLY DEFERRED)', - string: 'CREATE TABLE [users] ([id] int PRIMARY KEY REFERENCES [entity]([id]) DEFERRABLE INITIALLY DEFERRED)' - }, - oracle: { - text: 'CREATE TABLE "users" ("id" int PRIMARY KEY REFERENCES "entity"("id") DEFERRABLE INITIALLY DEFERRED)', - string: 'CREATE TABLE "users" ("id" int PRIMARY KEY REFERENCES "entity"("id") DEFERRABLE INITIALLY DEFERRED)' - }, - params: [] -}); - -// UNIQUE COLUMN TESTS -Harness.test({ - query: Table.define({ - name: 'post', - columns: [{ - name: 'id', - dataType: 'int', - //primaryKey: true, - //notNull: true, - unique: true - }] - }).create(), - pg: { - text : 'CREATE TABLE "post" ("id" int UNIQUE)', - string: 'CREATE TABLE "post" ("id" int UNIQUE)' - }, - sqlite: { - text : 'CREATE TABLE "post" ("id" int UNIQUE)', - string: 'CREATE TABLE "post" ("id" int UNIQUE)' - }, - mysql: { - text : 'CREATE TABLE `post` (`id` int UNIQUE)', - string: 'CREATE TABLE `post` (`id` int UNIQUE)' - }, - mssql: { - text : 'CREATE TABLE [post] ([id] int UNIQUE)', - string: 'CREATE TABLE [post] ([id] int UNIQUE)' - }, - oracle: { - text : 'CREATE TABLE "post" ("id" int UNIQUE)', - string: 'CREATE TABLE "post" ("id" int UNIQUE)' - }, - params: [] -}); - - -var noUsers = Table.define({ - name: 'no_users', - columns: { - id: { - primaryKey: true, - dataType: 'int', - references: { - table: "entity", - column: "id", - constraint: "" - } - } - } -}); - -Harness.test({ - query: noUsers.create(), - pg: { - text : 'CREATE TABLE "no_users" ("id" int PRIMARY KEY REFERENCES "entity"("id"))', - string: 'CREATE TABLE "no_users" ("id" int PRIMARY KEY REFERENCES "entity"("id"))' - }, - sqlite: { - text : 'CREATE TABLE "no_users" ("id" int PRIMARY KEY REFERENCES "entity"("id"))', - string: 'CREATE TABLE "no_users" ("id" int PRIMARY KEY REFERENCES "entity"("id"))' - }, - mysql: { - text : 'CREATE TABLE `no_users` (`id` int PRIMARY KEY REFERENCES `entity`(`id`))', - string: 'CREATE TABLE `no_users` (`id` int PRIMARY KEY REFERENCES `entity`(`id`))' - }, - mssql: { - text : 'CREATE TABLE [no_users] ([id] int PRIMARY KEY REFERENCES [entity]([id]))', - string: 'CREATE TABLE [no_users] ([id] int PRIMARY KEY REFERENCES [entity]([id]))' - }, - oracle: { - text : 'CREATE TABLE "no_users" ("id" int PRIMARY KEY REFERENCES "entity"("id"))', - string: 'CREATE TABLE "no_users" ("id" int PRIMARY KEY REFERENCES "entity"("id"))' - }, - params: [] -}); - -Harness.test({ - query: Table.define({ - name: 'post', - columns: [{ - name: 'id', - dataType: 'int', - //primaryKey: true, - notNull: true, - unique: true - }] - }).create(), - pg: { - text : 'CREATE TABLE "post" ("id" int NOT NULL UNIQUE)', - string: 'CREATE TABLE "post" ("id" int NOT NULL UNIQUE)' - }, - sqlite: { - text : 'CREATE TABLE "post" ("id" int NOT NULL UNIQUE)', - string: 'CREATE TABLE "post" ("id" int NOT NULL UNIQUE)' - }, - mysql: { - text : 'CREATE TABLE `post` (`id` int NOT NULL UNIQUE)', - string: 'CREATE TABLE `post` (`id` int NOT NULL UNIQUE)' - }, - mssql: { - text : 'CREATE TABLE [post] ([id] int NOT NULL UNIQUE)', - string: 'CREATE TABLE [post] ([id] int NOT NULL UNIQUE)' - }, - oracle: { - text : 'CREATE TABLE "post" ("id" int NOT NULL UNIQUE)', - string: 'CREATE TABLE "post" ("id" int NOT NULL UNIQUE)' - }, - params: [] -}); - -Harness.test({ - query: Table.define({ - name: 'post', - columns: [{ - name: 'id', - dataType: 'int', - primaryKey: true, - //notNull: true, - unique: true - }] - }).create(), - pg: { - text : 'CREATE TABLE "post" ("id" int PRIMARY KEY)', - string: 'CREATE TABLE "post" ("id" int PRIMARY KEY)' - }, - sqlite: { - text : 'CREATE TABLE "post" ("id" int PRIMARY KEY)', - string: 'CREATE TABLE "post" ("id" int PRIMARY KEY)' - }, - mysql: { - text : 'CREATE TABLE `post` (`id` int PRIMARY KEY)', - string: 'CREATE TABLE `post` (`id` int PRIMARY KEY)' - }, - mssql: { - text : 'CREATE TABLE [post] ([id] int PRIMARY KEY)', - string: 'CREATE TABLE [post] ([id] int PRIMARY KEY)' - }, - oracle: { - text : 'CREATE TABLE "post" ("id" int PRIMARY KEY)', - string: 'CREATE TABLE "post" ("id" int PRIMARY KEY)' - }, - params: [] -}); - -Harness.test({ - query: Table.define({ - name: 'post', - columns: [{ - name: 'id', - dataType: 'int', - primaryKey: true - }, { - name: 'blog_id', - dataType: 'int' - }, { - name: 'user_id', - dataType: 'int' - }], - foreignKeys: { - table: 'users', - columns: [ 'blog_id', 'user_id' ], - refColumns: [ 'id', 'user_id' ] - } - }).create(), - pg: { - text : 'CREATE TABLE "post" ("id" int PRIMARY KEY, "blog_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ( "id", "user_id" ))', - string: 'CREATE TABLE "post" ("id" int PRIMARY KEY, "blog_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ( "id", "user_id" ))' - }, - sqlite: { - text : 'CREATE TABLE "post" ("id" int PRIMARY KEY, "blog_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ( "id", "user_id" ))', - string: 'CREATE TABLE "post" ("id" int PRIMARY KEY, "blog_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ( "id", "user_id" ))' - }, - mysql: { - text : 'CREATE TABLE `post` (`id` int PRIMARY KEY, `blog_id` int, `user_id` int, FOREIGN KEY ( `blog_id`, `user_id` ) REFERENCES `users` ( `id`, `user_id` ))', - string: 'CREATE TABLE `post` (`id` int PRIMARY KEY, `blog_id` int, `user_id` int, FOREIGN KEY ( `blog_id`, `user_id` ) REFERENCES `users` ( `id`, `user_id` ))' - }, - params: [] -}); - -Harness.test({ - query: Table.define({ - name: 'replies', - columns: [{ - name: 'id', - dataType: 'int', - primaryKey: true - }, { - name: 'blog_id', - dataType: 'int' - }, { - name: 'post_id', - dataType: 'int' - }, { - name: 'user_id', - dataType: 'int' - }], - foreignKeys: [{ - table: 'users', - columns: [ 'blog_id', 'user_id' ], - onDelete: 'no action' - }, { - name: 'posts_idx', - table: 'posts', - columns: [ 'blog_id', 'post_id' ], - refColumns: [ 'blog_id', 'id' ], - onDelete: 'cascade', - onUpdate: 'set default' - }] - }).create(), - pg: { - text : 'CREATE TABLE "replies" ("id" int PRIMARY KEY, "blog_id" int, "post_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ON DELETE NO ACTION, CONSTRAINT "posts_idx" FOREIGN KEY ( "blog_id", "post_id" ) REFERENCES "posts" ( "blog_id", "id" ) ON DELETE CASCADE ON UPDATE SET DEFAULT)', - string: 'CREATE TABLE "replies" ("id" int PRIMARY KEY, "blog_id" int, "post_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ON DELETE NO ACTION, CONSTRAINT "posts_idx" FOREIGN KEY ( "blog_id", "post_id" ) REFERENCES "posts" ( "blog_id", "id" ) ON DELETE CASCADE ON UPDATE SET DEFAULT)' - }, - sqlite: { - text : 'CREATE TABLE "replies" ("id" int PRIMARY KEY, "blog_id" int, "post_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ON DELETE NO ACTION, CONSTRAINT "posts_idx" FOREIGN KEY ( "blog_id", "post_id" ) REFERENCES "posts" ( "blog_id", "id" ) ON DELETE CASCADE ON UPDATE SET DEFAULT)', - string: 'CREATE TABLE "replies" ("id" int PRIMARY KEY, "blog_id" int, "post_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ON DELETE NO ACTION, CONSTRAINT "posts_idx" FOREIGN KEY ( "blog_id", "post_id" ) REFERENCES "posts" ( "blog_id", "id" ) ON DELETE CASCADE ON UPDATE SET DEFAULT)' - }, - mysql: { - text : 'CREATE TABLE `replies` (`id` int PRIMARY KEY, `blog_id` int, `post_id` int, `user_id` int, FOREIGN KEY ( `blog_id`, `user_id` ) REFERENCES `users` ON DELETE NO ACTION, CONSTRAINT `posts_idx` FOREIGN KEY ( `blog_id`, `post_id` ) REFERENCES `posts` ( `blog_id`, `id` ) ON DELETE CASCADE ON UPDATE SET DEFAULT)', - string: 'CREATE TABLE `replies` (`id` int PRIMARY KEY, `blog_id` int, `post_id` int, `user_id` int, FOREIGN KEY ( `blog_id`, `user_id` ) REFERENCES `users` ON DELETE NO ACTION, CONSTRAINT `posts_idx` FOREIGN KEY ( `blog_id`, `post_id` ) REFERENCES `posts` ( `blog_id`, `id` ) ON DELETE CASCADE ON UPDATE SET DEFAULT)' - }, - params: [] -}); diff --git a/test/dialects/create-table-tests.ts b/test/dialects/create-table-tests.ts new file mode 100644 index 00000000..c635e2cc --- /dev/null +++ b/test/dialects/create-table-tests.ts @@ -0,0 +1,823 @@ +import * as Harness from './support.js'; +import { Table } from '../../dist/lib.js'; + +const group = Table.define({ + name: 'group', + columns: [ + { + name: 'id', + dataType: 'varchar(100)' + }, + { + name: 'user_id', + dataType: 'varchar(100)' + } + ] +}); + +Harness.test({ + query: group.create(), + pg: { + text: 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))', + string: 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))' + }, + sqlite: { + text: 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))', + string: 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))' + }, + mysql: { + text: 'CREATE TABLE `group` (`id` varchar(100), `user_id` varchar(100))', + string: 'CREATE TABLE `group` (`id` varchar(100), `user_id` varchar(100))' + }, + mssql: { + text: 'CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100))', + string: 'CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100))' + }, + oracle: { + text: 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))', + string: 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))' + }, + params: [] +}); + +Harness.test({ + query: group.create().ifNotExists(), + pg: { + text: 'CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100), "user_id" varchar(100))', + string: 'CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100), "user_id" varchar(100))' + }, + sqlite: { + text: 'CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100), "user_id" varchar(100))', + string: 'CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100), "user_id" varchar(100))' + }, + mysql: { + text: 'CREATE TABLE IF NOT EXISTS `group` (`id` varchar(100), `user_id` varchar(100))', + string: 'CREATE TABLE IF NOT EXISTS `group` (`id` varchar(100), `user_id` varchar(100))' + }, + mssql: { + text: + "IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'group') BEGIN CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100)) END", + string: + "IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'group') BEGIN CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100)) END" + }, + oracle: { + text: + 'BEGIN EXECUTE IMMEDIATE \'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))\'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -955 THEN RAISE; END IF; END;', + string: + 'BEGIN EXECUTE IMMEDIATE \'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))\'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -955 THEN RAISE; END IF; END;' + }, + params: [] +}); + +Harness.test({ + query: Table.define({ + name: 'user', + columns: [ + { + name: 'id', + dataType: 'varchar(100)' + } + ], + engine: 'InnoDB' + }).create(), + pg: { + text: 'CREATE TABLE "user" ("id" varchar(100))', + string: 'CREATE TABLE "user" ("id" varchar(100))' + }, + sqlite: { + text: 'CREATE TABLE "user" ("id" varchar(100))', + string: 'CREATE TABLE "user" ("id" varchar(100))' + }, + mysql: { + text: 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=InnoDB', + string: 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=InnoDB' + }, + mssql: { + text: 'CREATE TABLE [user] ([id] varchar(100))', + string: 'CREATE TABLE [user] ([id] varchar(100))' + }, + oracle: { + text: 'CREATE TABLE "user" ("id" varchar(100))', + string: 'CREATE TABLE "user" ("id" varchar(100))' + } +}); + +Harness.test({ + query: Table.define({ + name: 'user', + columns: [ + { + name: 'id', + dataType: 'varchar(100)' + } + ], + charset: 'latin1' + }).create(), + pg: { + text: 'CREATE TABLE "user" ("id" varchar(100))', + string: 'CREATE TABLE "user" ("id" varchar(100))' + }, + sqlite: { + text: 'CREATE TABLE "user" ("id" varchar(100))', + string: 'CREATE TABLE "user" ("id" varchar(100))' + }, + mysql: { + text: 'CREATE TABLE `user` (`id` varchar(100)) DEFAULT CHARSET=latin1', + string: 'CREATE TABLE `user` (`id` varchar(100)) DEFAULT CHARSET=latin1' + }, + mssql: { + text: 'CREATE TABLE [user] ([id] varchar(100))', + string: 'CREATE TABLE [user] ([id] varchar(100))' + }, + oracle: { + text: 'CREATE TABLE "user" ("id" varchar(100))', + string: 'CREATE TABLE "user" ("id" varchar(100))' + } +}); + +Harness.test({ + query: Table.define({ + name: 'user', + columns: [ + { + name: 'id', + dataType: 'varchar(100)' + } + ], + engine: 'MyISAM', + charset: 'latin1' + }).create(), + pg: { + text: 'CREATE TABLE "user" ("id" varchar(100))', + string: 'CREATE TABLE "user" ("id" varchar(100))' + }, + sqlite: { + text: 'CREATE TABLE "user" ("id" varchar(100))', + string: 'CREATE TABLE "user" ("id" varchar(100))' + }, + mysql: { + text: 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=MyISAM DEFAULT CHARSET=latin1', + string: 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=MyISAM DEFAULT CHARSET=latin1' + }, + mssql: { + text: 'CREATE TABLE [user] ([id] varchar(100))', + string: 'CREATE TABLE [user] ([id] varchar(100))' + }, + oracle: { + text: 'CREATE TABLE "user" ("id" varchar(100))', + string: 'CREATE TABLE "user" ("id" varchar(100))' + } +}); + +Harness.test({ + query: Table.define({ + name: 'user', + columns: [ + { + name: 'id', + dataType: 'int', + primaryKey: true + } + ] + }).create(), + pg: { + text: 'CREATE TABLE "user" ("id" int PRIMARY KEY)', + string: 'CREATE TABLE "user" ("id" int PRIMARY KEY)' + }, + sqlite: { + text: 'CREATE TABLE "user" ("id" int PRIMARY KEY)', + string: 'CREATE TABLE "user" ("id" int PRIMARY KEY)' + }, + mysql: { + text: 'CREATE TABLE `user` (`id` int PRIMARY KEY)', + string: 'CREATE TABLE `user` (`id` int PRIMARY KEY)' + }, + mssql: { + text: 'CREATE TABLE [user] ([id] int PRIMARY KEY)', + string: 'CREATE TABLE [user] ([id] int PRIMARY KEY)' + }, + oracle: { + text: 'CREATE TABLE "user" ("id" int PRIMARY KEY)', + string: 'CREATE TABLE "user" ("id" int PRIMARY KEY)' + } +}); + +Harness.test({ + query: Table.define({ + name: 'user', + columns: [ + { + name: 'id', + dataType: 'int', + notNull: true + } + ] + }).create(), + pg: { + text: 'CREATE TABLE "user" ("id" int NOT NULL)', + string: 'CREATE TABLE "user" ("id" int NOT NULL)' + }, + sqlite: { + text: 'CREATE TABLE "user" ("id" int NOT NULL)', + string: 'CREATE TABLE "user" ("id" int NOT NULL)' + }, + mysql: { + text: 'CREATE TABLE `user` (`id` int NOT NULL)', + string: 'CREATE TABLE `user` (`id` int NOT NULL)' + }, + oracle: { + text: 'CREATE TABLE "user" ("id" int NOT NULL)', + string: 'CREATE TABLE "user" ("id" int NOT NULL)' + } +}); + +Harness.test({ + query: Table.define({ + name: 'user', + columns: [ + { + name: 'id', + dataType: 'int', + primaryKey: true, + notNull: true + } + ] + }).create(), + pg: { + text: 'CREATE TABLE "user" ("id" int PRIMARY KEY)', + string: 'CREATE TABLE "user" ("id" int PRIMARY KEY)' + }, + sqlite: { + text: 'CREATE TABLE "user" ("id" int PRIMARY KEY)', + string: 'CREATE TABLE "user" ("id" int PRIMARY KEY)' + }, + mysql: { + text: 'CREATE TABLE `user` (`id` int PRIMARY KEY)', + string: 'CREATE TABLE `user` (`id` int PRIMARY KEY)' + }, + oracle: { + text: 'CREATE TABLE "user" ("id" int PRIMARY KEY)', + string: 'CREATE TABLE "user" ("id" int PRIMARY KEY)' + } +}); + +Harness.test({ + query: Table.define({ + name: 'user', + columns: [ + { + name: 'id', + dataType: 'int', + primaryKey: true, + notNull: true + }, + { + name: 'posts', + dataType: 'int', + notNull: true, + defaultValue: 0 + } + ] + }).create(), + pg: { + text: 'CREATE TABLE "user" ("id" int PRIMARY KEY, "posts" int NOT NULL DEFAULT 0)', + string: 'CREATE TABLE "user" ("id" int PRIMARY KEY, "posts" int NOT NULL DEFAULT 0)' + }, + sqlite: { + text: 'CREATE TABLE "user" ("id" int PRIMARY KEY, "posts" int NOT NULL DEFAULT 0)', + string: 'CREATE TABLE "user" ("id" int PRIMARY KEY, "posts" int NOT NULL DEFAULT 0)' + }, + mysql: { + text: 'CREATE TABLE `user` (`id` int PRIMARY KEY, `posts` int NOT NULL DEFAULT 0)', + string: 'CREATE TABLE `user` (`id` int PRIMARY KEY, `posts` int NOT NULL DEFAULT 0)' + }, + oracle: { + text: 'CREATE TABLE "user" ("id" int PRIMARY KEY, "posts" int NOT NULL DEFAULT 0)', + string: 'CREATE TABLE "user" ("id" int PRIMARY KEY, "posts" int NOT NULL DEFAULT 0)' + } +}); + +Harness.test({ + query: Table.define({ + name: 'post', + columns: [ + { + name: 'userId', + dataType: 'int', + references: { + table: 'user', + column: 'id', + onDelete: 'restrict', + onUpdate: 'set null' + } + } + ] + }).create(), + pg: { + text: 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id") ON DELETE RESTRICT ON UPDATE SET NULL)', + string: 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id") ON DELETE RESTRICT ON UPDATE SET NULL)' + }, + sqlite: { + text: 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id") ON DELETE RESTRICT ON UPDATE SET NULL)', + string: 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id") ON DELETE RESTRICT ON UPDATE SET NULL)' + }, + mysql: { + text: 'CREATE TABLE `post` (`userId` int REFERENCES `user`(`id`) ON DELETE RESTRICT ON UPDATE SET NULL)', + string: 'CREATE TABLE `post` (`userId` int REFERENCES `user`(`id`) ON DELETE RESTRICT ON UPDATE SET NULL)' + }, + oracle: { + text: 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id") ON DELETE RESTRICT ON UPDATE SET NULL)', + string: 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id") ON DELETE RESTRICT ON UPDATE SET NULL)' + }, + params: [] +}); + +Harness.test({ + query: Table.define({ + name: 'picture', + columns: [ + { + name: 'userId', + dataType: 'int', + references: { + table: 'user', + column: 'id' + } + }, + { + name: 'caption', + dataType: 'varchar(100)', + references: {} + } + ] + }).create(), + pg: { + text: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id"), "caption" varchar(100))', + string: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id"), "caption" varchar(100))' + }, + sqlite: { + text: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id"), "caption" varchar(100))', + string: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id"), "caption" varchar(100))' + }, + mysql: { + text: 'CREATE TABLE `picture` (`userId` int REFERENCES `user`(`id`), `caption` varchar(100))', + string: 'CREATE TABLE `picture` (`userId` int REFERENCES `user`(`id`), `caption` varchar(100))' + }, + oracle: { + text: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id"), "caption" varchar(100))', + string: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id"), "caption" varchar(100))' + }, + params: [] +}); + +Harness.test({ + query: Table.define({ + name: 'picture', + columns: [ + { + name: 'userId', + dataType: 'int', + references: { + table: 'user', + column: 'id', + onDelete: 'cascade' + } + } + ] + }).create(), + pg: { + text: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id") ON DELETE CASCADE)', + string: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id") ON DELETE CASCADE)' + }, + sqlite: { + text: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id") ON DELETE CASCADE)', + string: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id") ON DELETE CASCADE)' + }, + mysql: { + text: 'CREATE TABLE `picture` (`userId` int REFERENCES `user`(`id`) ON DELETE CASCADE)', + string: 'CREATE TABLE `picture` (`userId` int REFERENCES `user`(`id`) ON DELETE CASCADE)' + }, + oracle: { + text: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id") ON DELETE CASCADE)', + string: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id") ON DELETE CASCADE)' + }, + params: [] +}); + +Harness.test({ + query: Table.define({ + name: 'post', + columns: [ + { + name: 'userId', + dataType: 'int', + references: 'user' + } + ] + }).create(), + pg: { + text: + 'references is not a object for column userId (REFERENCES statements within CREATE TABLE and ADD COLUMN statements require refrences to be expressed as an object)', + throws: true + }, + sqlite: { + text: + 'references is not a object for column userId (REFERENCES statements within CREATE TABLE and ADD COLUMN statements require refrences to be expressed as an object)', + throws: true + }, + mysql: { + text: + 'references is not a object for column userId (REFERENCES statements within CREATE TABLE and ADD COLUMN statements require refrences to be expressed as an object)', + throws: true + }, + oracle: { + text: + 'references is not a object for column userId (REFERENCES statements within CREATE TABLE and ADD COLUMN statements require refrences to be expressed as an object)', + throws: true + }, + params: [] +}); + +Harness.test({ + query: Table.define({ + name: 'membership', + columns: { + group_id: { dataType: 'int', primaryKey: true }, + user_id: { dataType: 'int', primaryKey: true }, + desc: { dataType: 'varchar' } + } + }).create(), + pg: { + text: 'CREATE TABLE "membership" ("group_id" int, "user_id" int, "desc" varchar, PRIMARY KEY ("group_id", "user_id"))', + string: 'CREATE TABLE "membership" ("group_id" int, "user_id" int, "desc" varchar, PRIMARY KEY ("group_id", "user_id"))' + }, + sqlite: { + text: 'CREATE TABLE "membership" ("group_id" int, "user_id" int, "desc" varchar, PRIMARY KEY ("group_id", "user_id"))', + string: 'CREATE TABLE "membership" ("group_id" int, "user_id" int, "desc" varchar, PRIMARY KEY ("group_id", "user_id"))' + }, + mysql: { + text: 'CREATE TABLE `membership` (`group_id` int, `user_id` int, `desc` varchar, PRIMARY KEY (`group_id`, `user_id`))', + string: 'CREATE TABLE `membership` (`group_id` int, `user_id` int, `desc` varchar, PRIMARY KEY (`group_id`, `user_id`))' + } +}); + +// TEMPORARY TABLE TESTS + +// This tests explicitly setting the isTemporary flag to false, as opposed to all the test above here which have it +// as undefined. +Harness.test({ + query: Table.define({ + name: 'post', + columns: [ + { + name: 'id', + dataType: 'int' + } + ], + isTemporary: false + }).create(), + pg: { + text: 'CREATE TABLE "post" ("id" int)', + string: 'CREATE TABLE "post" ("id" int)' + }, + sqlite: { + text: 'CREATE TABLE "post" ("id" int)', + string: 'CREATE TABLE "post" ("id" int)' + }, + mysql: { + text: 'CREATE TABLE `post` (`id` int)', + string: 'CREATE TABLE `post` (`id` int)' + }, + mssql: { + text: 'CREATE TABLE [post] ([id] int)', + string: 'CREATE TABLE [post] ([id] int)' + }, + oracle: { + text: 'CREATE TABLE "post" ("id" int)', + string: 'CREATE TABLE "post" ("id" int)' + }, + params: [] +}); + +Harness.test({ + query: Table.define({ + name: 'post', + columns: [ + { + name: 'id', + dataType: 'int' + } + ], + isTemporary: true + }).create(), + pg: { + text: 'CREATE TEMPORARY TABLE "post" ("id" int)', + string: 'CREATE TEMPORARY TABLE "post" ("id" int)' + }, + sqlite: { + text: 'CREATE TEMPORARY TABLE "post" ("id" int)', + string: 'CREATE TEMPORARY TABLE "post" ("id" int)' + }, + mysql: { + text: 'CREATE TEMPORARY TABLE `post` (`id` int)', + string: 'CREATE TEMPORARY TABLE `post` (`id` int)' + }, + // mssql: { + // text : 'CREATE TABLE [#post] ([id] int)', + // string: 'CREATE TABLE [#post] ([id] int)' + // }, + params: [] +}); + +const users = Table.define({ + name: 'users', + columns: { + id: { + primaryKey: true, + dataType: 'int', + references: { + table: 'entity', + column: 'id', + constraint: 'DEFERRABLE INITIALLY DEFERRED' + } + } + } +}); + +Harness.test({ + query: users.create(), + pg: { + text: 'CREATE TABLE "users" ("id" int PRIMARY KEY REFERENCES "entity"("id") DEFERRABLE INITIALLY DEFERRED)', + string: 'CREATE TABLE "users" ("id" int PRIMARY KEY REFERENCES "entity"("id") DEFERRABLE INITIALLY DEFERRED)' + }, + sqlite: { + text: 'CREATE TABLE "users" ("id" int PRIMARY KEY REFERENCES "entity"("id") DEFERRABLE INITIALLY DEFERRED)', + string: 'CREATE TABLE "users" ("id" int PRIMARY KEY REFERENCES "entity"("id") DEFERRABLE INITIALLY DEFERRED)' + }, + mysql: { + text: 'CREATE TABLE `users` (`id` int PRIMARY KEY REFERENCES `entity`(`id`) DEFERRABLE INITIALLY DEFERRED)', + string: 'CREATE TABLE `users` (`id` int PRIMARY KEY REFERENCES `entity`(`id`) DEFERRABLE INITIALLY DEFERRED)' + }, + mssql: { + text: 'CREATE TABLE [users] ([id] int PRIMARY KEY REFERENCES [entity]([id]) DEFERRABLE INITIALLY DEFERRED)', + string: 'CREATE TABLE [users] ([id] int PRIMARY KEY REFERENCES [entity]([id]) DEFERRABLE INITIALLY DEFERRED)' + }, + oracle: { + text: 'CREATE TABLE "users" ("id" int PRIMARY KEY REFERENCES "entity"("id") DEFERRABLE INITIALLY DEFERRED)', + string: 'CREATE TABLE "users" ("id" int PRIMARY KEY REFERENCES "entity"("id") DEFERRABLE INITIALLY DEFERRED)' + }, + params: [] +}); + +// UNIQUE COLUMN TESTS +Harness.test({ + query: Table.define({ + name: 'post', + columns: [ + { + name: 'id', + dataType: 'int', + // primaryKey: true, + // notNull: true, + unique: true + } + ] + }).create(), + pg: { + text: 'CREATE TABLE "post" ("id" int UNIQUE)', + string: 'CREATE TABLE "post" ("id" int UNIQUE)' + }, + sqlite: { + text: 'CREATE TABLE "post" ("id" int UNIQUE)', + string: 'CREATE TABLE "post" ("id" int UNIQUE)' + }, + mysql: { + text: 'CREATE TABLE `post` (`id` int UNIQUE)', + string: 'CREATE TABLE `post` (`id` int UNIQUE)' + }, + mssql: { + text: 'CREATE TABLE [post] ([id] int UNIQUE)', + string: 'CREATE TABLE [post] ([id] int UNIQUE)' + }, + oracle: { + text: 'CREATE TABLE "post" ("id" int UNIQUE)', + string: 'CREATE TABLE "post" ("id" int UNIQUE)' + }, + params: [] +}); + +const noUsers = Table.define({ + name: 'no_users', + columns: { + id: { + primaryKey: true, + dataType: 'int', + references: { + table: 'entity', + column: 'id', + constraint: '' + } + } + } +}); + +Harness.test({ + query: noUsers.create(), + pg: { + text: 'CREATE TABLE "no_users" ("id" int PRIMARY KEY REFERENCES "entity"("id"))', + string: 'CREATE TABLE "no_users" ("id" int PRIMARY KEY REFERENCES "entity"("id"))' + }, + sqlite: { + text: 'CREATE TABLE "no_users" ("id" int PRIMARY KEY REFERENCES "entity"("id"))', + string: 'CREATE TABLE "no_users" ("id" int PRIMARY KEY REFERENCES "entity"("id"))' + }, + mysql: { + text: 'CREATE TABLE `no_users` (`id` int PRIMARY KEY REFERENCES `entity`(`id`))', + string: 'CREATE TABLE `no_users` (`id` int PRIMARY KEY REFERENCES `entity`(`id`))' + }, + mssql: { + text: 'CREATE TABLE [no_users] ([id] int PRIMARY KEY REFERENCES [entity]([id]))', + string: 'CREATE TABLE [no_users] ([id] int PRIMARY KEY REFERENCES [entity]([id]))' + }, + oracle: { + text: 'CREATE TABLE "no_users" ("id" int PRIMARY KEY REFERENCES "entity"("id"))', + string: 'CREATE TABLE "no_users" ("id" int PRIMARY KEY REFERENCES "entity"("id"))' + }, + params: [] +}); + +Harness.test({ + query: Table.define({ + name: 'post', + columns: [ + { + name: 'id', + dataType: 'int', + // primaryKey: true, + notNull: true, + unique: true + } + ] + }).create(), + pg: { + text: 'CREATE TABLE "post" ("id" int NOT NULL UNIQUE)', + string: 'CREATE TABLE "post" ("id" int NOT NULL UNIQUE)' + }, + sqlite: { + text: 'CREATE TABLE "post" ("id" int NOT NULL UNIQUE)', + string: 'CREATE TABLE "post" ("id" int NOT NULL UNIQUE)' + }, + mysql: { + text: 'CREATE TABLE `post` (`id` int NOT NULL UNIQUE)', + string: 'CREATE TABLE `post` (`id` int NOT NULL UNIQUE)' + }, + mssql: { + text: 'CREATE TABLE [post] ([id] int NOT NULL UNIQUE)', + string: 'CREATE TABLE [post] ([id] int NOT NULL UNIQUE)' + }, + oracle: { + text: 'CREATE TABLE "post" ("id" int NOT NULL UNIQUE)', + string: 'CREATE TABLE "post" ("id" int NOT NULL UNIQUE)' + }, + params: [] +}); + +Harness.test({ + query: Table.define({ + name: 'post', + columns: [ + { + name: 'id', + dataType: 'int', + primaryKey: true, + // notNull: true, + unique: true + } + ] + }).create(), + pg: { + text: 'CREATE TABLE "post" ("id" int PRIMARY KEY)', + string: 'CREATE TABLE "post" ("id" int PRIMARY KEY)' + }, + sqlite: { + text: 'CREATE TABLE "post" ("id" int PRIMARY KEY)', + string: 'CREATE TABLE "post" ("id" int PRIMARY KEY)' + }, + mysql: { + text: 'CREATE TABLE `post` (`id` int PRIMARY KEY)', + string: 'CREATE TABLE `post` (`id` int PRIMARY KEY)' + }, + mssql: { + text: 'CREATE TABLE [post] ([id] int PRIMARY KEY)', + string: 'CREATE TABLE [post] ([id] int PRIMARY KEY)' + }, + oracle: { + text: 'CREATE TABLE "post" ("id" int PRIMARY KEY)', + string: 'CREATE TABLE "post" ("id" int PRIMARY KEY)' + }, + params: [] +}); + +Harness.test({ + query: Table.define({ + name: 'post', + columns: [ + { + name: 'id', + dataType: 'int', + primaryKey: true + }, + { + name: 'blog_id', + dataType: 'int' + }, + { + name: 'user_id', + dataType: 'int' + } + ], + foreignKeys: { + table: 'users', + columns: ['blog_id', 'user_id'], + refColumns: ['id', 'user_id'] + } + }).create(), + pg: { + text: + 'CREATE TABLE "post" ("id" int PRIMARY KEY, "blog_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ( "id", "user_id" ))', + string: + 'CREATE TABLE "post" ("id" int PRIMARY KEY, "blog_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ( "id", "user_id" ))' + }, + sqlite: { + text: + 'CREATE TABLE "post" ("id" int PRIMARY KEY, "blog_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ( "id", "user_id" ))', + string: + 'CREATE TABLE "post" ("id" int PRIMARY KEY, "blog_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ( "id", "user_id" ))' + }, + mysql: { + text: + 'CREATE TABLE `post` (`id` int PRIMARY KEY, `blog_id` int, `user_id` int, FOREIGN KEY ( `blog_id`, `user_id` ) REFERENCES `users` ( `id`, `user_id` ))', + string: + 'CREATE TABLE `post` (`id` int PRIMARY KEY, `blog_id` int, `user_id` int, FOREIGN KEY ( `blog_id`, `user_id` ) REFERENCES `users` ( `id`, `user_id` ))' + }, + params: [] +}); + +Harness.test({ + query: Table.define({ + name: 'replies', + columns: [ + { + name: 'id', + dataType: 'int', + primaryKey: true + }, + { + name: 'blog_id', + dataType: 'int' + }, + { + name: 'post_id', + dataType: 'int' + }, + { + name: 'user_id', + dataType: 'int' + } + ], + foreignKeys: [ + { + table: 'users', + columns: ['blog_id', 'user_id'], + onDelete: 'no action' + }, + { + name: 'posts_idx', + table: 'posts', + columns: ['blog_id', 'post_id'], + refColumns: ['blog_id', 'id'], + onDelete: 'cascade', + onUpdate: 'set default' + } + ] + }).create(), + pg: { + text: + 'CREATE TABLE "replies" ("id" int PRIMARY KEY, "blog_id" int, "post_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ON DELETE NO ACTION, CONSTRAINT "posts_idx" FOREIGN KEY ( "blog_id", "post_id" ) REFERENCES "posts" ( "blog_id", "id" ) ON DELETE CASCADE ON UPDATE SET DEFAULT)', + string: + 'CREATE TABLE "replies" ("id" int PRIMARY KEY, "blog_id" int, "post_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ON DELETE NO ACTION, CONSTRAINT "posts_idx" FOREIGN KEY ( "blog_id", "post_id" ) REFERENCES "posts" ( "blog_id", "id" ) ON DELETE CASCADE ON UPDATE SET DEFAULT)' + }, + sqlite: { + text: + 'CREATE TABLE "replies" ("id" int PRIMARY KEY, "blog_id" int, "post_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ON DELETE NO ACTION, CONSTRAINT "posts_idx" FOREIGN KEY ( "blog_id", "post_id" ) REFERENCES "posts" ( "blog_id", "id" ) ON DELETE CASCADE ON UPDATE SET DEFAULT)', + string: + 'CREATE TABLE "replies" ("id" int PRIMARY KEY, "blog_id" int, "post_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ON DELETE NO ACTION, CONSTRAINT "posts_idx" FOREIGN KEY ( "blog_id", "post_id" ) REFERENCES "posts" ( "blog_id", "id" ) ON DELETE CASCADE ON UPDATE SET DEFAULT)' + }, + mysql: { + text: + 'CREATE TABLE `replies` (`id` int PRIMARY KEY, `blog_id` int, `post_id` int, `user_id` int, FOREIGN KEY ( `blog_id`, `user_id` ) REFERENCES `users` ON DELETE NO ACTION, CONSTRAINT `posts_idx` FOREIGN KEY ( `blog_id`, `post_id` ) REFERENCES `posts` ( `blog_id`, `id` ) ON DELETE CASCADE ON UPDATE SET DEFAULT)', + string: + 'CREATE TABLE `replies` (`id` int PRIMARY KEY, `blog_id` int, `post_id` int, `user_id` int, FOREIGN KEY ( `blog_id`, `user_id` ) REFERENCES `users` ON DELETE NO ACTION, CONSTRAINT `posts_idx` FOREIGN KEY ( `blog_id`, `post_id` ) REFERENCES `posts` ( `blog_id`, `id` ) ON DELETE CASCADE ON UPDATE SET DEFAULT)' + }, + params: [] +}); diff --git a/test/dialects/create-view-tests.js b/test/dialects/create-view-tests.js deleted file mode 100644 index 977f540a..00000000 --- a/test/dialects/create-view-tests.js +++ /dev/null @@ -1,80 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var user = Harness.defineUserTable(); - -//simple view create -Harness.test({ - query: user.select(user.star()).createView('allUsersView'), - pg: { - text : '(CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user")', - string: '(CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user")' - }, - sqlite: { - text : '(CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user")', - string: '(CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user")' - }, - mysql: { - text : '(CREATE VIEW `allUsersView` AS SELECT `user`.* FROM `user`)', - string: '(CREATE VIEW `allUsersView` AS SELECT `user`.* FROM `user`)' - }, - mssql: { - text : '(CREATE VIEW [allUsersView] AS SELECT [user].* FROM [user])', - string: '(CREATE VIEW [allUsersView] AS SELECT [user].* FROM [user])' - }, - oracle: { - text : '(CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user")', - string: '(CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user")' - } -}); - -//create view with parameters -Harness.test({ - query: user.select(user.star()).where(user.id.equals(1)).createView('oneUserView'), - pg: { - text : '(CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1))', - string: '(CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1))' - }, - sqlite: { - text : '(CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1))', - string: '(CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1))' - }, - mysql: { - text : '(CREATE VIEW `oneUserView` AS SELECT `user`.* FROM `user` WHERE (`user`.`id` = 1))', - string: '(CREATE VIEW `oneUserView` AS SELECT `user`.* FROM `user` WHERE (`user`.`id` = 1))' - }, - mssql: { - text : '(CREATE VIEW [oneUserView] AS SELECT [user].* FROM [user] WHERE ([user].[id] = 1))', - string: '(CREATE VIEW [oneUserView] AS SELECT [user].* FROM [user] WHERE ([user].[id] = 1))' - }, - oracle: { - text : '(CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1))', - string: '(CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1))' - } -}); - -//Tests error raised for non-SELECT create view attempts -Harness.test({ - query: user.delete().where(user.id.equals(1)).createView('oneUserView'), - pg: { - text : 'Create View requires a Select.', - throws: true - }, - sqlite: { - text : 'Create View requires a Select.', - throws: true - }, - mysql: { - text : 'Create View requires a Select.', - throws: true - }, - mssql: { - text : 'Create View requires a Select.', - throws: true - }, - oracle: { - text : 'Create View requires a Select.', - throws: true - }, - params: [] -}); diff --git a/test/dialects/create-view-tests.ts b/test/dialects/create-view-tests.ts new file mode 100644 index 00000000..d9731d88 --- /dev/null +++ b/test/dialects/create-view-tests.ts @@ -0,0 +1,84 @@ +import * as Harness from './support.js'; +const user = Harness.defineUserTable(); + +// simple view create +Harness.test({ + query: user.select(user.star()).createView('allUsersView'), + pg: { + text: '(CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user")', + string: '(CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user")' + }, + sqlite: { + text: '(CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user")', + string: '(CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user")' + }, + mysql: { + text: '(CREATE VIEW `allUsersView` AS SELECT `user`.* FROM `user`)', + string: '(CREATE VIEW `allUsersView` AS SELECT `user`.* FROM `user`)' + }, + mssql: { + text: '(CREATE VIEW [allUsersView] AS SELECT [user].* FROM [user])', + string: '(CREATE VIEW [allUsersView] AS SELECT [user].* FROM [user])' + }, + oracle: { + text: '(CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user")', + string: '(CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user")' + } +}); + +// create view with parameters +Harness.test({ + query: user + .select(user.star()) + .where(user.id.equals(1)) + .createView('oneUserView'), + pg: { + text: '(CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1))', + string: '(CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1))' + }, + sqlite: { + text: '(CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1))', + string: '(CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1))' + }, + mysql: { + text: '(CREATE VIEW `oneUserView` AS SELECT `user`.* FROM `user` WHERE (`user`.`id` = 1))', + string: '(CREATE VIEW `oneUserView` AS SELECT `user`.* FROM `user` WHERE (`user`.`id` = 1))' + }, + mssql: { + text: '(CREATE VIEW [oneUserView] AS SELECT [user].* FROM [user] WHERE ([user].[id] = 1))', + string: '(CREATE VIEW [oneUserView] AS SELECT [user].* FROM [user] WHERE ([user].[id] = 1))' + }, + oracle: { + text: '(CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1))', + string: '(CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1))' + } +}); + +// Tests error raised for non-SELECT create view attempts +Harness.test({ + query: user + .delete() + .where(user.id.equals(1)) + .createView('oneUserView'), + pg: { + text: 'Create View requires a Select.', + throws: true + }, + sqlite: { + text: 'Create View requires a Select.', + throws: true + }, + mysql: { + text: 'Create View requires a Select.', + throws: true + }, + mssql: { + text: 'Create View requires a Select.', + throws: true + }, + oracle: { + text: 'Create View requires a Select.', + throws: true + }, + params: [] +}); diff --git a/test/dialects/date-tests.js b/test/dialects/date-tests.js deleted file mode 100644 index dd2c4d64..00000000 --- a/test/dialects/date-tests.js +++ /dev/null @@ -1,228 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var customer = Harness.defineCustomerTable(); -var Sql = require('../../lib'); - -Harness.test({ - query: customer.select(Sql.functions.YEAR(customer.metadata)), - pg: { - text : 'SELECT EXTRACT(YEAR FROM "customer"."metadata") FROM "customer"', - string: 'SELECT EXTRACT(YEAR FROM "customer"."metadata") FROM "customer"' - }, - sqlite: { - text : 'SELECT strftime(\'%Y\', "customer"."metadata") FROM "customer"', - string: 'SELECT strftime(\'%Y\', "customer"."metadata") FROM "customer"' - }, - mysql: { - text : 'SELECT YEAR(`customer`.`metadata`) FROM `customer`', - string: 'SELECT YEAR(`customer`.`metadata`) FROM `customer`' - }, - mssql: { - text : 'SELECT DATEPART(year, [customer].[metadata]) FROM [customer]', - string: 'SELECT DATEPART(year, [customer].[metadata]) FROM [customer]' - }, - oracle: { - text : 'SELECT EXTRACT(YEAR FROM "customer"."metadata") FROM "customer"', - string: 'SELECT EXTRACT(YEAR FROM "customer"."metadata") FROM "customer"' - }, - params: [] -}); - -Harness.test({ - query: customer.select(Sql.functions.MONTH(customer.metadata)), - pg: { - text : 'SELECT EXTRACT(MONTH FROM "customer"."metadata") FROM "customer"', - string: 'SELECT EXTRACT(MONTH FROM "customer"."metadata") FROM "customer"' - }, - sqlite: { - text: 'SELECT strftime(\'%m\', datetime("customer"."metadata"/1000, "unixepoch")) FROM "customer"', - string: 'SELECT strftime(\'%m\', datetime("customer"."metadata"/1000, "unixepoch")) FROM "customer"', - config: { - dateTimeMillis: true - } - }, - mysql: { - text : 'SELECT MONTH(`customer`.`metadata`) FROM `customer`', - string: 'SELECT MONTH(`customer`.`metadata`) FROM `customer`' - }, - mssql: { - text : 'SELECT DATEPART(month, [customer].[metadata]) FROM [customer]', - string: 'SELECT DATEPART(month, [customer].[metadata]) FROM [customer]' - }, - oracle: { - text : 'SELECT EXTRACT(MONTH FROM "customer"."metadata") FROM "customer"', - string: 'SELECT EXTRACT(MONTH FROM "customer"."metadata") FROM "customer"' - }, - params: [] -}); - -Harness.test({ - query: customer.select(Sql.functions.DAY(customer.metadata)), - pg: { - text : 'SELECT EXTRACT(DAY FROM "customer"."metadata") FROM "customer"', - string: 'SELECT EXTRACT(DAY FROM "customer"."metadata") FROM "customer"' - }, - sqlite: { - text : 'SELECT strftime(\'%d\', "customer"."metadata") FROM "customer"', - string: 'SELECT strftime(\'%d\', "customer"."metadata") FROM "customer"' - }, - mysql: { - text : 'SELECT DAY(`customer`.`metadata`) FROM `customer`', - string: 'SELECT DAY(`customer`.`metadata`) FROM `customer`' - }, - mssql: { - text : 'SELECT DATEPART(day, [customer].[metadata]) FROM [customer]', - string: 'SELECT DATEPART(day, [customer].[metadata]) FROM [customer]' - }, - oracle: { - text : 'SELECT EXTRACT(DAY FROM "customer"."metadata") FROM "customer"', - string: 'SELECT EXTRACT(DAY FROM "customer"."metadata") FROM "customer"' - }, - params: [] -}); - -Harness.test({ - query: customer.select(Sql.functions.HOUR(customer.metadata)), - pg: { - text : 'SELECT EXTRACT(HOUR FROM "customer"."metadata") FROM "customer"', - string: 'SELECT EXTRACT(HOUR FROM "customer"."metadata") FROM "customer"' - }, - sqlite: { - text: 'SELECT strftime(\'%H\', datetime("customer"."metadata"/1000, "unixepoch")) FROM "customer"', - string: 'SELECT strftime(\'%H\', datetime("customer"."metadata"/1000, "unixepoch")) FROM "customer"', - config: { - dateTimeMillis: true - } - }, - mysql: { - text : 'SELECT HOUR(`customer`.`metadata`) FROM `customer`', - string: 'SELECT HOUR(`customer`.`metadata`) FROM `customer`' - }, - mssql: { - text : 'SELECT DATEPART(hour, [customer].[metadata]) FROM [customer]', - string: 'SELECT DATEPART(hour, [customer].[metadata]) FROM [customer]' - }, - oracle: { - text : 'SELECT EXTRACT(HOUR FROM "customer"."metadata") FROM "customer"', - string: 'SELECT EXTRACT(HOUR FROM "customer"."metadata") FROM "customer"' - }, - params: [] -}); - -Harness.test({ - query: customer.select(Sql.functions.CURRENT_TIMESTAMP()), - pg: { - text : 'SELECT CURRENT_TIMESTAMP FROM "customer"', - string: 'SELECT CURRENT_TIMESTAMP FROM "customer"' - }, - sqlite: { - text : 'SELECT CURRENT_TIMESTAMP FROM "customer"', - string: 'SELECT CURRENT_TIMESTAMP FROM "customer"' - }, - mysql: { - text : 'SELECT CURRENT_TIMESTAMP FROM `customer`', - string: 'SELECT CURRENT_TIMESTAMP FROM `customer`' - }, - mssql: { - text : 'SELECT CURRENT_TIMESTAMP FROM [customer]', - string: 'SELECT CURRENT_TIMESTAMP FROM [customer]' - }, - oracle: { - text : 'SELECT CURRENT_TIMESTAMP FROM "customer"', - string: 'SELECT CURRENT_TIMESTAMP FROM "customer"' - }, - params: [] -}); - -Harness.test({ - query: Sql.select(Sql.functions.CURRENT_TIMESTAMP().plus(Sql.interval({hours:1}))), - pg: { - text : 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'1 HOUR\')', - string: 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'1 HOUR\')' - }, - mysql: { - text : 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'1:0:0\' HOUR_SECOND)', - string: 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'1:0:0\' HOUR_SECOND)' - }, - params: [] -}); - -Harness.test({ - query: Sql.select(Sql.functions.CURRENT_TIMESTAMP().minus(Sql.interval({years:3}))), - pg: { - text : 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'3 YEAR\')', - string: 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'3 YEAR\')' - }, - mysql: { - text : 'SELECT (CURRENT_TIMESTAMP - INTERVAL 3 YEAR)', - string: 'SELECT (CURRENT_TIMESTAMP - INTERVAL 3 YEAR)' - }, - params: [] -}); - -Harness.test({ - query: Sql.select(Sql.functions.CURRENT_TIMESTAMP().minus(Sql.interval({years:3, months:2}))), - pg: { - text : 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'3 YEAR 2 MONTH\')', - string: 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'3 YEAR 2 MONTH\')' - }, - mysql: { - text : 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'3-2\' YEAR_MONTH)', - string: 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'3-2\' YEAR_MONTH)' - }, - params: [] -}); - -Harness.test({ - query: Sql.select(Sql.functions.CURRENT_TIMESTAMP().plus(Sql.interval({hours:1, minutes:20}))), - pg: { - text : 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'1 HOUR 20 MINUTE\')', - string: 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'1 HOUR 20 MINUTE\')' - }, - mysql: { - text : 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'1:20:0\' HOUR_SECOND)', - string: 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'1:20:0\' HOUR_SECOND)' - }, - params: [] -}); - -Harness.test({ - query: Sql.select(Sql.functions.CURRENT_TIMESTAMP().plus(Sql.interval({hours:'sql\'injection', minutes:20}))), - pg: { - text : 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'20 MINUTE\')', - string: 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'20 MINUTE\')' - }, - mysql: { - text : 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'0:20:0\' HOUR_SECOND)', - string: 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'0:20:0\' HOUR_SECOND)' - }, - params: [] -}); - -Harness.test({ - query: Sql.select(Sql.functions.CURRENT_TIMESTAMP().minus(Sql.interval({days: 1, hours:5, minutes: 'sql\'injection'}))), - pg: { - text : 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'1 DAY 5 HOUR\')', - string: 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'1 DAY 5 HOUR\')' - }, - mysql: { - text : 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'1 5:0:0\' DAY_SECOND)', - string: 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'1 5:0:0\' DAY_SECOND)' - }, - params: [] -}); - -Harness.test({ - query: Sql.select(Sql.functions.CURRENT_TIMESTAMP().minus(Sql.interval({years: 2, months: 5}))), - pg: { - text : 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'2 YEAR 5 MONTH\')', - string: 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'2 YEAR 5 MONTH\')' - }, - mysql: { - text : 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'2-5\' YEAR_MONTH)', - string: 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'2-5\' YEAR_MONTH)' - }, - params: [] -}); - diff --git a/test/dialects/date-tests.ts b/test/dialects/date-tests.ts new file mode 100644 index 00000000..7fcee52c --- /dev/null +++ b/test/dialects/date-tests.ts @@ -0,0 +1,228 @@ +import * as Harness from './support.js'; +import { Sql } from '../../dist/lib.js'; +const customer = Harness.defineCustomerTable(); +const instance = new Sql('postgres'); + +Harness.test({ + query: customer.select(instance.functions.YEAR(customer.metadata)), + pg: { + text: 'SELECT EXTRACT(YEAR FROM "customer"."metadata") FROM "customer"', + string: 'SELECT EXTRACT(YEAR FROM "customer"."metadata") FROM "customer"' + }, + sqlite: { + text: 'SELECT strftime(\'%Y\', "customer"."metadata") FROM "customer"', + string: 'SELECT strftime(\'%Y\', "customer"."metadata") FROM "customer"' + }, + mysql: { + text: 'SELECT YEAR(`customer`.`metadata`) FROM `customer`', + string: 'SELECT YEAR(`customer`.`metadata`) FROM `customer`' + }, + mssql: { + text: 'SELECT DATEPART(year, [customer].[metadata]) FROM [customer]', + string: 'SELECT DATEPART(year, [customer].[metadata]) FROM [customer]' + }, + oracle: { + text: 'SELECT EXTRACT(YEAR FROM "customer"."metadata") FROM "customer"', + string: 'SELECT EXTRACT(YEAR FROM "customer"."metadata") FROM "customer"' + }, + params: [] +}); + +Harness.test({ + query: customer.select(instance.functions.MONTH(customer.metadata)), + pg: { + text: 'SELECT EXTRACT(MONTH FROM "customer"."metadata") FROM "customer"', + string: 'SELECT EXTRACT(MONTH FROM "customer"."metadata") FROM "customer"' + }, + sqlite: { + text: 'SELECT strftime(\'%m\', datetime("customer"."metadata"/1000, "unixepoch")) FROM "customer"', + string: 'SELECT strftime(\'%m\', datetime("customer"."metadata"/1000, "unixepoch")) FROM "customer"', + config: { + dateTimeMillis: true + } + }, + mysql: { + text: 'SELECT MONTH(`customer`.`metadata`) FROM `customer`', + string: 'SELECT MONTH(`customer`.`metadata`) FROM `customer`' + }, + mssql: { + text: 'SELECT DATEPART(month, [customer].[metadata]) FROM [customer]', + string: 'SELECT DATEPART(month, [customer].[metadata]) FROM [customer]' + }, + oracle: { + text: 'SELECT EXTRACT(MONTH FROM "customer"."metadata") FROM "customer"', + string: 'SELECT EXTRACT(MONTH FROM "customer"."metadata") FROM "customer"' + }, + params: [] +}); + +Harness.test({ + query: customer.select(instance.functions.DAY(customer.metadata)), + pg: { + text: 'SELECT EXTRACT(DAY FROM "customer"."metadata") FROM "customer"', + string: 'SELECT EXTRACT(DAY FROM "customer"."metadata") FROM "customer"' + }, + sqlite: { + text: 'SELECT strftime(\'%d\', "customer"."metadata") FROM "customer"', + string: 'SELECT strftime(\'%d\', "customer"."metadata") FROM "customer"' + }, + mysql: { + text: 'SELECT DAY(`customer`.`metadata`) FROM `customer`', + string: 'SELECT DAY(`customer`.`metadata`) FROM `customer`' + }, + mssql: { + text: 'SELECT DATEPART(day, [customer].[metadata]) FROM [customer]', + string: 'SELECT DATEPART(day, [customer].[metadata]) FROM [customer]' + }, + oracle: { + text: 'SELECT EXTRACT(DAY FROM "customer"."metadata") FROM "customer"', + string: 'SELECT EXTRACT(DAY FROM "customer"."metadata") FROM "customer"' + }, + params: [] +}); + +Harness.test({ + query: customer.select(instance.functions.HOUR(customer.metadata)), + pg: { + text: 'SELECT EXTRACT(HOUR FROM "customer"."metadata") FROM "customer"', + string: 'SELECT EXTRACT(HOUR FROM "customer"."metadata") FROM "customer"' + }, + sqlite: { + text: 'SELECT strftime(\'%H\', datetime("customer"."metadata"/1000, "unixepoch")) FROM "customer"', + string: 'SELECT strftime(\'%H\', datetime("customer"."metadata"/1000, "unixepoch")) FROM "customer"', + config: { + dateTimeMillis: true + } + }, + mysql: { + text: 'SELECT HOUR(`customer`.`metadata`) FROM `customer`', + string: 'SELECT HOUR(`customer`.`metadata`) FROM `customer`' + }, + mssql: { + text: 'SELECT DATEPART(hour, [customer].[metadata]) FROM [customer]', + string: 'SELECT DATEPART(hour, [customer].[metadata]) FROM [customer]' + }, + oracle: { + text: 'SELECT EXTRACT(HOUR FROM "customer"."metadata") FROM "customer"', + string: 'SELECT EXTRACT(HOUR FROM "customer"."metadata") FROM "customer"' + }, + params: [] +}); + +Harness.test({ + query: customer.select(instance.functions.CURRENT_TIMESTAMP()), + pg: { + text: 'SELECT CURRENT_TIMESTAMP FROM "customer"', + string: 'SELECT CURRENT_TIMESTAMP FROM "customer"' + }, + sqlite: { + text: 'SELECT CURRENT_TIMESTAMP FROM "customer"', + string: 'SELECT CURRENT_TIMESTAMP FROM "customer"' + }, + mysql: { + text: 'SELECT CURRENT_TIMESTAMP FROM `customer`', + string: 'SELECT CURRENT_TIMESTAMP FROM `customer`' + }, + mssql: { + text: 'SELECT CURRENT_TIMESTAMP FROM [customer]', + string: 'SELECT CURRENT_TIMESTAMP FROM [customer]' + }, + oracle: { + text: 'SELECT CURRENT_TIMESTAMP FROM "customer"', + string: 'SELECT CURRENT_TIMESTAMP FROM "customer"' + }, + params: [] +}); + +Harness.test({ + query: instance.select(instance.functions.CURRENT_TIMESTAMP().plus(instance.interval({ hours: 1 }))), + pg: { + text: "SELECT (CURRENT_TIMESTAMP + INTERVAL '1 HOUR')", + string: "SELECT (CURRENT_TIMESTAMP + INTERVAL '1 HOUR')" + }, + mysql: { + text: "SELECT (CURRENT_TIMESTAMP + INTERVAL '1:0:0' HOUR_SECOND)", + string: "SELECT (CURRENT_TIMESTAMP + INTERVAL '1:0:0' HOUR_SECOND)" + }, + params: [] +}); + +Harness.test({ + query: instance.select(instance.functions.CURRENT_TIMESTAMP().minus(instance.interval({ years: 3 }))), + pg: { + text: "SELECT (CURRENT_TIMESTAMP - INTERVAL '3 YEAR')", + string: "SELECT (CURRENT_TIMESTAMP - INTERVAL '3 YEAR')" + }, + mysql: { + text: 'SELECT (CURRENT_TIMESTAMP - INTERVAL 3 YEAR)', + string: 'SELECT (CURRENT_TIMESTAMP - INTERVAL 3 YEAR)' + }, + params: [] +}); + +Harness.test({ + query: instance.select(instance.functions.CURRENT_TIMESTAMP().minus(instance.interval({ years: 3, months: 2 }))), + pg: { + text: "SELECT (CURRENT_TIMESTAMP - INTERVAL '3 YEAR 2 MONTH')", + string: "SELECT (CURRENT_TIMESTAMP - INTERVAL '3 YEAR 2 MONTH')" + }, + mysql: { + text: "SELECT (CURRENT_TIMESTAMP - INTERVAL '3-2' YEAR_MONTH)", + string: "SELECT (CURRENT_TIMESTAMP - INTERVAL '3-2' YEAR_MONTH)" + }, + params: [] +}); + +Harness.test({ + query: instance.select(instance.functions.CURRENT_TIMESTAMP().plus(instance.interval({ hours: 1, minutes: 20 }))), + pg: { + text: "SELECT (CURRENT_TIMESTAMP + INTERVAL '1 HOUR 20 MINUTE')", + string: "SELECT (CURRENT_TIMESTAMP + INTERVAL '1 HOUR 20 MINUTE')" + }, + mysql: { + text: "SELECT (CURRENT_TIMESTAMP + INTERVAL '1:20:0' HOUR_SECOND)", + string: "SELECT (CURRENT_TIMESTAMP + INTERVAL '1:20:0' HOUR_SECOND)" + }, + params: [] +}); + +Harness.test({ + query: instance.select(instance.functions.CURRENT_TIMESTAMP().plus(instance.interval({ hours: "sql'injection", minutes: 20 }))), + pg: { + text: "SELECT (CURRENT_TIMESTAMP + INTERVAL '20 MINUTE')", + string: "SELECT (CURRENT_TIMESTAMP + INTERVAL '20 MINUTE')" + }, + mysql: { + text: "SELECT (CURRENT_TIMESTAMP + INTERVAL '0:20:0' HOUR_SECOND)", + string: "SELECT (CURRENT_TIMESTAMP + INTERVAL '0:20:0' HOUR_SECOND)" + }, + params: [] +}); + +Harness.test({ + query: instance.select( + instance.functions.CURRENT_TIMESTAMP().minus(instance.interval({ days: 1, hours: 5, minutes: "sql'injection" })) + ), + pg: { + text: "SELECT (CURRENT_TIMESTAMP - INTERVAL '1 DAY 5 HOUR')", + string: "SELECT (CURRENT_TIMESTAMP - INTERVAL '1 DAY 5 HOUR')" + }, + mysql: { + text: "SELECT (CURRENT_TIMESTAMP - INTERVAL '1 5:0:0' DAY_SECOND)", + string: "SELECT (CURRENT_TIMESTAMP - INTERVAL '1 5:0:0' DAY_SECOND)" + }, + params: [] +}); + +Harness.test({ + query: instance.select(instance.functions.CURRENT_TIMESTAMP().minus(instance.interval({ years: 2, months: 5 }))), + pg: { + text: "SELECT (CURRENT_TIMESTAMP - INTERVAL '2 YEAR 5 MONTH')", + string: "SELECT (CURRENT_TIMESTAMP - INTERVAL '2 YEAR 5 MONTH')" + }, + mysql: { + text: "SELECT (CURRENT_TIMESTAMP - INTERVAL '2-5' YEAR_MONTH)", + string: "SELECT (CURRENT_TIMESTAMP - INTERVAL '2-5' YEAR_MONTH)" + }, + params: [] +}); diff --git a/test/dialects/delete-tests.js b/test/dialects/delete-tests.js deleted file mode 100644 index 51fe3026..00000000 --- a/test/dialects/delete-tests.js +++ /dev/null @@ -1,169 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var post = Harness.definePostTable(); -var user = Harness.defineUserTable(); - -Harness.test({ - query: post.delete().where(post.content.equals("hello's world")), - pg: { - text : 'DELETE FROM "post" WHERE ("post"."content" = $1)', - string: 'DELETE FROM "post" WHERE ("post"."content" = \'hello\'\'s world\')' - }, - sqlite: { - text : 'DELETE FROM "post" WHERE ("post"."content" = $1)', - string: 'DELETE FROM "post" WHERE ("post"."content" = \'hello\'\'s world\')' - }, - mysql: { - text : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', - string: 'DELETE FROM `post` WHERE (`post`.`content` = \'hello\'\'s world\')' - }, - mssql: { - text : 'DELETE FROM [post] WHERE ([post].[content] = @1)', - string: "DELETE FROM [post] WHERE ([post].[content] = 'hello''s world')" - }, - oracle: { - text : 'DELETE FROM "post" WHERE ("post"."content" = :1)', - string: 'DELETE FROM "post" WHERE ("post"."content" = \'hello\'\'s world\')' - }, - params: ["hello's world"] -}); - -Harness.test({ - query: post.delete(post).from(post), - pg: { - text: 'DELETE "post" FROM "post"', - string: 'DELETE "post" FROM "post"' - }, - sqlite: { - text: 'DELETE "post" FROM "post"', - string: 'DELETE "post" FROM "post"' - }, - mysql: { - text: 'DELETE `post` FROM `post`', - string: 'DELETE `post` FROM `post`' - }, - params: [] -}); - -Harness.test({ - query: post.delete([post, post]).from(post), - pg: { - text: 'DELETE "post", "post" FROM "post"', - string: 'DELETE "post", "post" FROM "post"' - }, - sqlite: { - text: 'DELETE "post", "post" FROM "post"', - string: 'DELETE "post", "post" FROM "post"' - }, - mysql: { - text: 'DELETE `post`, `post` FROM `post`', - string: 'DELETE `post`, `post` FROM `post`' - }, - params: [] -}); - -Harness.test({ - query: user - .delete(user) - .from(user.join(post).on(post.userId.equals(user.id))) - .where(post.content.equals('foo')), - pg: { - text: 'DELETE "user" FROM "user" INNER JOIN "post" ON ("post"."userId" = "user"."id") WHERE ("post"."content" = $1)', - string: 'DELETE "user" FROM "user" INNER JOIN "post" ON ("post"."userId" = "user"."id") WHERE ("post"."content" = \'foo\')' - }, - sqlite: { - text: 'DELETE "user" FROM "user" INNER JOIN "post" ON ("post"."userId" = "user"."id") WHERE ("post"."content" = $1)', - string: 'DELETE "user" FROM "user" INNER JOIN "post" ON ("post"."userId" = "user"."id") WHERE ("post"."content" = \'foo\')' - }, - mysql: { - text: 'DELETE `user` FROM `user` INNER JOIN `post` ON (`post`.`userId` = `user`.`id`) WHERE (`post`.`content` = ?)', - string: 'DELETE `user` FROM `user` INNER JOIN `post` ON (`post`.`userId` = `user`.`id`) WHERE (`post`.`content` = \'foo\')' - }, - oracle: { - text: 'DELETE "user" FROM "user" INNER JOIN "post" ON ("post"."userId" = "user"."id") WHERE ("post"."content" = :1)', - string: 'DELETE "user" FROM "user" INNER JOIN "post" ON ("post"."userId" = "user"."id") WHERE ("post"."content" = \'foo\')' - }, - params: [ 'foo' ] -}); - -Harness.test({ - query: post.delete().where({ - content: '' - }), - pg: { - text : 'DELETE FROM "post" WHERE ("post"."content" = $1)', - string: 'DELETE FROM "post" WHERE ("post"."content" = \'\')' - }, - sqlite: { - text : 'DELETE FROM "post" WHERE ("post"."content" = $1)', - string: 'DELETE FROM "post" WHERE ("post"."content" = \'\')' - }, - mysql: { - text : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', - string: 'DELETE FROM `post` WHERE (`post`.`content` = \'\')' - }, - mssql: { - text : 'DELETE FROM [post] WHERE ([post].[content] = @1)', - string: "DELETE FROM [post] WHERE ([post].[content] = '')" - }, - oracle: { - text : 'DELETE FROM "post" WHERE ("post"."content" = :1)', - string: 'DELETE FROM "post" WHERE ("post"."content" = \'\')' - }, - params: [''] -}); - -Harness.test({ - query: post.delete({ - content: '' - }), - pg: { - text : 'DELETE FROM "post" WHERE ("post"."content" = $1)', - string: 'DELETE FROM "post" WHERE ("post"."content" = \'\')' - }, - sqlite: { - text : 'DELETE FROM "post" WHERE ("post"."content" = $1)', - string: 'DELETE FROM "post" WHERE ("post"."content" = \'\')' - }, - mysql: { - text : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', - string: 'DELETE FROM `post` WHERE (`post`.`content` = \'\')' - }, - mssql: { - text : 'DELETE FROM [post] WHERE ([post].[content] = @1)', - string: "DELETE FROM [post] WHERE ([post].[content] = '')" - }, - oracle: { - text : 'DELETE FROM "post" WHERE ("post"."content" = :1)', - string: 'DELETE FROM "post" WHERE ("post"."content" = \'\')' - }, - params: [''] -}); - -Harness.test({ - query: post.delete({ - content: '' - }).or(post.content.isNull()), - pg: { - text : 'DELETE FROM "post" WHERE (("post"."content" = $1) OR ("post"."content" IS NULL))', - string: 'DELETE FROM "post" WHERE (("post"."content" = \'\') OR ("post"."content" IS NULL))' - }, - sqlite: { - text : 'DELETE FROM "post" WHERE (("post"."content" = $1) OR ("post"."content" IS NULL))', - string: 'DELETE FROM "post" WHERE (("post"."content" = \'\') OR ("post"."content" IS NULL))' - }, - mysql: { - text : 'DELETE FROM `post` WHERE ((`post`.`content` = ?) OR (`post`.`content` IS NULL))', - string: 'DELETE FROM `post` WHERE ((`post`.`content` = \'\') OR (`post`.`content` IS NULL))' - }, - mssql: { - text : 'DELETE FROM [post] WHERE (([post].[content] = @1) OR ([post].[content] IS NULL))', - string: "DELETE FROM [post] WHERE (([post].[content] = '') OR ([post].[content] IS NULL))" - }, - oracle: { - text : 'DELETE FROM "post" WHERE (("post"."content" = :1) OR ("post"."content" IS NULL))', - string: 'DELETE FROM "post" WHERE (("post"."content" = \'\') OR ("post"."content" IS NULL))' - }, - params: [''] -}); diff --git a/test/dialects/delete-tests.ts b/test/dialects/delete-tests.ts new file mode 100644 index 00000000..73695cd1 --- /dev/null +++ b/test/dialects/delete-tests.ts @@ -0,0 +1,169 @@ +import * as Harness from './support.js'; +const post = Harness.definePostTable(); +const user = Harness.defineUserTable(); + +Harness.test({ + query: post.delete().where(post.content.equals("hello's world")), + pg: { + text: 'DELETE FROM "post" WHERE ("post"."content" = $1)', + string: 'DELETE FROM "post" WHERE ("post"."content" = \'hello\'\'s world\')' + }, + sqlite: { + text: 'DELETE FROM "post" WHERE ("post"."content" = $1)', + string: 'DELETE FROM "post" WHERE ("post"."content" = \'hello\'\'s world\')' + }, + mysql: { + text: 'DELETE FROM `post` WHERE (`post`.`content` = ?)', + string: "DELETE FROM `post` WHERE (`post`.`content` = 'hello''s world')" + }, + mssql: { + text: 'DELETE FROM [post] WHERE ([post].[content] = @1)', + string: "DELETE FROM [post] WHERE ([post].[content] = 'hello''s world')" + }, + oracle: { + text: 'DELETE FROM "post" WHERE ("post"."content" = :1)', + string: 'DELETE FROM "post" WHERE ("post"."content" = \'hello\'\'s world\')' + }, + params: ["hello's world"] +}); + +Harness.test({ + query: post.delete(post).from(post), + pg: { + text: 'DELETE "post" FROM "post"', + string: 'DELETE "post" FROM "post"' + }, + sqlite: { + text: 'DELETE "post" FROM "post"', + string: 'DELETE "post" FROM "post"' + }, + mysql: { + text: 'DELETE `post` FROM `post`', + string: 'DELETE `post` FROM `post`' + }, + params: [] +}); + +Harness.test({ + query: post.delete([post, post]).from(post), + pg: { + text: 'DELETE "post", "post" FROM "post"', + string: 'DELETE "post", "post" FROM "post"' + }, + sqlite: { + text: 'DELETE "post", "post" FROM "post"', + string: 'DELETE "post", "post" FROM "post"' + }, + mysql: { + text: 'DELETE `post`, `post` FROM `post`', + string: 'DELETE `post`, `post` FROM `post`' + }, + params: [] +}); + +Harness.test({ + query: user + .delete(user) + .from(user.join(post).on(post.userId.equals(user.id))) + .where(post.content.equals('foo')), + pg: { + text: 'DELETE "user" FROM "user" INNER JOIN "post" ON ("post"."userId" = "user"."id") WHERE ("post"."content" = $1)', + string: 'DELETE "user" FROM "user" INNER JOIN "post" ON ("post"."userId" = "user"."id") WHERE ("post"."content" = \'foo\')' + }, + sqlite: { + text: 'DELETE "user" FROM "user" INNER JOIN "post" ON ("post"."userId" = "user"."id") WHERE ("post"."content" = $1)', + string: 'DELETE "user" FROM "user" INNER JOIN "post" ON ("post"."userId" = "user"."id") WHERE ("post"."content" = \'foo\')' + }, + mysql: { + text: 'DELETE `user` FROM `user` INNER JOIN `post` ON (`post`.`userId` = `user`.`id`) WHERE (`post`.`content` = ?)', + string: "DELETE `user` FROM `user` INNER JOIN `post` ON (`post`.`userId` = `user`.`id`) WHERE (`post`.`content` = 'foo')" + }, + oracle: { + text: 'DELETE "user" FROM "user" INNER JOIN "post" ON ("post"."userId" = "user"."id") WHERE ("post"."content" = :1)', + string: 'DELETE "user" FROM "user" INNER JOIN "post" ON ("post"."userId" = "user"."id") WHERE ("post"."content" = \'foo\')' + }, + params: ['foo'] +}); + +Harness.test({ + query: post.delete().where({ + content: '' + }), + pg: { + text: 'DELETE FROM "post" WHERE ("post"."content" = $1)', + string: 'DELETE FROM "post" WHERE ("post"."content" = \'\')' + }, + sqlite: { + text: 'DELETE FROM "post" WHERE ("post"."content" = $1)', + string: 'DELETE FROM "post" WHERE ("post"."content" = \'\')' + }, + mysql: { + text: 'DELETE FROM `post` WHERE (`post`.`content` = ?)', + string: "DELETE FROM `post` WHERE (`post`.`content` = '')" + }, + mssql: { + text: 'DELETE FROM [post] WHERE ([post].[content] = @1)', + string: "DELETE FROM [post] WHERE ([post].[content] = '')" + }, + oracle: { + text: 'DELETE FROM "post" WHERE ("post"."content" = :1)', + string: 'DELETE FROM "post" WHERE ("post"."content" = \'\')' + }, + params: [''] +}); + +Harness.test({ + query: post.delete({ + content: '' + }), + pg: { + text: 'DELETE FROM "post" WHERE ("post"."content" = $1)', + string: 'DELETE FROM "post" WHERE ("post"."content" = \'\')' + }, + sqlite: { + text: 'DELETE FROM "post" WHERE ("post"."content" = $1)', + string: 'DELETE FROM "post" WHERE ("post"."content" = \'\')' + }, + mysql: { + text: 'DELETE FROM `post` WHERE (`post`.`content` = ?)', + string: "DELETE FROM `post` WHERE (`post`.`content` = '')" + }, + mssql: { + text: 'DELETE FROM [post] WHERE ([post].[content] = @1)', + string: "DELETE FROM [post] WHERE ([post].[content] = '')" + }, + oracle: { + text: 'DELETE FROM "post" WHERE ("post"."content" = :1)', + string: 'DELETE FROM "post" WHERE ("post"."content" = \'\')' + }, + params: [''] +}); + +Harness.test({ + query: post + .delete({ + content: '' + }) + .or(post.content.isNull()), + pg: { + text: 'DELETE FROM "post" WHERE (("post"."content" = $1) OR ("post"."content" IS NULL))', + string: 'DELETE FROM "post" WHERE (("post"."content" = \'\') OR ("post"."content" IS NULL))' + }, + sqlite: { + text: 'DELETE FROM "post" WHERE (("post"."content" = $1) OR ("post"."content" IS NULL))', + string: 'DELETE FROM "post" WHERE (("post"."content" = \'\') OR ("post"."content" IS NULL))' + }, + mysql: { + text: 'DELETE FROM `post` WHERE ((`post`.`content` = ?) OR (`post`.`content` IS NULL))', + string: "DELETE FROM `post` WHERE ((`post`.`content` = '') OR (`post`.`content` IS NULL))" + }, + mssql: { + text: 'DELETE FROM [post] WHERE (([post].[content] = @1) OR ([post].[content] IS NULL))', + string: "DELETE FROM [post] WHERE (([post].[content] = '') OR ([post].[content] IS NULL))" + }, + oracle: { + text: 'DELETE FROM "post" WHERE (("post"."content" = :1) OR ("post"."content" IS NULL))', + string: 'DELETE FROM "post" WHERE (("post"."content" = \'\') OR ("post"."content" IS NULL))' + }, + params: [''] +}); diff --git a/test/dialects/distinct-on-tests.js b/test/dialects/distinct-on-tests.js deleted file mode 100644 index d238f928..00000000 --- a/test/dialects/distinct-on-tests.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var user = Harness.defineUserTable(); -var Sql = require('../../lib').setDialect('postgres'); - -Harness.test({ - query: user.select().distinctOn(user.id), - pg: { - text : 'SELECT DISTINCT ON("user"."id") "user".* FROM "user"', - string: 'SELECT DISTINCT ON("user"."id") "user".* FROM "user"' - }, - params: [] -}); - -Harness.test({ - query: user.select(user.id,user.name).distinctOn(user.id), - pg: { - text : 'SELECT DISTINCT ON("user"."id") "user"."id", "user"."name" FROM "user"', - string: 'SELECT DISTINCT ON("user"."id") "user"."id", "user"."name" FROM "user"' - }, - params: [] -}); - diff --git a/test/dialects/distinct-on-tests.ts b/test/dialects/distinct-on-tests.ts new file mode 100644 index 00000000..ced30cb0 --- /dev/null +++ b/test/dialects/distinct-on-tests.ts @@ -0,0 +1,30 @@ +import * as Harness from './support.js'; +const user = Harness.defineUserTable(); +const customerAlias = Harness.defineCustomerAliasTable(); + +Harness.test({ + query: user.select().distinctOn(user.id), + pg: { + text: 'SELECT DISTINCT ON("user"."id") "user".* FROM "user"', + string: 'SELECT DISTINCT ON("user"."id") "user".* FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: customerAlias.select().distinctOn(customerAlias.id_alias), + pg: { + text: 'SELECT DISTINCT ON("customer"."id") "customer"."id" AS "id_alias", "customer"."name" AS "name_alias", "customer"."age" AS "age_alias", "customer"."income" AS "income_alias", "customer"."metadata" AS "metadata_alias" FROM "customer"', + string: 'SELECT DISTINCT ON("customer"."id") "customer"."id" AS "id_alias", "customer"."name" AS "name_alias", "customer"."age" AS "age_alias", "customer"."income" AS "income_alias", "customer"."metadata" AS "metadata_alias" FROM "customer"' + }, + params: [] +}); + +Harness.test({ + query: customerAlias.select(customerAlias.id_alias, customerAlias.name_alias).distinctOn(customerAlias.id_alias), + pg: { + text: 'SELECT DISTINCT ON("customer"."id") "customer"."id" AS "id_alias", "customer"."name" AS "name_alias" FROM "customer"', + string: 'SELECT DISTINCT ON("customer"."id") "customer"."id" AS "id_alias", "customer"."name" AS "name_alias" FROM "customer"' + }, + params: [] +}); diff --git a/test/dialects/distinct-tests.js b/test/dialects/distinct-tests.js deleted file mode 100644 index 9f922bff..00000000 --- a/test/dialects/distinct-tests.js +++ /dev/null @@ -1,132 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var user = Harness.defineUserTable(); - -Harness.test({ - query: user.select(user.id.distinct()), - pg: { - text : 'SELECT DISTINCT("user"."id") FROM "user"', - string: 'SELECT DISTINCT("user"."id") FROM "user"' - }, - sqlite: { - text : 'SELECT DISTINCT("user"."id") FROM "user"', - string: 'SELECT DISTINCT("user"."id") FROM "user"' - }, - mysql: { - text : 'SELECT DISTINCT(`user`.`id`) FROM `user`', - string: 'SELECT DISTINCT(`user`.`id`) FROM `user`' - }, - mssql: { - text : 'SELECT DISTINCT([user].[id]) FROM [user]', - string: 'SELECT DISTINCT([user].[id]) FROM [user]' - }, - oracle: { - text : 'SELECT DISTINCT("user"."id") FROM "user"', - string: 'SELECT DISTINCT("user"."id") FROM "user"' - }, - params: [] -}); - -Harness.test({ - query: user.select(user.id.count().distinct().as('count')), - pg: { - text : 'SELECT COUNT(DISTINCT("user"."id")) AS "count" FROM "user"', - string: 'SELECT COUNT(DISTINCT("user"."id")) AS "count" FROM "user"' - }, - sqlite: { - text : 'SELECT COUNT(DISTINCT("user"."id")) AS "count" FROM "user"', - string: 'SELECT COUNT(DISTINCT("user"."id")) AS "count" FROM "user"' - }, - mysql: { - text : 'SELECT COUNT(DISTINCT(`user`.`id`)) AS `count` FROM `user`', - string: 'SELECT COUNT(DISTINCT(`user`.`id`)) AS `count` FROM `user`' - }, - mssql: { - text : 'SELECT COUNT(DISTINCT([user].[id])) AS [count] FROM [user]', - string: 'SELECT COUNT(DISTINCT([user].[id])) AS [count] FROM [user]' - }, - oracle: { - text : 'SELECT COUNT(DISTINCT("user"."id")) "count" FROM "user"', - string: 'SELECT COUNT(DISTINCT("user"."id")) "count" FROM "user"' - }, - params: [] -}); - -// BELOW HERE TEST DISTINCT ON THE ENTIRE RESULTS SET, NOT JUST ONE COLUMN - -Harness.test({ - query: user.select().distinct(), - pg: { - text : 'SELECT DISTINCT "user".* FROM "user"', - string: 'SELECT DISTINCT "user".* FROM "user"' - }, - sqlite: { - text : 'SELECT DISTINCT "user".* FROM "user"', - string: 'SELECT DISTINCT "user".* FROM "user"' - }, - mysql: { - text : 'SELECT DISTINCT `user`.* FROM `user`', - string: 'SELECT DISTINCT `user`.* FROM `user`' - }, - mssql: { - text : 'SELECT DISTINCT [user].* FROM [user]', - string: 'SELECT DISTINCT [user].* FROM [user]' - }, - oracle: { - text : 'SELECT DISTINCT "user".* FROM "user"', - string: 'SELECT DISTINCT "user".* FROM "user"' - }, - params: [] -}); - -Harness.test({ - query: user.select(user.id).distinct(), - pg: { - text : 'SELECT DISTINCT "user"."id" FROM "user"', - string: 'SELECT DISTINCT "user"."id" FROM "user"' - }, - sqlite: { - text : 'SELECT DISTINCT "user"."id" FROM "user"', - string: 'SELECT DISTINCT "user"."id" FROM "user"' - }, - mysql: { - text : 'SELECT DISTINCT `user`.`id` FROM `user`', - string: 'SELECT DISTINCT `user`.`id` FROM `user`' - }, - mssql: { - text : 'SELECT DISTINCT [user].[id] FROM [user]', - string: 'SELECT DISTINCT [user].[id] FROM [user]' - }, - oracle: { - text : 'SELECT DISTINCT "user"."id" FROM "user"', - string: 'SELECT DISTINCT "user"."id" FROM "user"' - }, - params: [] -}); - -Harness.test({ - query: user.select(user.id,user.name).distinct(), - pg: { - text : 'SELECT DISTINCT "user"."id", "user"."name" FROM "user"', - string: 'SELECT DISTINCT "user"."id", "user"."name" FROM "user"' - }, - sqlite: { - text : 'SELECT DISTINCT "user"."id", "user"."name" FROM "user"', - string: 'SELECT DISTINCT "user"."id", "user"."name" FROM "user"' - }, - mysql: { - text : 'SELECT DISTINCT `user`.`id`, `user`.`name` FROM `user`', - string: 'SELECT DISTINCT `user`.`id`, `user`.`name` FROM `user`' - }, - mssql: { - text : 'SELECT DISTINCT [user].[id], [user].[name] FROM [user]', - string: 'SELECT DISTINCT [user].[id], [user].[name] FROM [user]' - }, - oracle: { - text : 'SELECT DISTINCT "user"."id", "user"."name" FROM "user"', - string: 'SELECT DISTINCT "user"."id", "user"."name" FROM "user"' - }, - params: [] -}); - diff --git a/test/dialects/distinct-tests.ts b/test/dialects/distinct-tests.ts new file mode 100644 index 00000000..bc8c7da1 --- /dev/null +++ b/test/dialects/distinct-tests.ts @@ -0,0 +1,134 @@ +import * as Harness from './support.js'; +const user = Harness.defineUserTable(); + +Harness.test({ + query: user.select(user.id.distinct()), + pg: { + text: 'SELECT DISTINCT("user"."id") FROM "user"', + string: 'SELECT DISTINCT("user"."id") FROM "user"' + }, + sqlite: { + text: 'SELECT DISTINCT("user"."id") FROM "user"', + string: 'SELECT DISTINCT("user"."id") FROM "user"' + }, + mysql: { + text: 'SELECT DISTINCT(`user`.`id`) FROM `user`', + string: 'SELECT DISTINCT(`user`.`id`) FROM `user`' + }, + mssql: { + text: 'SELECT DISTINCT([user].[id]) FROM [user]', + string: 'SELECT DISTINCT([user].[id]) FROM [user]' + }, + oracle: { + text: 'SELECT DISTINCT("user"."id") FROM "user"', + string: 'SELECT DISTINCT("user"."id") FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: user.select( + user.id + .count() + .distinct() + .as('count') + ), + pg: { + text: 'SELECT COUNT(DISTINCT("user"."id")) AS "count" FROM "user"', + string: 'SELECT COUNT(DISTINCT("user"."id")) AS "count" FROM "user"' + }, + sqlite: { + text: 'SELECT COUNT(DISTINCT("user"."id")) AS "count" FROM "user"', + string: 'SELECT COUNT(DISTINCT("user"."id")) AS "count" FROM "user"' + }, + mysql: { + text: 'SELECT COUNT(DISTINCT(`user`.`id`)) AS `count` FROM `user`', + string: 'SELECT COUNT(DISTINCT(`user`.`id`)) AS `count` FROM `user`' + }, + mssql: { + text: 'SELECT COUNT(DISTINCT([user].[id])) AS [count] FROM [user]', + string: 'SELECT COUNT(DISTINCT([user].[id])) AS [count] FROM [user]' + }, + oracle: { + text: 'SELECT COUNT(DISTINCT("user"."id")) "count" FROM "user"', + string: 'SELECT COUNT(DISTINCT("user"."id")) "count" FROM "user"' + }, + params: [] +}); + +// BELOW HERE TEST DISTINCT ON THE ENTIRE RESULTS SET, NOT JUST ONE COLUMN + +Harness.test({ + query: user.select().distinct(), + pg: { + text: 'SELECT DISTINCT "user".* FROM "user"', + string: 'SELECT DISTINCT "user".* FROM "user"' + }, + sqlite: { + text: 'SELECT DISTINCT "user".* FROM "user"', + string: 'SELECT DISTINCT "user".* FROM "user"' + }, + mysql: { + text: 'SELECT DISTINCT `user`.* FROM `user`', + string: 'SELECT DISTINCT `user`.* FROM `user`' + }, + mssql: { + text: 'SELECT DISTINCT [user].* FROM [user]', + string: 'SELECT DISTINCT [user].* FROM [user]' + }, + oracle: { + text: 'SELECT DISTINCT "user".* FROM "user"', + string: 'SELECT DISTINCT "user".* FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: user.select(user.id).distinct(), + pg: { + text: 'SELECT DISTINCT "user"."id" FROM "user"', + string: 'SELECT DISTINCT "user"."id" FROM "user"' + }, + sqlite: { + text: 'SELECT DISTINCT "user"."id" FROM "user"', + string: 'SELECT DISTINCT "user"."id" FROM "user"' + }, + mysql: { + text: 'SELECT DISTINCT `user`.`id` FROM `user`', + string: 'SELECT DISTINCT `user`.`id` FROM `user`' + }, + mssql: { + text: 'SELECT DISTINCT [user].[id] FROM [user]', + string: 'SELECT DISTINCT [user].[id] FROM [user]' + }, + oracle: { + text: 'SELECT DISTINCT "user"."id" FROM "user"', + string: 'SELECT DISTINCT "user"."id" FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: user.select(user.id, user.name).distinct(), + pg: { + text: 'SELECT DISTINCT "user"."id", "user"."name" FROM "user"', + string: 'SELECT DISTINCT "user"."id", "user"."name" FROM "user"' + }, + sqlite: { + text: 'SELECT DISTINCT "user"."id", "user"."name" FROM "user"', + string: 'SELECT DISTINCT "user"."id", "user"."name" FROM "user"' + }, + mysql: { + text: 'SELECT DISTINCT `user`.`id`, `user`.`name` FROM `user`', + string: 'SELECT DISTINCT `user`.`id`, `user`.`name` FROM `user`' + }, + mssql: { + text: 'SELECT DISTINCT [user].[id], [user].[name] FROM [user]', + string: 'SELECT DISTINCT [user].[id], [user].[name] FROM [user]' + }, + oracle: { + text: 'SELECT DISTINCT "user"."id", "user"."name" FROM "user"', + string: 'SELECT DISTINCT "user"."id", "user"."name" FROM "user"' + }, + params: [] +}); diff --git a/test/dialects/drop-table-tests.js b/test/dialects/drop-table-tests.js deleted file mode 100644 index eb183e64..00000000 --- a/test/dialects/drop-table-tests.js +++ /dev/null @@ -1,96 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var post = Harness.definePostTable(); - -Harness.test({ - query: post.drop(), - pg: { - text : 'DROP TABLE "post"', - string: 'DROP TABLE "post"' - }, - sqlite: { - text : 'DROP TABLE "post"', - string: 'DROP TABLE "post"' - }, - mysql: { - text : 'DROP TABLE `post`', - string: 'DROP TABLE `post`' - }, - mssql: { - text : 'DROP TABLE [post]', - string: 'DROP TABLE [post]' - }, - oracle: { - text : 'DROP TABLE "post"', - string: 'DROP TABLE "post"' - }, - params: [] -}); - -Harness.test({ - query: post.drop().ifExists(), - pg: { - text : 'DROP TABLE IF EXISTS "post"', - string: 'DROP TABLE IF EXISTS "post"' - }, - sqlite: { - text : 'DROP TABLE IF EXISTS "post"', - string: 'DROP TABLE IF EXISTS "post"' - }, - mysql: { - text : 'DROP TABLE IF EXISTS `post`', - string: 'DROP TABLE IF EXISTS `post`' - }, - mssql: { - text : 'IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = [post]) BEGIN DROP TABLE [post] END', - string: 'IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = [post]) BEGIN DROP TABLE [post] END' - }, - oracle: { - text : 'BEGIN EXECUTE IMMEDIATE \'DROP TABLE "post"\'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;', - string: 'BEGIN EXECUTE IMMEDIATE \'DROP TABLE "post"\'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;' - }, - params: [] -}); - -Harness.test({ - query: post.drop().cascade(), - pg: { - text : 'DROP TABLE "post" CASCADE', - string: 'DROP TABLE "post" CASCADE' - }, - sqlite: { - text : 'Sqlite do not support CASCADE in DROP TABLE', - throws: true - }, - mysql: { - text : 'DROP TABLE `post` CASCADE', - string: 'DROP TABLE `post` CASCADE' - }, - oracle: { - text : 'DROP TABLE "post" CASCADE CONSTRAINTS', - string: 'DROP TABLE "post" CASCADE CONSTRAINTS' - }, - params: [] -}); - -Harness.test({ - query: post.drop().restrict(), - pg: { - text : 'DROP TABLE "post" RESTRICT', - string: 'DROP TABLE "post" RESTRICT' - }, - sqlite: { - text : 'Sqlite do not support RESTRICT in DROP TABLE', - throws: true - }, - mysql: { - text : 'DROP TABLE `post` RESTRICT', - string: 'DROP TABLE `post` RESTRICT' - }, - oracle: { - text : 'Oracle do not support RESTRICT in DROP TABLE', - throws: true - }, - params: [] -}); diff --git a/test/dialects/drop-table-tests.ts b/test/dialects/drop-table-tests.ts new file mode 100644 index 00000000..f3114985 --- /dev/null +++ b/test/dialects/drop-table-tests.ts @@ -0,0 +1,94 @@ +import * as Harness from './support.js'; +const post = Harness.definePostTable(); + +Harness.test({ + query: post.drop(), + pg: { + text: 'DROP TABLE "post"', + string: 'DROP TABLE "post"' + }, + sqlite: { + text: 'DROP TABLE "post"', + string: 'DROP TABLE "post"' + }, + mysql: { + text: 'DROP TABLE `post`', + string: 'DROP TABLE `post`' + }, + mssql: { + text: 'DROP TABLE [post]', + string: 'DROP TABLE [post]' + }, + oracle: { + text: 'DROP TABLE "post"', + string: 'DROP TABLE "post"' + }, + params: [] +}); + +Harness.test({ + query: post.drop().ifExists(), + pg: { + text: 'DROP TABLE IF EXISTS "post"', + string: 'DROP TABLE IF EXISTS "post"' + }, + sqlite: { + text: 'DROP TABLE IF EXISTS "post"', + string: 'DROP TABLE IF EXISTS "post"' + }, + mysql: { + text: 'DROP TABLE IF EXISTS `post`', + string: 'DROP TABLE IF EXISTS `post`' + }, + mssql: { + text: 'IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = [post]) BEGIN DROP TABLE [post] END', + string: 'IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = [post]) BEGIN DROP TABLE [post] END' + }, + oracle: { + text: 'BEGIN EXECUTE IMMEDIATE \'DROP TABLE "post"\'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;', + string: 'BEGIN EXECUTE IMMEDIATE \'DROP TABLE "post"\'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;' + }, + params: [] +}); + +Harness.test({ + query: post.drop().cascade(), + pg: { + text: 'DROP TABLE "post" CASCADE', + string: 'DROP TABLE "post" CASCADE' + }, + sqlite: { + text: 'Sqlite do not support CASCADE in DROP TABLE', + throws: true + }, + mysql: { + text: 'DROP TABLE `post` CASCADE', + string: 'DROP TABLE `post` CASCADE' + }, + oracle: { + text: 'DROP TABLE "post" CASCADE CONSTRAINTS', + string: 'DROP TABLE "post" CASCADE CONSTRAINTS' + }, + params: [] +}); + +Harness.test({ + query: post.drop().restrict(), + pg: { + text: 'DROP TABLE "post" RESTRICT', + string: 'DROP TABLE "post" RESTRICT' + }, + sqlite: { + text: 'Sqlite do not support RESTRICT in DROP TABLE', + throws: true + }, + mysql: { + text: 'DROP TABLE `post` RESTRICT', + string: 'DROP TABLE `post` RESTRICT' + }, + oracle: { + text: 'Oracle do not support RESTRICT in DROP TABLE', + throws: true + }, + params: [] +}); diff --git a/test/dialects/for-share-tests.js b/test/dialects/for-share-tests.js deleted file mode 100644 index 4b9627fa..00000000 --- a/test/dialects/for-share-tests.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var post = Harness.definePostTable(); -var user = Harness.defineUserTable(); - -Harness.test({ - query: post.select(post.star()).forShare(), - pg: { - text : 'SELECT "post".* FROM "post" FOR SHARE', - string: 'SELECT "post".* FROM "post" FOR SHARE' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.star()).from(post.join(user).on(user.id.equals(post.userId))).where(post.content.equals('foo')).forShare(), - pg: { - text : 'SELECT "post".* FROM "post" INNER JOIN "user" ON ("user"."id" = "post"."userId") WHERE ("post"."content" = $1) FOR SHARE', - string: 'SELECT "post".* FROM "post" INNER JOIN "user" ON ("user"."id" = "post"."userId") WHERE ("post"."content" = \'foo\') FOR SHARE' - }, - params: ["foo"] -}); diff --git a/test/dialects/for-share-tests.ts b/test/dialects/for-share-tests.ts new file mode 100644 index 00000000..ceaa2ea8 --- /dev/null +++ b/test/dialects/for-share-tests.ts @@ -0,0 +1,26 @@ +import * as Harness from './support.js'; +const post = Harness.definePostTable(); +const user = Harness.defineUserTable(); + +Harness.test({ + query: post.select(post.star()).forShare(), + pg: { + text: 'SELECT "post".* FROM "post" FOR SHARE', + string: 'SELECT "post".* FROM "post" FOR SHARE' + }, + params: [] +}); + +Harness.test({ + query: post + .select(post.star()) + .from(post.join(user).on(user.id.equals(post.userId))) + .where(post.content.equals('foo')) + .forShare(), + pg: { + text: 'SELECT "post".* FROM "post" INNER JOIN "user" ON ("user"."id" = "post"."userId") WHERE ("post"."content" = $1) FOR SHARE', + string: + 'SELECT "post".* FROM "post" INNER JOIN "user" ON ("user"."id" = "post"."userId") WHERE ("post"."content" = \'foo\') FOR SHARE' + }, + params: ['foo'] +}); diff --git a/test/dialects/for-update-tests.js b/test/dialects/for-update-tests.js deleted file mode 100644 index 19a01e20..00000000 --- a/test/dialects/for-update-tests.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var post = Harness.definePostTable(); -var user = Harness.defineUserTable(); - -Harness.test({ - query: post.select(post.star()).forUpdate(), - pg: { - text : 'SELECT "post".* FROM "post" FOR UPDATE', - string: 'SELECT "post".* FROM "post" FOR UPDATE' - }, - mysql: { - text : 'SELECT `post`.* FROM `post` FOR UPDATE', - string: 'SELECT `post`.* FROM `post` FOR UPDATE' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.star()).from(post.join(user).on(user.id.equals(post.userId))).where(post.content.equals('foo')).forUpdate(), - pg: { - text : 'SELECT "post".* FROM "post" INNER JOIN "user" ON ("user"."id" = "post"."userId") WHERE ("post"."content" = $1) FOR UPDATE', - string: 'SELECT "post".* FROM "post" INNER JOIN "user" ON ("user"."id" = "post"."userId") WHERE ("post"."content" = \'foo\') FOR UPDATE' - }, - mysql: { - text : 'SELECT `post`.* FROM `post` INNER JOIN `user` ON (`user`.`id` = `post`.`userId`) WHERE (`post`.`content` = ?) FOR UPDATE', - string: 'SELECT `post`.* FROM `post` INNER JOIN `user` ON (`user`.`id` = `post`.`userId`) WHERE (`post`.`content` = \'foo\') FOR UPDATE' - }, - params: ["foo"] -}); diff --git a/test/dialects/for-update-tests.ts b/test/dialects/for-update-tests.ts new file mode 100644 index 00000000..dd1bddb3 --- /dev/null +++ b/test/dialects/for-update-tests.ts @@ -0,0 +1,35 @@ +import * as Harness from './support.js'; +const post = Harness.definePostTable(); +const user = Harness.defineUserTable(); + +Harness.test({ + query: post.select(post.star()).forUpdate(), + pg: { + text: 'SELECT "post".* FROM "post" FOR UPDATE', + string: 'SELECT "post".* FROM "post" FOR UPDATE' + }, + mysql: { + text: 'SELECT `post`.* FROM `post` FOR UPDATE', + string: 'SELECT `post`.* FROM `post` FOR UPDATE' + }, + params: [] +}); + +Harness.test({ + query: post + .select(post.star()) + .from(post.join(user).on(user.id.equals(post.userId))) + .where(post.content.equals('foo')) + .forUpdate(), + pg: { + text: 'SELECT "post".* FROM "post" INNER JOIN "user" ON ("user"."id" = "post"."userId") WHERE ("post"."content" = $1) FOR UPDATE', + string: + 'SELECT "post".* FROM "post" INNER JOIN "user" ON ("user"."id" = "post"."userId") WHERE ("post"."content" = \'foo\') FOR UPDATE' + }, + mysql: { + text: 'SELECT `post`.* FROM `post` INNER JOIN `user` ON (`user`.`id` = `post`.`userId`) WHERE (`post`.`content` = ?) FOR UPDATE', + string: + "SELECT `post`.* FROM `post` INNER JOIN `user` ON (`user`.`id` = `post`.`userId`) WHERE (`post`.`content` = 'foo') FOR UPDATE" + }, + params: ['foo'] +}); diff --git a/test/dialects/from-clause-tests.js b/test/dialects/from-clause-tests.js deleted file mode 100644 index 673087db..00000000 --- a/test/dialects/from-clause-tests.js +++ /dev/null @@ -1,93 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var user = Harness.defineUserTable(); -var post = Harness.definePostTable(); - -Harness.test({ - query: user.select(user.star()).from(user).from(post), - pg: { - text : 'SELECT "user".* FROM "user" , "post"', - string: 'SELECT "user".* FROM "user" , "post"' - }, - sqlite: { - text : 'SELECT "user".* FROM "user" , "post"', - string: 'SELECT "user".* FROM "user" , "post"' - }, - mysql: { - text : 'SELECT `user`.* FROM `user` , `post`', - string: 'SELECT `user`.* FROM `user` , `post`' - }, - mssql: { - text : 'SELECT [user].* FROM [user] , [post]', - string: 'SELECT [user].* FROM [user] , [post]' - }, - oracle: { - text : 'SELECT "user".* FROM "user" , "post"', - string: 'SELECT "user".* FROM "user" , "post"' - } -}); - -Harness.test({ - query: user.select(user.star(), post.star()).from(user).from(post), - pg: { - text : 'SELECT "user".*, "post".* FROM "user" , "post"', - string: 'SELECT "user".*, "post".* FROM "user" , "post"' - }, - sqlite: { - text : 'SELECT "user".*, "post".* FROM "user" , "post"', - string: 'SELECT "user".*, "post".* FROM "user" , "post"' - }, - mysql: { - text : 'SELECT `user`.*, `post`.* FROM `user` , `post`', - string: 'SELECT `user`.*, `post`.* FROM `user` , `post`' - }, - mssql: { - text : 'SELECT [user].*, [post].* FROM [user] , [post]', - string: 'SELECT [user].*, [post].* FROM [user] , [post]' - }, - oracle: { - text : 'SELECT "user".*, "post".* FROM "user" , "post"', - string: 'SELECT "user".*, "post".* FROM "user" , "post"' - } -}); - -Harness.test({ - query: user.select(user.star()).from(user, post), - pg: { - text : 'SELECT "user".* FROM "user" , "post"', - string: 'SELECT "user".* FROM "user" , "post"' - }, - sqlite: { - text : 'SELECT "user".* FROM "user" , "post"', - string: 'SELECT "user".* FROM "user" , "post"' - }, - mysql: { - text : 'SELECT `user`.* FROM `user` , `post`', - string: 'SELECT `user`.* FROM `user` , `post`' - }, - oracle: { - text : 'SELECT "user".* FROM "user" , "post"', - string: 'SELECT "user".* FROM "user" , "post"' - } -}); - -Harness.test({ - query: user.select(user.star()).from([user, post]), - pg: { - text : 'SELECT "user".* FROM "user" , "post"', - string: 'SELECT "user".* FROM "user" , "post"' - }, - sqlite: { - text : 'SELECT "user".* FROM "user" , "post"', - string: 'SELECT "user".* FROM "user" , "post"' - }, - mysql: { - text : 'SELECT `user`.* FROM `user` , `post`', - string: 'SELECT `user`.* FROM `user` , `post`' - }, - oracle: { - text : 'SELECT "user".* FROM "user" , "post"', - string: 'SELECT "user".* FROM "user" , "post"' - } -}); \ No newline at end of file diff --git a/test/dialects/from-clause-tests.ts b/test/dialects/from-clause-tests.ts new file mode 100644 index 00000000..2fb3efa8 --- /dev/null +++ b/test/dialects/from-clause-tests.ts @@ -0,0 +1,97 @@ +import * as Harness from './support.js'; +const post = Harness.definePostTable(); +const user = Harness.defineUserTable(); + +Harness.test({ + query: user + .select(user.star()) + .from(user) + .from(post), + pg: { + text: 'SELECT "user".* FROM "user" , "post"', + string: 'SELECT "user".* FROM "user" , "post"' + }, + sqlite: { + text: 'SELECT "user".* FROM "user" , "post"', + string: 'SELECT "user".* FROM "user" , "post"' + }, + mysql: { + text: 'SELECT `user`.* FROM `user` , `post`', + string: 'SELECT `user`.* FROM `user` , `post`' + }, + mssql: { + text: 'SELECT [user].* FROM [user] , [post]', + string: 'SELECT [user].* FROM [user] , [post]' + }, + oracle: { + text: 'SELECT "user".* FROM "user" , "post"', + string: 'SELECT "user".* FROM "user" , "post"' + } +}); + +Harness.test({ + query: user + .select(user.star(), post.star()) + .from(user) + .from(post), + pg: { + text: 'SELECT "user".*, "post".* FROM "user" , "post"', + string: 'SELECT "user".*, "post".* FROM "user" , "post"' + }, + sqlite: { + text: 'SELECT "user".*, "post".* FROM "user" , "post"', + string: 'SELECT "user".*, "post".* FROM "user" , "post"' + }, + mysql: { + text: 'SELECT `user`.*, `post`.* FROM `user` , `post`', + string: 'SELECT `user`.*, `post`.* FROM `user` , `post`' + }, + mssql: { + text: 'SELECT [user].*, [post].* FROM [user] , [post]', + string: 'SELECT [user].*, [post].* FROM [user] , [post]' + }, + oracle: { + text: 'SELECT "user".*, "post".* FROM "user" , "post"', + string: 'SELECT "user".*, "post".* FROM "user" , "post"' + } +}); + +Harness.test({ + query: user.select(user.star()).from(user, post), + pg: { + text: 'SELECT "user".* FROM "user" , "post"', + string: 'SELECT "user".* FROM "user" , "post"' + }, + sqlite: { + text: 'SELECT "user".* FROM "user" , "post"', + string: 'SELECT "user".* FROM "user" , "post"' + }, + mysql: { + text: 'SELECT `user`.* FROM `user` , `post`', + string: 'SELECT `user`.* FROM `user` , `post`' + }, + oracle: { + text: 'SELECT "user".* FROM "user" , "post"', + string: 'SELECT "user".* FROM "user" , "post"' + } +}); + +Harness.test({ + query: user.select(user.star()).from([user, post]), + pg: { + text: 'SELECT "user".* FROM "user" , "post"', + string: 'SELECT "user".* FROM "user" , "post"' + }, + sqlite: { + text: 'SELECT "user".* FROM "user" , "post"', + string: 'SELECT "user".* FROM "user" , "post"' + }, + mysql: { + text: 'SELECT `user`.* FROM `user` , `post`', + string: 'SELECT `user`.* FROM `user` , `post`' + }, + oracle: { + text: 'SELECT "user".* FROM "user" , "post"', + string: 'SELECT "user".* FROM "user" , "post"' + } +}); diff --git a/test/dialects/function-tests.js b/test/dialects/function-tests.js deleted file mode 100644 index 702d8c63..00000000 --- a/test/dialects/function-tests.js +++ /dev/null @@ -1,82 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var Sql = require('../../lib'); - -var post = Harness.definePostTable(); - -Harness.test({ - query: post.select(Sql.functions.LENGTH(post.content)), - pg: { - text : 'SELECT LENGTH("post"."content") FROM "post"', - string: 'SELECT LENGTH("post"."content") FROM "post"' - }, - sqlite: { - text : 'SELECT LENGTH("post"."content") FROM "post"', - string: 'SELECT LENGTH("post"."content") FROM "post"' - }, - mysql: { - text : 'SELECT LENGTH(`post`.`content`) FROM `post`', - string: 'SELECT LENGTH(`post`.`content`) FROM `post`' - }, - mssql: { - text : 'SELECT LEN([post].[content]) FROM [post]', - string: 'SELECT LEN([post].[content]) FROM [post]' - }, - oracle: { - text : 'SELECT LENGTH("post"."content") FROM "post"', - string: 'SELECT LENGTH("post"."content") FROM "post"' - }, - params: [] -}); - -Harness.test({ - query: post.select(Sql.functions.LEFT(post.content,4)), - pg: { - text : 'SELECT LEFT("post"."content", $1) FROM "post"', - string: 'SELECT LEFT("post"."content", 4) FROM "post"' - }, - sqlite: { - text : 'SELECT SUBSTR("post"."content", 1, $1) FROM "post"', - string: 'SELECT SUBSTR("post"."content", 1, 4) FROM "post"' - }, - mysql: { - text : 'SELECT LEFT(`post`.`content`, ?) FROM `post`', - string: 'SELECT LEFT(`post`.`content`, 4) FROM `post`' - }, - mssql: { - text : 'SELECT LEFT([post].[content], @1) FROM [post]', - string: 'SELECT LEFT([post].[content], 4) FROM [post]' - }, - oracle: { - text : 'SELECT LEFT("post"."content", :1) FROM "post"', - string: 'SELECT LEFT("post"."content", 4) FROM "post"' - }, - params: [4] -}); - -Harness.test({ - query: post.select(Sql.functions.RIGHT(post.content,4)), - pg: { - text : 'SELECT RIGHT("post"."content", $1) FROM "post"', - string: 'SELECT RIGHT("post"."content", 4) FROM "post"' - }, - sqlite: { - text : 'SELECT SUBSTR("post"."content", -$1) FROM "post"', - string: 'SELECT SUBSTR("post"."content", -4) FROM "post"' - }, - mysql: { - text : 'SELECT RIGHT(`post`.`content`, ?) FROM `post`', - string: 'SELECT RIGHT(`post`.`content`, 4) FROM `post`' - }, - mssql: { - text : 'SELECT RIGHT([post].[content], @1) FROM [post]', - string: 'SELECT RIGHT([post].[content], 4) FROM [post]' - }, - oracle: { - text : 'SELECT RIGHT("post"."content", :1) FROM "post"', - string: 'SELECT RIGHT("post"."content", 4) FROM "post"' - }, - params: [4] -}); - diff --git a/test/dialects/function-tests.ts b/test/dialects/function-tests.ts new file mode 100644 index 00000000..e6e742e4 --- /dev/null +++ b/test/dialects/function-tests.ts @@ -0,0 +1,79 @@ +import * as Harness from './support.js'; +import { Sql } from '../../dist/lib.js'; +const post = Harness.definePostTable(); +const instance = new Sql('postgres'); + +Harness.test({ + query: post.select(instance.functions.LENGTH(post.content)), + pg: { + text: 'SELECT LENGTH("post"."content") FROM "post"', + string: 'SELECT LENGTH("post"."content") FROM "post"' + }, + sqlite: { + text: 'SELECT LENGTH("post"."content") FROM "post"', + string: 'SELECT LENGTH("post"."content") FROM "post"' + }, + mysql: { + text: 'SELECT LENGTH(`post`.`content`) FROM `post`', + string: 'SELECT LENGTH(`post`.`content`) FROM `post`' + }, + mssql: { + text: 'SELECT LEN([post].[content]) FROM [post]', + string: 'SELECT LEN([post].[content]) FROM [post]' + }, + oracle: { + text: 'SELECT LENGTH("post"."content") FROM "post"', + string: 'SELECT LENGTH("post"."content") FROM "post"' + }, + params: [] +}); + +Harness.test({ + query: post.select(instance.functions.LEFT(post.content, 4)), + pg: { + text: 'SELECT LEFT("post"."content", $1) FROM "post"', + string: 'SELECT LEFT("post"."content", 4) FROM "post"' + }, + sqlite: { + text: 'SELECT SUBSTR("post"."content", 1, $1) FROM "post"', + string: 'SELECT SUBSTR("post"."content", 1, 4) FROM "post"' + }, + mysql: { + text: 'SELECT LEFT(`post`.`content`, ?) FROM `post`', + string: 'SELECT LEFT(`post`.`content`, 4) FROM `post`' + }, + mssql: { + text: 'SELECT LEFT([post].[content], @1) FROM [post]', + string: 'SELECT LEFT([post].[content], 4) FROM [post]' + }, + oracle: { + text: 'SELECT LEFT("post"."content", :1) FROM "post"', + string: 'SELECT LEFT("post"."content", 4) FROM "post"' + }, + params: [4] +}); + +Harness.test({ + query: post.select(instance.functions.RIGHT(post.content, 4)), + pg: { + text: 'SELECT RIGHT("post"."content", $1) FROM "post"', + string: 'SELECT RIGHT("post"."content", 4) FROM "post"' + }, + sqlite: { + text: 'SELECT SUBSTR("post"."content", -$1) FROM "post"', + string: 'SELECT SUBSTR("post"."content", -4) FROM "post"' + }, + mysql: { + text: 'SELECT RIGHT(`post`.`content`, ?) FROM `post`', + string: 'SELECT RIGHT(`post`.`content`, 4) FROM `post`' + }, + mssql: { + text: 'SELECT RIGHT([post].[content], @1) FROM [post]', + string: 'SELECT RIGHT([post].[content], 4) FROM [post]' + }, + oracle: { + text: 'SELECT RIGHT("post"."content", :1) FROM "post"', + string: 'SELECT RIGHT("post"."content", 4) FROM "post"' + }, + params: [4] +}); diff --git a/test/dialects/group-by-tests.js b/test/dialects/group-by-tests.js deleted file mode 100644 index 673b5639..00000000 --- a/test/dialects/group-by-tests.js +++ /dev/null @@ -1,129 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var post = Harness.definePostTable(); - -Harness.test({ - query: post.select(post.content).group(post.userId), - pg: { - text : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"', - string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"' - }, - sqlite: { - text : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"', - string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"' - }, - mysql: { - text : 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`', - string: 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`' - }, - mssql: { - text : 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId]', - string: 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId]' - }, - oracle: { - text : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"', - string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.content).group(post.userId, post.id), - pg: { - text : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', - string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' - }, - sqlite: { - text : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', - string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' - }, - mysql: { - text : 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`, `post`.`id`', - string: 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`, `post`.`id`' - }, - mssql: { - text : 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId], [post].[id]', - string: 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId], [post].[id]' - }, - oracle: { - text : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', - string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.content.arrayAgg()).group(post.userId), - pg: { - text : 'SELECT array_agg("post"."content") AS "contents" FROM "post" GROUP BY "post"."userId"', - string: 'SELECT array_agg("post"."content") AS "contents" FROM "post" GROUP BY "post"."userId"' - }, - sqlite: { - text : 'SELECT GROUP_CONCAT("post"."content") AS "contents" FROM "post" GROUP BY "post"."userId"', - string: 'SELECT GROUP_CONCAT("post"."content") AS "contents" FROM "post" GROUP BY "post"."userId"' - }, - mysql: { - text : 'SELECT GROUP_CONCAT(`post`.`content`) AS `contents` FROM `post` GROUP BY `post`.`userId`', - string: 'SELECT GROUP_CONCAT(`post`.`content`) AS `contents` FROM `post` GROUP BY `post`.`userId`' - }, - mssql: { - text : 'SQL Server does not support array_agg.', - throws: true - }, - oracle: { - text : 'Oracle does not support array_agg.', - throws: true - }, - params: [] -}); - -Harness.test({ - query: post.select(post.content.arrayAgg('post contents')).group(post.userId), - pg: { - text : 'SELECT array_agg("post"."content") AS "post contents" FROM "post" GROUP BY "post"."userId"', - string: 'SELECT array_agg("post"."content") AS "post contents" FROM "post" GROUP BY "post"."userId"' - }, - sqlite: { - text : 'SELECT GROUP_CONCAT("post"."content") AS "post contents" FROM "post" GROUP BY "post"."userId"', - string: 'SELECT GROUP_CONCAT("post"."content") AS "post contents" FROM "post" GROUP BY "post"."userId"' - }, - mysql: { - text : 'SELECT GROUP_CONCAT(`post`.`content`) AS `post contents` FROM `post` GROUP BY `post`.`userId`', - string: 'SELECT GROUP_CONCAT(`post`.`content`) AS `post contents` FROM `post` GROUP BY `post`.`userId`' - }, - mssql: { - text : 'SQL Server does not support array_agg.', - throws: true - }, - oracle: { - text : 'Oracle does not support array_agg.', - throws: true - }, - params: [] -}); - -Harness.test({ - query: post.select(post.content).group([post.userId, post.id]), - pg: { - text : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', - string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' - }, - sqlite: { - text : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', - string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' - }, - mysql: { - text : 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`, `post`.`id`', - string: 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`, `post`.`id`' - }, - mssql: { - text : 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId], [post].[id]', - string: 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId], [post].[id]' - }, - oracel: { - text : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', - string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' - }, - params: [] -}); diff --git a/test/dialects/group-by-tests.ts b/test/dialects/group-by-tests.ts new file mode 100644 index 00000000..c5c207af --- /dev/null +++ b/test/dialects/group-by-tests.ts @@ -0,0 +1,127 @@ +import * as Harness from './support.js'; +const post = Harness.definePostTable(); + +Harness.test({ + query: post.select(post.content).group(post.userId), + pg: { + text: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"', + string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"' + }, + sqlite: { + text: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"', + string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"' + }, + mysql: { + text: 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`', + string: 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`' + }, + mssql: { + text: 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId]', + string: 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId]' + }, + oracle: { + text: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"', + string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.content).group(post.userId, post.id), + pg: { + text: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', + string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' + }, + sqlite: { + text: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', + string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' + }, + mysql: { + text: 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`, `post`.`id`', + string: 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`, `post`.`id`' + }, + mssql: { + text: 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId], [post].[id]', + string: 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId], [post].[id]' + }, + oracle: { + text: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', + string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.content.arrayAgg()).group(post.userId), + pg: { + text: 'SELECT array_agg("post"."content") AS "contents" FROM "post" GROUP BY "post"."userId"', + string: 'SELECT array_agg("post"."content") AS "contents" FROM "post" GROUP BY "post"."userId"' + }, + sqlite: { + text: 'SELECT GROUP_CONCAT("post"."content") AS "contents" FROM "post" GROUP BY "post"."userId"', + string: 'SELECT GROUP_CONCAT("post"."content") AS "contents" FROM "post" GROUP BY "post"."userId"' + }, + mysql: { + text: 'SELECT GROUP_CONCAT(`post`.`content`) AS `contents` FROM `post` GROUP BY `post`.`userId`', + string: 'SELECT GROUP_CONCAT(`post`.`content`) AS `contents` FROM `post` GROUP BY `post`.`userId`' + }, + mssql: { + text: 'SQL Server does not support array_agg.', + throws: true + }, + oracle: { + text: 'Oracle does not support array_agg.', + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.select(post.content.arrayAgg('post contents')).group(post.userId), + pg: { + text: 'SELECT array_agg("post"."content") AS "post contents" FROM "post" GROUP BY "post"."userId"', + string: 'SELECT array_agg("post"."content") AS "post contents" FROM "post" GROUP BY "post"."userId"' + }, + sqlite: { + text: 'SELECT GROUP_CONCAT("post"."content") AS "post contents" FROM "post" GROUP BY "post"."userId"', + string: 'SELECT GROUP_CONCAT("post"."content") AS "post contents" FROM "post" GROUP BY "post"."userId"' + }, + mysql: { + text: 'SELECT GROUP_CONCAT(`post`.`content`) AS `post contents` FROM `post` GROUP BY `post`.`userId`', + string: 'SELECT GROUP_CONCAT(`post`.`content`) AS `post contents` FROM `post` GROUP BY `post`.`userId`' + }, + mssql: { + text: 'SQL Server does not support array_agg.', + throws: true + }, + oracle: { + text: 'Oracle does not support array_agg.', + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.select(post.content).group([post.userId, post.id]), + pg: { + text: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', + string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' + }, + sqlite: { + text: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', + string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' + }, + mysql: { + text: 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`, `post`.`id`', + string: 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`, `post`.`id`' + }, + mssql: { + text: 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId], [post].[id]', + string: 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId], [post].[id]' + }, + oracel: { + text: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', + string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' + }, + params: [] +}); diff --git a/test/dialects/having-tests.js b/test/dialects/having-tests.js deleted file mode 100644 index 5f8f9cc7..00000000 --- a/test/dialects/having-tests.js +++ /dev/null @@ -1,79 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var post = Harness.definePostTable(); - -Harness.test({ - query : post.select(post.userId, post.content.count()).group(post.userId).having(post.userId.gt(10)), - pg : { - text : 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1)', - string: 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > 10)' - }, - sqlite: { - text : 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1)', - string: 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > 10)' - }, - mysql : { - text : 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > ?)', - string: 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > 10)' - }, - mssql : { - text : 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > @1)', - string: 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > 10)' - }, - oracle: { - text : 'SELECT "post"."userId", COUNT("post"."content") "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > :1)', - string: 'SELECT "post"."userId", COUNT("post"."content") "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > 10)' - }, - params: [10] -}); - -Harness.test({ - query : post.select(post.userId, post.content.count()).group(post.userId).having(post.userId.gt(10), post.userId.lt(100)), - pg : { - text : 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1) AND ("post"."userId" < $2)', - string: 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > 10) AND ("post"."userId" < 100)' - }, - sqlite: { - text : 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1) AND ("post"."userId" < $2)', - string: 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > 10) AND ("post"."userId" < 100)' - }, - mysql : { - text : 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > ?) AND (`post`.`userId` < ?)', - string: 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > 10) AND (`post`.`userId` < 100)' - }, - mssql : { - text : 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > @1) AND ([post].[userId] < @2)', - string: 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > 10) AND ([post].[userId] < 100)' - }, - oracle: { - text : 'SELECT "post"."userId", COUNT("post"."content") "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > :1) AND ("post"."userId" < :2)', - string: 'SELECT "post"."userId", COUNT("post"."content") "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > 10) AND ("post"."userId" < 100)' - }, - params: [10, 100] -}); - -Harness.test({ - query : post.select(post.userId, post.content.count()).group(post.userId).having([post.userId.gt(10), post.userId.lt(100)]), - pg : { - text : 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1) AND ("post"."userId" < $2)', - string: 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > 10) AND ("post"."userId" < 100)' - }, - sqlite: { - text : 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1) AND ("post"."userId" < $2)', - string: 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > 10) AND ("post"."userId" < 100)' - }, - mysql : { - text : 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > ?) AND (`post`.`userId` < ?)', - string: 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > 10) AND (`post`.`userId` < 100)' - }, - mssql : { - text : 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > @1) AND ([post].[userId] < @2)', - string: 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > 10) AND ([post].[userId] < 100)' - }, - oracle: { - text : 'SELECT "post"."userId", COUNT("post"."content") "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > :1) AND ("post"."userId" < :2)', - string: 'SELECT "post"."userId", COUNT("post"."content") "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > 10) AND ("post"."userId" < 100)' - }, - params: [10, 100] -}); diff --git a/test/dialects/having-tests.ts b/test/dialects/having-tests.ts new file mode 100644 index 00000000..a46b184d --- /dev/null +++ b/test/dialects/having-tests.ts @@ -0,0 +1,116 @@ +import * as Harness from './support.js'; +const post = Harness.definePostTable(); + +Harness.test({ + query: post + .select(post.userId, post.content.count()) + .group(post.userId) + .having(post.userId.gt(10)), + pg: { + text: + 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1)', + string: + 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > 10)' + }, + sqlite: { + text: + 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1)', + string: + 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > 10)' + }, + mysql: { + text: + 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > ?)', + string: + 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > 10)' + }, + mssql: { + text: + 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > @1)', + string: + 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > 10)' + }, + oracle: { + text: + 'SELECT "post"."userId", COUNT("post"."content") "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > :1)', + string: + 'SELECT "post"."userId", COUNT("post"."content") "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > 10)' + }, + params: [10] +}); + +Harness.test({ + query: post + .select(post.userId, post.content.count()) + .group(post.userId) + .having(post.userId.gt(10), post.userId.lt(100)), + pg: { + text: + 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1) AND ("post"."userId" < $2)', + string: + 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > 10) AND ("post"."userId" < 100)' + }, + sqlite: { + text: + 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1) AND ("post"."userId" < $2)', + string: + 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > 10) AND ("post"."userId" < 100)' + }, + mysql: { + text: + 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > ?) AND (`post`.`userId` < ?)', + string: + 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > 10) AND (`post`.`userId` < 100)' + }, + mssql: { + text: + 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > @1) AND ([post].[userId] < @2)', + string: + 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > 10) AND ([post].[userId] < 100)' + }, + oracle: { + text: + 'SELECT "post"."userId", COUNT("post"."content") "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > :1) AND ("post"."userId" < :2)', + string: + 'SELECT "post"."userId", COUNT("post"."content") "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > 10) AND ("post"."userId" < 100)' + }, + params: [10, 100] +}); + +Harness.test({ + query: post + .select(post.userId, post.content.count()) + .group(post.userId) + .having([post.userId.gt(10), post.userId.lt(100)]), + pg: { + text: + 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1) AND ("post"."userId" < $2)', + string: + 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > 10) AND ("post"."userId" < 100)' + }, + sqlite: { + text: + 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1) AND ("post"."userId" < $2)', + string: + 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > 10) AND ("post"."userId" < 100)' + }, + mysql: { + text: + 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > ?) AND (`post`.`userId` < ?)', + string: + 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > 10) AND (`post`.`userId` < 100)' + }, + mssql: { + text: + 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > @1) AND ([post].[userId] < @2)', + string: + 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > 10) AND ([post].[userId] < 100)' + }, + oracle: { + text: + 'SELECT "post"."userId", COUNT("post"."content") "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > :1) AND ("post"."userId" < :2)', + string: + 'SELECT "post"."userId", COUNT("post"."content") "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > 10) AND ("post"."userId" < 100)' + }, + params: [10, 100] +}); diff --git a/test/dialects/hstore-tests.js b/test/dialects/hstore-tests.js deleted file mode 100644 index 54ba2d22..00000000 --- a/test/dialects/hstore-tests.js +++ /dev/null @@ -1,25 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var customer = Harness.defineCustomerTable(); -var Sql = require('../../lib').setDialect('postgres'); - -Harness.test({ - query: customer.update({ - metadata: customer.metadata.concat(Sql.functions.HSTORE('age', 20)) - }), - pg: { - text : 'UPDATE "customer" SET "metadata" = ("customer"."metadata" || HSTORE($1, $2))', - string: 'UPDATE "customer" SET "metadata" = ("customer"."metadata" || HSTORE(\'age\', 20))' - }, - params: ['age', 20] -}); - -Harness.test({ - query: customer.select(customer.metadata.key('age')), - pg: { - text : 'SELECT ("customer"."metadata" -> $1) FROM "customer"', - string: 'SELECT ("customer"."metadata" -> \'age\') FROM "customer"' - }, - params: ['age'] -}); diff --git a/test/dialects/hstore-tests.ts b/test/dialects/hstore-tests.ts new file mode 100644 index 00000000..9e51243f --- /dev/null +++ b/test/dialects/hstore-tests.ts @@ -0,0 +1,24 @@ +import * as Harness from './support.js'; +import { Sql } from '../../dist/lib.js'; +const customer = Harness.defineCustomerTable(); +const instance = new Sql('postgres'); + +Harness.test({ + query: customer.update({ + metadata: customer.metadata.concat(instance.functions.HSTORE('age', 20)) + }), + pg: { + text: 'UPDATE "customer" SET "metadata" = ("customer"."metadata" || HSTORE($1, $2))', + string: 'UPDATE "customer" SET "metadata" = ("customer"."metadata" || HSTORE(\'age\', 20))' + }, + params: ['age', 20] +}); + +Harness.test({ + query: customer.select(customer.metadata.key('age')), + pg: { + text: 'SELECT ("customer"."metadata" -> $1) FROM "customer"', + string: 'SELECT ("customer"."metadata" -> \'age\') FROM "customer"' + }, + params: ['age'] +}); diff --git a/test/dialects/ilike-tests.js b/test/dialects/ilike-tests.js deleted file mode 100644 index aba487ee..00000000 --- a/test/dialects/ilike-tests.js +++ /dev/null @@ -1,45 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var post = Harness.definePostTable(); -var user = Harness.defineUserTable(); -var Sql = require('../../lib').setDialect('postgres'); - -Harness.test({ - query: post.select(post.content, post.userId).where(post.content.ilike('A%')), - pg: { - text : 'SELECT "post"."content", "post"."userId" FROM "post" WHERE ("post"."content" ILIKE $1)', - string: 'SELECT "post"."content", "post"."userId" FROM "post" WHERE ("post"."content" ILIKE \'A%\')' - }, - params: ['A%'] -}); - -Harness.test({ - query: post.insert(post.content, post.userId) - .select('\'test\'', user.id).from(user).where(user.name.ilike('A%')), - pg: { - text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" ILIKE $1)', - string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" ILIKE \'A%\')' - }, - params: ['A%'] -}); - -Harness.test({ - query: post.insert([post.content, post.userId]) - .select('\'test\'', user.id).from(user).where(user.name.ilike('A%')), - pg: { - text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" ILIKE $1)', - string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" ILIKE \'A%\')' - }, - params: ['A%'] -}); - -Harness.test({ - query: post.insert(post.userId) - .select(user.id).from(user).where(user.name.ilike('A%')), - pg: { - text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" ILIKE $1)', - string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" ILIKE \'A%\')' - }, - params: ['A%'] -}); diff --git a/test/dialects/ilike-tests.ts b/test/dialects/ilike-tests.ts new file mode 100644 index 00000000..be6bb510 --- /dev/null +++ b/test/dialects/ilike-tests.ts @@ -0,0 +1,51 @@ +import * as Harness from './support.js'; +const post = Harness.definePostTable(); +const user = Harness.defineUserTable(); + +Harness.test({ + query: post.select(post.content, post.userId).where(post.content.ilike('A%')), + pg: { + text: 'SELECT "post"."content", "post"."userId" FROM "post" WHERE ("post"."content" ILIKE $1)', + string: 'SELECT "post"."content", "post"."userId" FROM "post" WHERE ("post"."content" ILIKE \'A%\')' + }, + params: ['A%'] +}); + +Harness.test({ + query: post + .insert(post.content, post.userId) + .select("'test'", user.id) + .from(user) + .where(user.name.ilike('A%')), + pg: { + text: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" ILIKE $1)', + string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" ILIKE \'A%\')' + }, + params: ['A%'] +}); + +Harness.test({ + query: post + .insert([post.content, post.userId]) + .select("'test'", user.id) + .from(user) + .where(user.name.ilike('A%')), + pg: { + text: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" ILIKE $1)', + string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" ILIKE \'A%\')' + }, + params: ['A%'] +}); + +Harness.test({ + query: post + .insert(post.userId) + .select(user.id) + .from(user) + .where(user.name.ilike('A%')), + pg: { + text: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" ILIKE $1)', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" ILIKE \'A%\')' + }, + params: ['A%'] +}); diff --git a/test/dialects/in-clause-tests.js b/test/dialects/in-clause-tests.js deleted file mode 100644 index 513c7243..00000000 --- a/test/dialects/in-clause-tests.js +++ /dev/null @@ -1,179 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var post = Harness.definePostTable(); - -Harness.test({ - query: post.select(post.star()).where(post.id.in([])), - pg: { - text : 'SELECT "post".* FROM "post" WHERE (1=0)', - string: 'SELECT "post".* FROM "post" WHERE (1=0)' - }, - sqlite: { - text : 'SELECT "post".* FROM "post" WHERE (1=0)', - string: 'SELECT "post".* FROM "post" WHERE (1=0)' - }, - mysql: { - text : 'SELECT `post`.* FROM `post` WHERE (1=0)', - string: 'SELECT `post`.* FROM `post` WHERE (1=0)' - }, - mssql: { - text : 'SELECT [post].* FROM [post] WHERE (1=0)', - string: 'SELECT [post].* FROM [post] WHERE (1=0)' - }, - oracle: { - text : 'SELECT "post".* FROM "post" WHERE (1=0)', - string: 'SELECT "post".* FROM "post" WHERE (1=0)' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.star()).where(post.id.in([1])), - pg: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IN ($1))', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1))' - }, - sqlite: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IN ($1))', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1))' - }, - mysql: { - text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (?))', - string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (1))' - }, - mssql: { - text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (@1))', - string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (1))' - }, - oracle: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (:1))', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1))' - }, - params: [1] -}); - -Harness.test({ - query: post.select(post.star()).where(post.id.in([null])), - pg: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)' - }, - sqlite: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)' - }, - mysql: { - text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NULL)', - string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NULL)' - }, - mssql: { - text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NULL)', - string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NULL)' - }, - oracle: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.star()).where(post.id.in([1, 2])), - pg: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IN ($1, $2))', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2))' - }, - sqlite: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IN ($1, $2))', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2))' - }, - mysql: { - text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (?, ?))', - string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (1, 2))' - }, - mssql: { - text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (@1, @2))', - string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (1, 2))' - }, - oracle: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (:1, :2))', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2))' - }, - params: [1, 2] -}); - -Harness.test({ - query: post.select(post.star()).where(post.id.in([null, null])), - pg: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)' - }, - sqlite: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)' - }, - mysql: { - text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NULL)', - string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NULL)' - }, - mssql: { - text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NULL)', - string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NULL)' - }, - oracle: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.star()).where(post.id.in([1, null, 2])), - pg: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IN ($1, $2) OR "post"."id" IS NULL)', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2) OR "post"."id" IS NULL)' - }, - sqlite: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IN ($1, $2) OR "post"."id" IS NULL)', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2) OR "post"."id" IS NULL)' - }, - mysql: { - text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (?, ?) OR `post`.`id` IS NULL)', - string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (1, 2) OR `post`.`id` IS NULL)' - }, - mssql: { - text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (@1, @2) OR [post].[id] IS NULL)', - string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (1, 2) OR [post].[id] IS NULL)' - }, - oracle: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (:1, :2) OR "post"."id" IS NULL)', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2) OR "post"."id" IS NULL)' - }, - params: [1, 2] -}); - -Harness.test({ - query: post.select(post.star()).where(post.id.in([1, null, 2, null])), - pg: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IN ($1, $2) OR "post"."id" IS NULL)', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2) OR "post"."id" IS NULL)' - }, - sqlite: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IN ($1, $2) OR "post"."id" IS NULL)', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2) OR "post"."id" IS NULL)' - }, - mysql: { - text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (?, ?) OR `post`.`id` IS NULL)', - string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (1, 2) OR `post`.`id` IS NULL)' - }, - mssql: { - text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (@1, @2) OR [post].[id] IS NULL)', - string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (1, 2) OR [post].[id] IS NULL)' - }, - oracle: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (:1, :2) OR "post"."id" IS NULL)', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2) OR "post"."id" IS NULL)' - }, - params: [1, 2] -}); diff --git a/test/dialects/in-clause-tests.ts b/test/dialects/in-clause-tests.ts new file mode 100644 index 00000000..1f6ac719 --- /dev/null +++ b/test/dialects/in-clause-tests.ts @@ -0,0 +1,177 @@ +import * as Harness from './support.js'; +const post = Harness.definePostTable(); + +Harness.test({ + query: post.select(post.star()).where(post.id.in([])), + pg: { + text: 'SELECT "post".* FROM "post" WHERE (1=0)', + string: 'SELECT "post".* FROM "post" WHERE (1=0)' + }, + sqlite: { + text: 'SELECT "post".* FROM "post" WHERE (1=0)', + string: 'SELECT "post".* FROM "post" WHERE (1=0)' + }, + mysql: { + text: 'SELECT `post`.* FROM `post` WHERE (1=0)', + string: 'SELECT `post`.* FROM `post` WHERE (1=0)' + }, + mssql: { + text: 'SELECT [post].* FROM [post] WHERE (1=0)', + string: 'SELECT [post].* FROM [post] WHERE (1=0)' + }, + oracle: { + text: 'SELECT "post".* FROM "post" WHERE (1=0)', + string: 'SELECT "post".* FROM "post" WHERE (1=0)' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.in([1])), + pg: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN ($1))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1))' + }, + sqlite: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN ($1))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1))' + }, + mysql: { + text: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (?))', + string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (1))' + }, + mssql: { + text: 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (@1))', + string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (1))' + }, + oracle: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (:1))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1))' + }, + params: [1] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.in([null])), + pg: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)' + }, + sqlite: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)' + }, + mysql: { + text: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NULL)', + string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NULL)' + }, + mssql: { + text: 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NULL)', + string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NULL)' + }, + oracle: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.in([1, 2])), + pg: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN ($1, $2))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2))' + }, + sqlite: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN ($1, $2))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2))' + }, + mysql: { + text: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (?, ?))', + string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (1, 2))' + }, + mssql: { + text: 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (@1, @2))', + string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (1, 2))' + }, + oracle: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (:1, :2))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2))' + }, + params: [1, 2] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.in([null, null])), + pg: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)' + }, + sqlite: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)' + }, + mysql: { + text: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NULL)', + string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NULL)' + }, + mssql: { + text: 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NULL)', + string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NULL)' + }, + oracle: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.in([1, null, 2])), + pg: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN ($1, $2) OR "post"."id" IS NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2) OR "post"."id" IS NULL)' + }, + sqlite: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN ($1, $2) OR "post"."id" IS NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2) OR "post"."id" IS NULL)' + }, + mysql: { + text: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (?, ?) OR `post`.`id` IS NULL)', + string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (1, 2) OR `post`.`id` IS NULL)' + }, + mssql: { + text: 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (@1, @2) OR [post].[id] IS NULL)', + string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (1, 2) OR [post].[id] IS NULL)' + }, + oracle: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (:1, :2) OR "post"."id" IS NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2) OR "post"."id" IS NULL)' + }, + params: [1, 2] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.in([1, null, 2, null])), + pg: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN ($1, $2) OR "post"."id" IS NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2) OR "post"."id" IS NULL)' + }, + sqlite: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN ($1, $2) OR "post"."id" IS NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2) OR "post"."id" IS NULL)' + }, + mysql: { + text: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (?, ?) OR `post`.`id` IS NULL)', + string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (1, 2) OR `post`.`id` IS NULL)' + }, + mssql: { + text: 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (@1, @2) OR [post].[id] IS NULL)', + string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (1, 2) OR [post].[id] IS NULL)' + }, + oracle: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (:1, :2) OR "post"."id" IS NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2) OR "post"."id" IS NULL)' + }, + params: [1, 2] +}); diff --git a/test/dialects/index.js b/test/dialects/index.js deleted file mode 100644 index ad9a93a7..00000000 --- a/test/dialects/index.js +++ /dev/null @@ -1 +0,0 @@ -'use strict'; diff --git a/test/dialects/indexes-tests.js b/test/dialects/indexes-tests.js deleted file mode 100644 index 86b50449..00000000 --- a/test/dialects/indexes-tests.js +++ /dev/null @@ -1,235 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var post = Harness.definePostTable(); - -Harness.test({ - query: post.indexes(), - pg: { - text : 'SELECT relname FROM pg_class WHERE oid IN ( SELECT indexrelid FROM pg_index, pg_class WHERE pg_class.relname=\'post\' AND pg_class.relnamespace IN (SELECT pg_namespace.oid FROM pg_namespace WHERE nspname = \'public\') AND pg_class.oid=pg_index.indrelid)', - string: 'SELECT relname FROM pg_class WHERE oid IN ( SELECT indexrelid FROM pg_index, pg_class WHERE pg_class.relname=\'post\' AND pg_class.relnamespace IN (SELECT pg_namespace.oid FROM pg_namespace WHERE nspname = \'public\') AND pg_class.oid=pg_index.indrelid)' - }, - mysql: { - text : 'SHOW INDEX FROM `post`', - string: 'SHOW INDEX FROM `post`' - }, - sqlite: { - text : 'PRAGMA INDEX_LIST("post")', - string: 'PRAGMA INDEX_LIST("post")' - }, - oracle: { - text : 'SELECT * FROM USER_INDEXES WHERE TABLE_NAME = \'post\'', - string: 'SELECT * FROM USER_INDEXES WHERE TABLE_NAME = \'post\'' - }, - params: [] -}); - -Harness.test({ - query: post.indexes().create('index_name').unique().using('btree').on(post.id, post.userId).withParser('foo'), - pg: { - text : 'CREATE UNIQUE INDEX "index_name" USING BTREE ON "post" ("id","userId") WITH PARSER foo', - string: 'CREATE UNIQUE INDEX "index_name" USING BTREE ON "post" ("id","userId") WITH PARSER foo' - }, - mysql: { - text : 'CREATE UNIQUE INDEX `index_name` USING BTREE ON `post` (`id`,`userId`) WITH PARSER foo', - string: 'CREATE UNIQUE INDEX `index_name` USING BTREE ON `post` (`id`,`userId`) WITH PARSER foo' - }, - sqlite: { - text : 'CREATE UNIQUE INDEX "index_name" USING BTREE ON "post" ("id","userId") WITH PARSER foo', - string: 'CREATE UNIQUE INDEX "index_name" USING BTREE ON "post" ("id","userId") WITH PARSER foo' - }, - oracle: { - text : 'CREATE UNIQUE INDEX "index_name" USING BTREE ON "post" ("id","userId") WITH PARSER foo', - string: 'CREATE UNIQUE INDEX "index_name" USING BTREE ON "post" ("id","userId") WITH PARSER foo' - }, - params: [] -}); - -Harness.test({ - query: post.indexes().create().fulltext().on(post.id), - pg: { - text : 'CREATE FULLTEXT INDEX "post_id" ON "post" ("id")', - string: 'CREATE FULLTEXT INDEX "post_id" ON "post" ("id")' - }, - mysql: { - text : 'CREATE FULLTEXT INDEX `post_id` ON `post` (`id`)', - string: 'CREATE FULLTEXT INDEX `post_id` ON `post` (`id`)' - }, - sqlite: { - text : 'CREATE FULLTEXT INDEX "post_id" ON "post" ("id")', - string: 'CREATE FULLTEXT INDEX "post_id" ON "post" ("id")' - }, - params: [] -}); - -Harness.test({ - query: post.indexes().create().spatial().on(post.id), - pg: { - text : 'CREATE SPATIAL INDEX "post_id" ON "post" ("id")', - string: 'CREATE SPATIAL INDEX "post_id" ON "post" ("id")' - }, - mysql: { - text : 'CREATE SPATIAL INDEX `post_id` ON `post` (`id`)', - string: 'CREATE SPATIAL INDEX `post_id` ON `post` (`id`)' - }, - sqlite: { - text : 'CREATE SPATIAL INDEX "post_id" ON "post" ("id")', - string: 'CREATE SPATIAL INDEX "post_id" ON "post" ("id")' - }, - params: [] -}); - -Harness.test({ - query: post.indexes().create().on(post.userId, post.id), - pg: { - text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', - string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' - }, - mysql: { - text : 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id`)', - string: 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id`)' - }, - sqlite: { - text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', - string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' - }, - oracle: { - text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', - string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' - }, - params: [] -}); - -Harness.test({ - query: post.indexes().create().on(post.userId).on(post.id), - pg: { - text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', - string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' - }, - mysql: { - text : 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id`)', - string: 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id`)' - }, - sqlite: { - text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', - string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' - }, - oracle: { - text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', - string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' - }, - params: [] -}); - -Harness.test({ - query: post.indexes().create().on(post.userId, post.id.desc), - pg: { - text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)', - string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)' - }, - mysql: { - text : 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id` DESC)', - string: 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id` DESC)' - }, - sqlite: { - text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)', - string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)' - }, - mssql: { - text : 'CREATE INDEX [post_id_userId] ON [post] ([userId],[id] DESC)', - string: 'CREATE INDEX [post_id_userId] ON [post] ([userId],[id] DESC)' - }, - oracle: { - text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)', - string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)' - }, - params: [] -}); - -Harness.test({ - query: post.indexes().create().on(post.userId).on(post.id.descending), - pg: { - text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)', - string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)' - }, - mysql: { - text : 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id` DESC)', - string: 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id` DESC)' - }, - sqlite: { - text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)', - string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)' - }, - mssql: { - text : 'CREATE INDEX [post_id_userId] ON [post] ([userId],[id] DESC)', - string: 'CREATE INDEX [post_id_userId] ON [post] ([userId],[id] DESC)' - }, - oracle: { - text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)', - string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)' - }, - params: [] -}); - - -Harness.test({ - query: post.indexes().create(), - pg: { - text : 'No columns defined!', - throws: true - }, - mysql: { - text : 'No columns defined!', - throws: true - }, - sqlite: { - text : 'No columns defined!', - throws: true - }, - oracle: { - text : 'No columns defined!', - throws: true - } -}); - -Harness.test({ - query: post.indexes().drop('index_name'), - pg: { - text : 'DROP INDEX "public"."index_name"', - string: 'DROP INDEX "public"."index_name"' - }, - mysql: { - text : 'DROP INDEX `public`.`index_name`', - string: 'DROP INDEX `public`.`index_name`' - }, - sqlite: { - text : 'DROP INDEX "public"."index_name"', - string: 'DROP INDEX "public"."index_name"' - }, - oracle: { - text : 'DROP INDEX "index_name"', - string: 'DROP INDEX "index_name"' - }, - params: [] -}); - -Harness.test({ - query: post.indexes().drop(post.userId, post.id), - pg: { - text : 'DROP INDEX "public"."post_id_userId"', - string: 'DROP INDEX "public"."post_id_userId"' - }, - mysql: { - text : 'DROP INDEX `public`.`post_id_userId`', - string: 'DROP INDEX `public`.`post_id_userId`' - }, - sqlite: { - text : 'DROP INDEX "public"."post_id_userId"', - string: 'DROP INDEX "public"."post_id_userId"' - }, - oracle: { - text : 'DROP INDEX "post_id_userId"', - string: 'DROP INDEX "post_id_userId"' - }, - params: [] -}); diff --git a/test/dialects/indexes-tests.ts b/test/dialects/indexes-tests.ts new file mode 100644 index 00000000..c78deeac --- /dev/null +++ b/test/dialects/indexes-tests.ts @@ -0,0 +1,283 @@ +import * as Harness from './support.js'; +const post = Harness.definePostTable(); + +Harness.test({ + query: post.indexes(), + pg: { + text: + "SELECT relname FROM pg_class WHERE oid IN ( SELECT indexrelid FROM pg_index, pg_class WHERE pg_class.relname='post' AND pg_class.relnamespace IN (SELECT pg_namespace.oid FROM pg_namespace WHERE nspname = 'public') AND pg_class.oid=pg_index.indrelid)", + string: + "SELECT relname FROM pg_class WHERE oid IN ( SELECT indexrelid FROM pg_index, pg_class WHERE pg_class.relname='post' AND pg_class.relnamespace IN (SELECT pg_namespace.oid FROM pg_namespace WHERE nspname = 'public') AND pg_class.oid=pg_index.indrelid)" + }, + mysql: { + text: 'SHOW INDEX FROM `post`', + string: 'SHOW INDEX FROM `post`' + }, + sqlite: { + text: 'PRAGMA INDEX_LIST("post")', + string: 'PRAGMA INDEX_LIST("post")' + }, + oracle: { + text: "SELECT * FROM USER_INDEXES WHERE TABLE_NAME = 'post'", + string: "SELECT * FROM USER_INDEXES WHERE TABLE_NAME = 'post'" + }, + params: [] +}); + +Harness.test({ + query: post + .indexes() + .create('index_name') + .unique() + .using('btree') + .on(post.id, post.userId) + .withParser('foo'), + pg: { + text: 'CREATE UNIQUE INDEX "index_name" ON "post" USING BTREE ("id","userId") WITH PARSER foo', + string: 'CREATE UNIQUE INDEX "index_name" ON "post" USING BTREE ("id","userId") WITH PARSER foo' + }, + mysql: { + text: 'CREATE UNIQUE INDEX `index_name` USING BTREE ON `post` (`id`,`userId`) WITH PARSER foo', + string: 'CREATE UNIQUE INDEX `index_name` USING BTREE ON `post` (`id`,`userId`) WITH PARSER foo' + }, + sqlite: { + text: 'CREATE UNIQUE INDEX "index_name" USING BTREE ON "post" ("id","userId") WITH PARSER foo', + string: 'CREATE UNIQUE INDEX "index_name" USING BTREE ON "post" ("id","userId") WITH PARSER foo' + }, + oracle: { + text: 'CREATE UNIQUE INDEX "index_name" USING BTREE ON "post" ("id","userId") WITH PARSER foo', + string: 'CREATE UNIQUE INDEX "index_name" USING BTREE ON "post" ("id","userId") WITH PARSER foo' + }, + params: [] +}); + +Harness.test({ + query: post + .indexes() + .create() + .fulltext() + .on(post.id), + pg: { + text: 'CREATE FULLTEXT INDEX "post_id" ON "post" ("id")', + string: 'CREATE FULLTEXT INDEX "post_id" ON "post" ("id")' + }, + mysql: { + text: 'CREATE FULLTEXT INDEX `post_id` ON `post` (`id`)', + string: 'CREATE FULLTEXT INDEX `post_id` ON `post` (`id`)' + }, + sqlite: { + text: 'CREATE FULLTEXT INDEX "post_id" ON "post" ("id")', + string: 'CREATE FULLTEXT INDEX "post_id" ON "post" ("id")' + }, + params: [] +}); + +Harness.test({ + query: post + .indexes() + .create() + .spatial() + .on(post.id), + pg: { + text: 'CREATE SPATIAL INDEX "post_id" ON "post" ("id")', + string: 'CREATE SPATIAL INDEX "post_id" ON "post" ("id")' + }, + mysql: { + text: 'CREATE SPATIAL INDEX `post_id` ON `post` (`id`)', + string: 'CREATE SPATIAL INDEX `post_id` ON `post` (`id`)' + }, + sqlite: { + text: 'CREATE SPATIAL INDEX "post_id" ON "post" ("id")', + string: 'CREATE SPATIAL INDEX "post_id" ON "post" ("id")' + }, + params: [] +}); + +Harness.test({ + query: post + .indexes() + .create() + .on(post.userId, post.id), + pg: { + text: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', + string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' + }, + mysql: { + text: 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id`)', + string: 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id`)' + }, + sqlite: { + text: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', + string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' + }, + oracle: { + text: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', + string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' + }, + params: [] +}); + +Harness.test({ + query: post + .indexes() + .create() + .on(post.userId) + .on(post.id), + pg: { + text: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', + string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' + }, + mysql: { + text: 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id`)', + string: 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id`)' + }, + sqlite: { + text: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', + string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' + }, + oracle: { + text: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', + string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' + }, + params: [] +}); + +Harness.test({ + query: post + .indexes() + .create() + .on(post.userId, post.id.desc()), + pg: { + text: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)', + string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)' + }, + mysql: { + text: 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id` DESC)', + string: 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id` DESC)' + }, + sqlite: { + text: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)', + string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)' + }, + mssql: { + text: 'CREATE INDEX [post_id_userId] ON [post] ([userId],[id] DESC)', + string: 'CREATE INDEX [post_id_userId] ON [post] ([userId],[id] DESC)' + }, + oracle: { + text: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)', + string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)' + }, + params: [] +}); + +Harness.test({ + query: post + .indexes() + .create('mandatory_name') + .ifNotExists() + .on(post.userId, post.id.desc()), + pg: { + text: 'CREATE INDEX IF NOT EXISTS "mandatory_name" ON "post" ("userId","id" DESC)', + string: 'CREATE INDEX IF NOT EXISTS "mandatory_name" ON "post" ("userId","id" DESC)' + }, + mysql: { + text: 'Feature does not exist in MySQL', + throws: true + }, + sqlite: { + text: 'CREATE INDEX IF NOT EXISTS "mandatory_name" ON "post" ("userId","id" DESC)', + string: 'CREATE INDEX IF NOT EXISTS "mandatory_name" ON "post" ("userId","id" DESC)' + }, + mssql: { + text: 'Feature does not exist in MSSQL', + throws: true + }, + oracle: { + text: 'Feature does not exist in Oracle', + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.indexes().create(), + pg: { + text: 'No columns defined!', + throws: true + }, + mysql: { + text: 'No columns defined!', + throws: true + }, + sqlite: { + text: 'No columns defined!', + throws: true + }, + oracle: { + text: 'No columns defined!', + throws: true + } +}); + +Harness.test({ + query: post.indexes().drop('index_name'), + pg: { + text: 'DROP INDEX "public"."index_name"', + string: 'DROP INDEX "public"."index_name"' + }, + mysql: { + text: 'DROP INDEX `public`.`index_name`', + string: 'DROP INDEX `public`.`index_name`' + }, + sqlite: { + text: 'DROP INDEX "public"."index_name"', + string: 'DROP INDEX "public"."index_name"' + }, + oracle: { + text: 'DROP INDEX "index_name"', + string: 'DROP INDEX "index_name"' + }, + params: [] +}); + +Harness.test({ + query: post.indexes().drop(post.userId, post.id), + pg: { + text: 'DROP INDEX "public"."post_id_userId"', + string: 'DROP INDEX "public"."post_id_userId"' + }, + mysql: { + text: 'DROP INDEX `public`.`post_id_userId`', + string: 'DROP INDEX `public`.`post_id_userId`' + }, + sqlite: { + text: 'DROP INDEX "public"."post_id_userId"', + string: 'DROP INDEX "public"."post_id_userId"' + }, + oracle: { + text: 'DROP INDEX "post_id_userId"', + string: 'DROP INDEX "post_id_userId"' + }, + params: [] +}); + +Harness.test({ + query: post.indexes().drop(post.userId, post.id).ifExists(), + pg: { + text: 'DROP INDEX IF EXISTS "public"."post_id_userId"', + string: 'DROP INDEX IF EXISTS "public"."post_id_userId"' + }, + mysql: { + text: 'Feature does not exist in MySQL', + throws: true + }, + sqlite: { + text: 'DROP INDEX IF EXISTS "public"."post_id_userId"', + string: 'DROP INDEX IF EXISTS "public"."post_id_userId"' + }, + oracle: { + text: 'Feature does not exist in Oracle', + throws: true + }, + params: [] +}); diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js deleted file mode 100644 index 60ba6a62..00000000 --- a/test/dialects/insert-tests.js +++ /dev/null @@ -1,1094 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var post = Harness.definePostTable(); -var user = Harness.defineUserTable(); -var contentTable = Harness.defineContentTable(); -var customerAliasTable = Harness.defineCustomerAliasTable(); - -var arrayTable = require('../../lib/table').define({ - name: 'arraytest', - columns: ['id', 'numbers'] -}); - -Harness.test({ - query: post.insert(post.content.value('test'), post.userId.value(1)), - pg: { - text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 1)' - }, - sqlite: { - text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 1)' - }, - mysql: { - text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', - string: 'INSERT INTO `post` (`content`, `userId`) VALUES (\'test\', 1)' - }, - oracle: { - text : 'INSERT INTO "post" ("content", "userId") VALUES (:1, :2)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 1)' - }, - params: ['test', 1] -}); - -Harness.test({ - query: post.insert(post.content.value('whoah')), - pg: { - text : 'INSERT INTO "post" ("content") VALUES ($1)', - string: 'INSERT INTO "post" ("content") VALUES (\'whoah\')' - }, - sqlite: { - text : 'INSERT INTO "post" ("content") VALUES ($1)', - string: 'INSERT INTO "post" ("content") VALUES (\'whoah\')' - }, - mysql: { - text : 'INSERT INTO `post` (`content`) VALUES (?)', - string: 'INSERT INTO `post` (`content`) VALUES (\'whoah\')' - }, - mssql: { - text : 'INSERT INTO [post] ([content]) VALUES (@1)', - string: 'INSERT INTO [post] ([content]) VALUES (\'whoah\')' - }, - oracle: { - text : 'INSERT INTO "post" ("content") VALUES (:1)', - string: 'INSERT INTO "post" ("content") VALUES (\'whoah\')' - }, - params: ['whoah'] -}); - -Harness.test({ - query: post.insert({length: 0}), - pg: { - text : 'INSERT INTO "post" ("length") VALUES ($1)', - string: 'INSERT INTO "post" ("length") VALUES (0)' - }, - sqlite: { - text : 'INSERT INTO "post" ("length") VALUES ($1)', - string: 'INSERT INTO "post" ("length") VALUES (0)' - }, - mysql: { - text : 'INSERT INTO `post` (`length`) VALUES (?)', - string: 'INSERT INTO `post` (`length`) VALUES (0)' - }, - mssql: { - text : 'INSERT INTO [post] ([length]) VALUES (@1)', - string: 'INSERT INTO [post] ([length]) VALUES (0)' - }, - oracle: { - text : 'INSERT INTO "post" ("length") VALUES (:1)', - string: 'INSERT INTO "post" ("length") VALUES (0)' - }, - params: [0] -}); - -Harness.test({ - query: post.insert({ - content: 'test', - userId: 2 - }), - pg: { - text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2)' - }, - sqlite: { - text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2)' - }, - mysql: { - text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', - string: 'INSERT INTO `post` (`content`, `userId`) VALUES (\'test\', 2)' - }, - oracle: { - text : 'INSERT INTO "post" ("content", "userId") VALUES (:1, :2)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2)' - }, - params: ['test', 2] -}); - -Harness.test({ - query: post.insert({ - content: post.sql.functions.LOWER('TEST'), - userId: 2 - }), - pg: { - text : 'INSERT INTO "post" ("content", "userId") VALUES (LOWER($1), $2)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (LOWER(\'TEST\'), 2)' - }, - sqlite: { - text : 'INSERT INTO "post" ("content", "userId") VALUES (LOWER($1), $2)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (LOWER(\'TEST\'), 2)' - }, - mysql: { - text : 'INSERT INTO `post` (`content`, `userId`) VALUES (LOWER(?), ?)', - string: 'INSERT INTO `post` (`content`, `userId`) VALUES (LOWER(\'TEST\'), 2)' - }, - oracle: { - text : 'INSERT INTO "post" ("content", "userId") VALUES (LOWER(:1), :2)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (LOWER(\'TEST\'), 2)' - }, - params: ['TEST', 2] -}); - -// allow bulk insert -Harness.test({ - query: post.insert([{ - content: 'whoah' - }, { - content: 'hey' - } - ]), - pg: { - text : 'INSERT INTO "post" ("content") VALUES ($1), ($2)', - string: 'INSERT INTO "post" ("content") VALUES (\'whoah\'), (\'hey\')' - }, - sqlite: { - text : 'INSERT INTO "post" ("content") VALUES ($1), ($2)', - string: 'INSERT INTO "post" ("content") VALUES (\'whoah\'), (\'hey\')' - }, - mysql: { - text : 'INSERT INTO `post` (`content`) VALUES (?), (?)', - string: 'INSERT INTO `post` (`content`) VALUES (\'whoah\'), (\'hey\')' - }, - oracle: { - text : 'INSERT INTO "post" ("content") VALUES (:1), (:2)', - string: 'INSERT INTO "post" ("content") VALUES (\'whoah\'), (\'hey\')' - }, - params: ['whoah', 'hey'] -}); - -Harness.test({ - query: post.insert([{ - content: 'whoah', - userId: 1 - }, { - content: 'hey', - userId: 2 - } - ]), - pg: { - text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' - }, - sqlite: { - text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' - }, - mysql: { - text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, ?)', - string: 'INSERT INTO `post` (`content`, `userId`) VALUES (\'whoah\', 1), (\'hey\', 2)' - }, - oracle: { - text : 'INSERT INTO "post" ("content", "userId") VALUES (:1, :2), (:3, :4)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' - }, - params: ['whoah', 1, 'hey', 2] -}); - -// consistent order -Harness.test({ - query: post.insert([{ - content: 'whoah', - userId: 1 - }, { - userId: 2, - content: 'hey' - } - ]), - pg: { - text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' - }, - sqlite: { - text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' - }, - mysql: { - text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, ?)', - string: 'INSERT INTO `post` (`content`, `userId`) VALUES (\'whoah\', 1), (\'hey\', 2)' - }, - mssql: { - text : 'INSERT INTO [post] ([content], [userId]) VALUES (@1, @2), (@3, @4)', - string: 'INSERT INTO [post] ([content], [userId]) VALUES (\'whoah\', 1), (\'hey\', 2)' - }, - oracle: { - text : 'INSERT INTO "post" ("content", "userId") VALUES (:1, :2), (:3, :4)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' - }, - params: ['whoah', 1, 'hey', 2] -}); - -Harness.test({ - query: post.insert({}), - pg: { - text : 'INSERT INTO "post" DEFAULT VALUES', - string: 'INSERT INTO "post" DEFAULT VALUES' - }, - sqlite: { - text : 'INSERT INTO "post" DEFAULT VALUES', - string: 'INSERT INTO "post" DEFAULT VALUES' - }, - mysql: { - text : 'INSERT INTO `post` () VALUES ()', - string: 'INSERT INTO `post` () VALUES ()' - }, - mssql: { - text : 'INSERT INTO [post] DEFAULT VALUES', - string: 'INSERT INTO [post] DEFAULT VALUES' - }, - oracle: { - text : 'INSERT INTO "post" DEFAULT VALUES', - string: 'INSERT INTO "post" DEFAULT VALUES' - }, - params: [] -}); - -Harness.test({ - query: post.insert({}).returning('*'), - pg: { - text : 'INSERT INTO "post" DEFAULT VALUES RETURNING *', - string: 'INSERT INTO "post" DEFAULT VALUES RETURNING *' - }, - sqlite: { - throws: true - }, - mysql: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [] -}); - -Harness.test({ - query: post.insert({}).returning(post.star()), - pg: { - text : 'INSERT INTO "post" DEFAULT VALUES RETURNING *', - string: 'INSERT INTO "post" DEFAULT VALUES RETURNING *' - }, - sqlite: { - throws: true - }, - mysql: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [] -}); - -Harness.test({ - query: post.insert({}).returning(post.id), - pg: { - text : 'INSERT INTO "post" DEFAULT VALUES RETURNING "id"', - string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id"' - }, - sqlite: { - throws: true - }, - mysql: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [] -}); - -Harness.test({ - query: post.insert({}).returning(post.id, post.content), - pg: { - text : 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', - string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"' - }, - sqlite: { - throws: true - }, - mysql: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [] -}); - -Harness.test({ - query: post.insert({}).returning([post.id, post.content]), - pg: { - text : 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', - string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"' - }, - sqlite: { - throws: true - }, - mysql: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [] -}); - -// handle missing columns -Harness.test({ - query: post.insert([{ - content: 'whoah', - userId: 1 - }, { - content: 'hey' - } - ]), - pg: { - text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, DEFAULT)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', DEFAULT)', - params: ['whoah', 1, 'hey'] - }, - sqlite: { - text : 'Sqlite requires the same number of columns in each insert row', - throws: true - }, - mysql: { - text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, DEFAULT)', - string: 'INSERT INTO `post` (`content`, `userId`) VALUES (\'whoah\', 1), (\'hey\', DEFAULT)', - params: ['whoah', 1, 'hey'] - }, - mssql: { - text : 'INSERT INTO [post] ([content], [userId]) VALUES (@1, @2), (@3, DEFAULT)', - string: 'INSERT INTO [post] ([content], [userId]) VALUES (\'whoah\', 1), (\'hey\', DEFAULT)', - params: ['whoah', 1, 'hey'] - }, - oracle: { - text : 'INSERT INTO "post" ("content", "userId") VALUES (:1, :2), (:3, DEFAULT)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', DEFAULT)', - params: ['whoah', 1, 'hey'] - }, -}); - -Harness.test({ - query: post.insert([{ - userId: 1 - }, { - content: 'hey', - userId: 2 - } - ]), - pg: { - text : 'INSERT INTO "post" ("userId", "content") VALUES ($1, DEFAULT), ($2, $3)', - string: 'INSERT INTO "post" ("userId", "content") VALUES (1, DEFAULT), (2, \'hey\')', - params: [1, 2, 'hey'] - }, - sqlite: { - text : 'Sqlite requires the same number of columns in each insert row', - throws: true - }, - mysql: { - text : 'INSERT INTO `post` (`userId`, `content`) VALUES (?, DEFAULT), (?, ?)', - string: 'INSERT INTO `post` (`userId`, `content`) VALUES (1, DEFAULT), (2, \'hey\')', - params: [1, 2, 'hey'] - }, - mssql: { - text : 'INSERT INTO [post] ([userId], [content]) VALUES (@1, DEFAULT), (@2, @3)', - string: 'INSERT INTO [post] ([userId], [content]) VALUES (1, DEFAULT), (2, \'hey\')', - params: [1, 2, 'hey'] - }, - oracle: { - text : 'INSERT INTO "post" ("userId", "content") VALUES (:1, DEFAULT), (:2, :3)', - string: 'INSERT INTO "post" ("userId", "content") VALUES (1, DEFAULT), (2, \'hey\')', - params: [1, 2, 'hey'] - } -}); - -Harness.test({ - query: post.insert(post.content, post.userId) - .select('\'test\'', user.id).from(user).where(user.name.like('A%')), - pg: { - text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', - string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' - }, - sqlite: { - text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', - string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' - }, - mysql: { - text : 'INSERT INTO `post` (`content`, `userId`) SELECT \'test\', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE ?)', - string: 'INSERT INTO `post` (`content`, `userId`) SELECT \'test\', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE \'A%\')' - }, - mssql: { - text : 'INSERT INTO [post] ([content], [userId]) SELECT \'test\', [user].[id] FROM [user] WHERE ([user].[name] LIKE @1)', - string: 'INSERT INTO [post] ([content], [userId]) SELECT \'test\', [user].[id] FROM [user] WHERE ([user].[name] LIKE \'A%\')' - }, - oracle: { - text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE :1)', - string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' - }, - params: ['A%'] -}); - -Harness.test({ - query: post.insert([post.content, post.userId]) - .select('\'test\'', user.id).from(user).where(user.name.like('A%')), - pg: { - text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', - string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' - }, - sqlite: { - text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', - string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' - }, - mysql: { - text : 'INSERT INTO `post` (`content`, `userId`) SELECT \'test\', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE ?)', - string: 'INSERT INTO `post` (`content`, `userId`) SELECT \'test\', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE \'A%\')' - }, - mssql: { - text : 'INSERT INTO [post] ([content], [userId]) SELECT \'test\', [user].[id] FROM [user] WHERE ([user].[name] LIKE @1)', - string: 'INSERT INTO [post] ([content], [userId]) SELECT \'test\', [user].[id] FROM [user] WHERE ([user].[name] LIKE \'A%\')' - }, - oracle: { - text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE :1)', - string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' - }, - params: ['A%'] -}); - -Harness.test({ - query: post.insert(post.userId) - .select(user.id).from(user).where(user.name.like('A%')), - pg: { - text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', - string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' - }, - sqlite: { - text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', - string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' - }, - mysql: { - text : 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user` WHERE (`user`.`name` LIKE ?)', - string: 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user` WHERE (`user`.`name` LIKE \'A%\')' - }, - oracle: { - text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE :1)', - string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' - }, - params: ['A%'] -}); - -Harness.test({ - query: post.insert(post.userId) - .select(post.userId).from(user.join(post).on(user.id.equals(post.userId))).where(post.tags.like('A%')), - pg: { - text : 'INSERT INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE $1)', - string: 'INSERT INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE \'A%\')' - }, - sqlite: { - text : 'INSERT INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE $1)', - string: 'INSERT INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE \'A%\')' - }, - mysql: { - text : 'INSERT INTO `post` (`userId`) SELECT `post`.`userId` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`post`.`tags` LIKE ?)', - string: 'INSERT INTO `post` (`userId`) SELECT `post`.`userId` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`post`.`tags` LIKE \'A%\')' - }, - mssql: { - text : 'INSERT INTO [post] ([userId]) SELECT [post].[userId] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) WHERE ([post].[tags] LIKE @1)', - string: 'INSERT INTO [post] ([userId]) SELECT [post].[userId] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) WHERE ([post].[tags] LIKE \'A%\')' - }, - oracle: { - text : 'INSERT INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE :1)', - string: 'INSERT INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE \'A%\')' - }, - params: ['A%'] -}); - -Harness.test({ - query: post.insert(post.userId).select(user.id).distinct().from(user), - pg: { - text : 'INSERT INTO "post" ("userId") SELECT DISTINCT "user"."id" FROM "user"', - string: 'INSERT INTO "post" ("userId") SELECT DISTINCT "user"."id" FROM "user"' - }, - sqlite: { - text : 'INSERT INTO "post" ("userId") SELECT DISTINCT "user"."id" FROM "user"', - string: 'INSERT INTO "post" ("userId") SELECT DISTINCT "user"."id" FROM "user"' - }, - mysql: { - text : 'INSERT INTO `post` (`userId`) SELECT DISTINCT `user`.`id` FROM `user`', - string: 'INSERT INTO `post` (`userId`) SELECT DISTINCT `user`.`id` FROM `user`' - }, - mssql: { - text : 'INSERT INTO [post] ([userId]) SELECT DISTINCT [user].[id] FROM [user]', - string: 'INSERT INTO [post] ([userId]) SELECT DISTINCT [user].[id] FROM [user]' - }, - oracle: { - text : 'INSERT INTO "post" ("userId") SELECT DISTINCT "user"."id" FROM "user"', - string: 'INSERT INTO "post" ("userId") SELECT DISTINCT "user"."id" FROM "user"' - }, - params: [] -}); - -// Binary inserts -Harness.test({ - query: post.insert(post.content.value(new Buffer('test')), post.userId.value(2)), - pg: { - text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (\'\\x74657374\', 2)' - }, - sqlite: { - text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (x\'74657374\', 2)' - }, - mysql: { - text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', - string: 'INSERT INTO `post` (`content`, `userId`) VALUES (x\'74657374\', 2)' - }, - mssql: { - text : 'INSERT INTO [post] ([content], [userId]) VALUES (@1, @2)', - string: 'INSERT INTO [post] ([content], [userId]) VALUES (\'\\x74657374\', 2)' - }, - oracle: { - text : 'INSERT INTO "post" ("content", "userId") VALUES (:1, :2)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (utl_raw.cast_to_varchar2(hextoraw(\'74657374\')), 2)' - }, - params: [new Buffer('test'), 2] -}); - -Harness.test({ - query: post.insert({ - content: new Buffer('test'), - userId: 2 - }), - pg: { - text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (\'\\x74657374\', 2)' - }, - sqlite: { - text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (x\'74657374\', 2)' - }, - mysql: { - text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', - string: 'INSERT INTO `post` (`content`, `userId`) VALUES (x\'74657374\', 2)' - }, - mssql: { - text : 'INSERT INTO [post] ([content], [userId]) VALUES (@1, @2)', - string: 'INSERT INTO [post] ([content], [userId]) VALUES (\'\\x74657374\', 2)' - }, - oracle: { - text : 'INSERT INTO "post" ("content", "userId") VALUES (:1, :2)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (utl_raw.cast_to_varchar2(hextoraw(\'74657374\')), 2)' - }, - params: [new Buffer('test'), 2] -}); - -Harness.test({ - query: post.insert([{ - content: new Buffer('whoah') - }, { - content: new Buffer('hey') - } - ]), - pg: { - text : 'INSERT INTO "post" ("content") VALUES ($1), ($2)', - string: 'INSERT INTO "post" ("content") ' + - 'VALUES (\'\\x77686f6168\'), (\'\\x686579\')' - }, - sqlite: { - text : 'INSERT INTO "post" ("content") VALUES ($1), ($2)', - string: 'INSERT INTO "post" ("content") VALUES (x\'77686f6168\'), (x\'686579\')' - }, - mysql: { - text : 'INSERT INTO `post` (`content`) VALUES (?), (?)', - string: 'INSERT INTO `post` (`content`) VALUES (x\'77686f6168\'), (x\'686579\')' - }, - mssql: { - text : 'INSERT INTO [post] ([content]) VALUES (@1), (@2)', - string: 'INSERT INTO [post] ([content]) VALUES (\'\\x77686f6168\'), (\'\\x686579\')' - }, - oracle: { - text : 'INSERT INTO "post" ("content") VALUES (:1), (:2)', - string: 'INSERT INTO "post" ("content") VALUES (utl_raw.cast_to_varchar2(hextoraw(\'77686f6168\'))), (utl_raw.cast_to_varchar2(hextoraw(\'686579\')))' - }, - params: [new Buffer('whoah'), new Buffer('hey')] -}); - -Harness.test({ - query: post.insert({ - content: 'test', - userId: 2 - }).onDuplicate({ - content: 'testupdate', - }), - pg: { - throws: true - }, - sqlite: { - throws: true - }, - mysql: { - text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?) ON DUPLICATE KEY UPDATE `post`.`content` = ?', - string: 'INSERT INTO `post` (`content`, `userId`) VALUES (\'test\', 2) ON DUPLICATE KEY UPDATE `post`.`content` = \'testupdate\'' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['test', 2, 'testupdate'] -}); - -Harness.test({ - query: customerAliasTable.insert({ - id : 2, - name : 'test' - }).onConflict({ - columns: ['id'], - update: ['name'] - }), - mysql: { - throws: true - }, - sqlite: { - throws: true - }, - pg: { - text : 'INSERT INTO "customer" ("id", "name") VALUES ($1, $2) ON CONFLICT ("id") DO UPDATE SET "name" = EXCLUDED."name"', - string: 'INSERT INTO "customer" ("id", "name") VALUES (2, \'test\') ON CONFLICT ("id") DO UPDATE SET "name" = EXCLUDED."name"' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [2, 'test'] -}); - -Harness.test({ - query: customerAliasTable.insert({ - id : 2, - name : 'test' - }).orIgnore(), - mysql: { - throws: true - }, - sqlite: { - text : 'INSERT OR IGNORE INTO "customer" ("id", "name") VALUES ($1, $2)', - string: 'INSERT OR IGNORE INTO "customer" ("id", "name") VALUES (2, \'test\')' - }, - pg: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [2, 'test'] -}); - -Harness.test({ - query: post.insert({ - content: 'test', - userId: 2 - }).onConflict({ - columns: ['userId'], - update: ['content'] - }), - mysql: { - throws: true - }, - sqlite: { - throws: true - }, - pg: { - text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2) ON CONFLICT ("userId") DO UPDATE SET "content" = EXCLUDED."content"', - string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2) ON CONFLICT ("userId") DO UPDATE SET "content" = EXCLUDED."content"' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['test', 2] -}); - -Harness.test({ - query: post.insert({ - content: 'test', - userId: 2 - }).onConflict({ - columns: ['userId','content'], - update: ['content','userId'] - }), - mysql: { - throws: true - }, - sqlite: { - throws: true - }, - pg: { - text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2) ON CONFLICT ("userId", "content") DO UPDATE SET "content" = EXCLUDED."content", "userId" = EXCLUDED."userId"', - string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2) ON CONFLICT ("userId", "content") DO UPDATE SET "content" = EXCLUDED."content", "userId" = EXCLUDED."userId"' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['test', 2] -}); - -Harness.test({ - query: post.insert({ - content: 'test', - userId: 2 - }).onConflict({ - columns: ['userId'], - update: ['content'] - }).where(post.userId.equals(2)), - mysql: { - throws: true - }, - sqlite: { - throws: true - }, - pg: { - text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2) ON CONFLICT ("userId") DO UPDATE SET "content" = EXCLUDED."content" WHERE ("post"."userId" = $3)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2) ON CONFLICT ("userId") DO UPDATE SET "content" = EXCLUDED."content" WHERE ("post"."userId" = 2)' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['test', 2, 2] -}); - -Harness.test({ - query: post.insert({ - content: 'test', - userId: 2 - }).onConflict({ - constraint: 'conc_userId', - update: ['content'] - }).where(post.userId.equals(2)), - mysql: { - throws: true - }, - sqlite: { - throws: true - }, - pg: { - text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2) ON CONFLICT ON CONSTRAINT "conc_userId" DO UPDATE SET "content" = EXCLUDED."content" WHERE ("post"."userId" = $3)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2) ON CONFLICT ON CONSTRAINT "conc_userId" DO UPDATE SET "content" = EXCLUDED."content" WHERE ("post"."userId" = 2)' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['test', 2, 2] -}); - -Harness.test({ - query: post.insert({ - content: 'test', - userId: 2 - }).onConflict({ - columns: ['userId'], - }), - mysql: { - throws: true - }, - sqlite: { - throws: true - }, - pg: { - text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2) ON CONFLICT ("userId") DO NOTHING', - string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2) ON CONFLICT ("userId") DO NOTHING' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['test', 2] -}); - -Harness.test({ - query: post.insert({ - content: 'test', - userId: 2 - }).onConflict({ - constraint: 'conc_userId', - }), - mysql: { - throws: true - }, - sqlite: { - throws: true - }, - pg: { - text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2) ON CONFLICT ON CONSTRAINT "conc_userId" DO NOTHING', - string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2) ON CONFLICT ON CONSTRAINT "conc_userId" DO NOTHING' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['test', 2] -}); - -Harness.test({ - query: contentTable.insert({ - contentId: 20, - text : "something" - }).onConflict({ - columns: ['contentId'], - }), - mysql: { - throws: true - }, - sqlite: { - throws: true - }, - pg: { - text : 'INSERT INTO "content" ("content_id", "text") VALUES ($1, $2) ON CONFLICT ("content_id") DO NOTHING', - string: 'INSERT INTO "content" ("content_id", "text") VALUES (20, \'something\') ON CONFLICT ("content_id") DO NOTHING' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [20, "something"] -}); - -Harness.test({ - query: contentTable.insert({ - contentId: 20, - text : "something", - contentPosts : "another thing", - }).onConflict({ - columns: ['contentId'], - update: ['contentPosts'] - }), - mysql: { - throws: true - }, - sqlite: { - throws: true - }, - pg: { - text : 'INSERT INTO "content" ("content_id", "text", "content_posts") VALUES ($1, $2, $3) ON CONFLICT ("content_id") DO UPDATE SET "content_posts" = EXCLUDED."content_posts"', - string: 'INSERT INTO "content" ("content_id", "text", "content_posts") VALUES (20, \'something\', \'another thing\') ON CONFLICT ("content_id") DO UPDATE SET "content_posts" = EXCLUDED."content_posts"' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [20, "something", "another thing"] -}); - -Harness.test({ - query: post.insert([]), - - mysql: { - text : 'SELECT `post`.* FROM `post` WHERE (1=2)', - string: 'SELECT `post`.* FROM `post` WHERE (1=2)' - }, - params: [] -}); - -Harness.test({ - query: arrayTable.insert(arrayTable.id.value(1), arrayTable.numbers.value([2, 3, 4])), - pg: { - text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', - string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, \'{2,3,4}\')' - }, - sqlite: { - text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', - string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, \'[2,3,4]\')' - }, - mysql: { - text : 'INSERT INTO `arraytest` (`id`, `numbers`) VALUES (?, ?)', - string: 'INSERT INTO `arraytest` (`id`, `numbers`) VALUES (1, (2, 3, 4))' - }, - oracle: { - text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES (:1, :2)', - string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, (2, 3, 4))' - } -}); - -Harness.test({ - query: arrayTable.insert(arrayTable.id.value(1), arrayTable.numbers.value(["one", "two", "three"])), - pg: { - text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', - string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, \'{"one","two","three"}\')' - }, - sqlite: { - text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', - string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, \'["one","two","three"]\')' - }, - mysql: { - text : 'INSERT INTO `arraytest` (`id`, `numbers`) VALUES (?, ?)', - string: 'INSERT INTO `arraytest` (`id`, `numbers`) VALUES (1, (\'one\', \'two\', \'three\'))' - }, - oracle: { - text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES (:1, :2)', - string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, (\'one\', \'two\', \'three\'))' - } -}); - -Harness.test({ - query: post.insert(post.userId).select(user.id).from(user), - pg: { - text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', - string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' - }, - sqlite: { - text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', - string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' - }, - mysql: { - text : 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user`', - string: 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user`' - }, - mssql: { - text : 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user]', - string: 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user]' - }, - oracle: { - text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', - string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' - }, - params: [] -}); - -Harness.test({ - query: post.insert(post.userId).select(user.id).from(user).onConflict({ - columns: ['userId'], - update: ['content'] - }), - pg: { - text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" ON CONFLICT ("userId") DO UPDATE SET "content" = EXCLUDED."content"', - string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" ON CONFLICT ("userId") DO UPDATE SET "content" = EXCLUDED."content"' - }, - sqlite: { - throws: true - }, - mysql: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [] -}); - -Harness.test({ - query: post.insert(post.userId).add(user.select(user.id)), - pg: { - text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', - string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' - }, - sqlite: { - text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', - string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' - }, - mysql: { - text : 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user`', - string: 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user`' - }, - mssql: { - text : 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user]', - string: 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user]' - }, - oracle: { - text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', - string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' - }, - params: [] -}); - -Harness.test({ - query: post.insert(post.userId).add(user.select(user.id).from(user)), - pg: { - text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', - string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' - }, - sqlite: { - text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', - string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' - }, - mysql: { - text : 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user`', - string: 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user`' - }, - mssql: { - text : 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user]', - string: 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user]' - }, - oracle: { - text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', - string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' - }, - params: [] -}); - -Harness.test({ - query: post.insert(post.userId).add(user.select(user.id).order(user.id)), - pg: { - text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"', - string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"' - }, - sqlite: { - text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"', - string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"' - }, - mysql: { - text : 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user` ORDER BY `user`.`id`', - string: 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user` ORDER BY `user`.`id`' - }, - mssql: { - text : 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user] ORDER BY [user].[id]', - string: 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user] ORDER BY [user].[id]' - }, - oracle: { - text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"', - string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"' - }, - params: [] -}); - diff --git a/test/dialects/insert-tests.ts b/test/dialects/insert-tests.ts new file mode 100644 index 00000000..e4081ce8 --- /dev/null +++ b/test/dialects/insert-tests.ts @@ -0,0 +1,1231 @@ +import * as Harness from './support.js'; +import { Table } from '../../dist/lib.js'; +const post = Harness.definePostTable(); +const user = Harness.defineUserTable(); +const contentTable = Harness.defineContentTable(); +const customerAliasTable = Harness.defineCustomerAliasTable(); + +const arrayTable = Table.define<{ id: number; numbers: any[] }>({ + name: 'arraytest', + columns: ['id', 'numbers'] +}); + +Harness.test({ + query: post.insert(post.content.value('test'), post.userId.value(1)), + pg: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 1)' + }, + sqlite: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 1)' + }, + mysql: { + text: 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', + string: "INSERT INTO `post` (`content`, `userId`) VALUES ('test', 1)" + }, + oracle: { + text: 'INSERT INTO "post" ("content", "userId") VALUES (:1, :2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 1)' + }, + params: ['test', 1] +}); + +Harness.test({ + query: post.insert(post.content.value('whoah')), + pg: { + text: 'INSERT INTO "post" ("content") VALUES ($1)', + string: 'INSERT INTO "post" ("content") VALUES (\'whoah\')' + }, + sqlite: { + text: 'INSERT INTO "post" ("content") VALUES ($1)', + string: 'INSERT INTO "post" ("content") VALUES (\'whoah\')' + }, + mysql: { + text: 'INSERT INTO `post` (`content`) VALUES (?)', + string: "INSERT INTO `post` (`content`) VALUES ('whoah')" + }, + mssql: { + text: 'INSERT INTO [post] ([content]) VALUES (@1)', + string: "INSERT INTO [post] ([content]) VALUES ('whoah')" + }, + oracle: { + text: 'INSERT INTO "post" ("content") VALUES (:1)', + string: 'INSERT INTO "post" ("content") VALUES (\'whoah\')' + }, + params: ['whoah'] +}); + +Harness.test({ + query: post.insert({ length: 0 }), + pg: { + text: 'INSERT INTO "post" ("length") VALUES ($1)', + string: 'INSERT INTO "post" ("length") VALUES (0)' + }, + sqlite: { + text: 'INSERT INTO "post" ("length") VALUES ($1)', + string: 'INSERT INTO "post" ("length") VALUES (0)' + }, + mysql: { + text: 'INSERT INTO `post` (`length`) VALUES (?)', + string: 'INSERT INTO `post` (`length`) VALUES (0)' + }, + mssql: { + text: 'INSERT INTO [post] ([length]) VALUES (@1)', + string: 'INSERT INTO [post] ([length]) VALUES (0)' + }, + oracle: { + text: 'INSERT INTO "post" ("length") VALUES (:1)', + string: 'INSERT INTO "post" ("length") VALUES (0)' + }, + params: [0] +}); + +Harness.test({ + query: post.insert({ + content: 'test', + userId: 2 + }), + pg: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2)' + }, + sqlite: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2)' + }, + mysql: { + text: 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', + string: "INSERT INTO `post` (`content`, `userId`) VALUES ('test', 2)" + }, + oracle: { + text: 'INSERT INTO "post" ("content", "userId") VALUES (:1, :2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2)' + }, + params: ['test', 2] +}); + +Harness.test({ + query: post.insert({ + content: post.sql.functions.LOWER('TEST'), + userId: 2 + }), + pg: { + text: 'INSERT INTO "post" ("content", "userId") VALUES (LOWER($1), $2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (LOWER(\'TEST\'), 2)' + }, + sqlite: { + text: 'INSERT INTO "post" ("content", "userId") VALUES (LOWER($1), $2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (LOWER(\'TEST\'), 2)' + }, + mysql: { + text: 'INSERT INTO `post` (`content`, `userId`) VALUES (LOWER(?), ?)', + string: "INSERT INTO `post` (`content`, `userId`) VALUES (LOWER('TEST'), 2)" + }, + oracle: { + text: 'INSERT INTO "post" ("content", "userId") VALUES (LOWER(:1), :2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (LOWER(\'TEST\'), 2)' + }, + params: ['TEST', 2] +}); + +// allow bulk insert +Harness.test({ + query: post.insert([ + { + content: 'whoah' + }, + { + content: 'hey' + } + ]), + pg: { + text: 'INSERT INTO "post" ("content") VALUES ($1), ($2)', + string: 'INSERT INTO "post" ("content") VALUES (\'whoah\'), (\'hey\')' + }, + sqlite: { + text: 'INSERT INTO "post" ("content") VALUES ($1), ($2)', + string: 'INSERT INTO "post" ("content") VALUES (\'whoah\'), (\'hey\')' + }, + mysql: { + text: 'INSERT INTO `post` (`content`) VALUES (?), (?)', + string: "INSERT INTO `post` (`content`) VALUES ('whoah'), ('hey')" + }, + oracle: { + text: 'INSERT INTO "post" ("content") VALUES (:1), (:2)', + string: 'INSERT INTO "post" ("content") VALUES (\'whoah\'), (\'hey\')' + }, + params: ['whoah', 'hey'] +}); + +Harness.test({ + query: post.insert([ + { + content: 'whoah', + userId: 1 + }, + { + content: 'hey', + userId: 2 + } + ]), + pg: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' + }, + sqlite: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' + }, + mysql: { + text: 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, ?)', + string: "INSERT INTO `post` (`content`, `userId`) VALUES ('whoah', 1), ('hey', 2)" + }, + oracle: { + text: 'INSERT INTO "post" ("content", "userId") VALUES (:1, :2), (:3, :4)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' + }, + params: ['whoah', 1, 'hey', 2] +}); + +// consistent order +Harness.test({ + query: post.insert([ + { + content: 'whoah', + userId: 1 + }, + { + userId: 2, + content: 'hey' + } + ]), + pg: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' + }, + sqlite: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' + }, + mysql: { + text: 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, ?)', + string: "INSERT INTO `post` (`content`, `userId`) VALUES ('whoah', 1), ('hey', 2)" + }, + mssql: { + text: 'INSERT INTO [post] ([content], [userId]) VALUES (@1, @2), (@3, @4)', + string: "INSERT INTO [post] ([content], [userId]) VALUES ('whoah', 1), ('hey', 2)" + }, + oracle: { + text: 'INSERT INTO "post" ("content", "userId") VALUES (:1, :2), (:3, :4)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' + }, + params: ['whoah', 1, 'hey', 2] +}); + +Harness.test({ + query: post.insert({}), + pg: { + text: 'INSERT INTO "post" DEFAULT VALUES', + string: 'INSERT INTO "post" DEFAULT VALUES' + }, + sqlite: { + text: 'INSERT INTO "post" DEFAULT VALUES', + string: 'INSERT INTO "post" DEFAULT VALUES' + }, + mysql: { + text: 'INSERT INTO `post` () VALUES ()', + string: 'INSERT INTO `post` () VALUES ()' + }, + mssql: { + text: 'INSERT INTO [post] DEFAULT VALUES', + string: 'INSERT INTO [post] DEFAULT VALUES' + }, + oracle: { + text: 'INSERT INTO "post" DEFAULT VALUES', + string: 'INSERT INTO "post" DEFAULT VALUES' + }, + params: [] +}); + +Harness.test({ + query: post.insert({}).returning('*'), + pg: { + text: 'INSERT INTO "post" DEFAULT VALUES RETURNING *', + string: 'INSERT INTO "post" DEFAULT VALUES RETURNING *' + }, + sqlite: { + throws: true + }, + mysql: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.insert({}).returning(post.star()), + pg: { + text: 'INSERT INTO "post" DEFAULT VALUES RETURNING *', + string: 'INSERT INTO "post" DEFAULT VALUES RETURNING *' + }, + sqlite: { + throws: true + }, + mysql: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.insert({}).returning(post.id), + pg: { + text: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id"', + string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id"' + }, + sqlite: { + throws: true + }, + mysql: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.insert({}).returning(post.id, post.content), + pg: { + text: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', + string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"' + }, + sqlite: { + throws: true + }, + mysql: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.insert({}).returning([post.id, post.content]), + pg: { + text: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', + string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"' + }, + sqlite: { + throws: true + }, + mysql: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +// handle missing columns +Harness.test({ + query: post.insert([ + { + content: 'whoah', + userId: 1 + }, + { + content: 'hey' + } + ]), + pg: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, DEFAULT)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', DEFAULT)', + params: ['whoah', 1, 'hey'] + }, + sqlite: { + text: 'Sqlite requires the same number of columns in each insert row', + throws: true + }, + mysql: { + text: 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, DEFAULT)', + string: "INSERT INTO `post` (`content`, `userId`) VALUES ('whoah', 1), ('hey', DEFAULT)", + params: ['whoah', 1, 'hey'] + }, + mssql: { + text: 'INSERT INTO [post] ([content], [userId]) VALUES (@1, @2), (@3, DEFAULT)', + string: "INSERT INTO [post] ([content], [userId]) VALUES ('whoah', 1), ('hey', DEFAULT)", + params: ['whoah', 1, 'hey'] + }, + oracle: { + text: 'INSERT INTO "post" ("content", "userId") VALUES (:1, :2), (:3, DEFAULT)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', DEFAULT)', + params: ['whoah', 1, 'hey'] + } +}); + +Harness.test({ + query: post.insert([ + { + userId: 1 + }, + { + content: 'hey', + userId: 2 + } + ]), + pg: { + text: 'INSERT INTO "post" ("userId", "content") VALUES ($1, DEFAULT), ($2, $3)', + string: 'INSERT INTO "post" ("userId", "content") VALUES (1, DEFAULT), (2, \'hey\')', + params: [1, 2, 'hey'] + }, + sqlite: { + text: 'Sqlite requires the same number of columns in each insert row', + throws: true + }, + mysql: { + text: 'INSERT INTO `post` (`userId`, `content`) VALUES (?, DEFAULT), (?, ?)', + string: "INSERT INTO `post` (`userId`, `content`) VALUES (1, DEFAULT), (2, 'hey')", + params: [1, 2, 'hey'] + }, + mssql: { + text: 'INSERT INTO [post] ([userId], [content]) VALUES (@1, DEFAULT), (@2, @3)', + string: "INSERT INTO [post] ([userId], [content]) VALUES (1, DEFAULT), (2, 'hey')", + params: [1, 2, 'hey'] + }, + oracle: { + text: 'INSERT INTO "post" ("userId", "content") VALUES (:1, DEFAULT), (:2, :3)', + string: 'INSERT INTO "post" ("userId", "content") VALUES (1, DEFAULT), (2, \'hey\')', + params: [1, 2, 'hey'] + } +}); + +Harness.test({ + query: post + .insert(post.content, post.userId) + .select("'test'", user.id) + .from(user) + .where(user.name.like('A%')), + pg: { + text: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', + string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' + }, + sqlite: { + text: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', + string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' + }, + mysql: { + text: "INSERT INTO `post` (`content`, `userId`) SELECT 'test', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE ?)", + string: "INSERT INTO `post` (`content`, `userId`) SELECT 'test', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE 'A%')" + }, + mssql: { + text: "INSERT INTO [post] ([content], [userId]) SELECT 'test', [user].[id] FROM [user] WHERE ([user].[name] LIKE @1)", + string: "INSERT INTO [post] ([content], [userId]) SELECT 'test', [user].[id] FROM [user] WHERE ([user].[name] LIKE 'A%')" + }, + oracle: { + text: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE :1)', + string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' + }, + params: ['A%'] +}); + +Harness.test({ + query: post + .insert([post.content, post.userId]) + .select("'test'", user.id) + .from(user) + .where(user.name.like('A%')), + pg: { + text: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', + string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' + }, + sqlite: { + text: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', + string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' + }, + mysql: { + text: "INSERT INTO `post` (`content`, `userId`) SELECT 'test', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE ?)", + string: "INSERT INTO `post` (`content`, `userId`) SELECT 'test', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE 'A%')" + }, + mssql: { + text: "INSERT INTO [post] ([content], [userId]) SELECT 'test', [user].[id] FROM [user] WHERE ([user].[name] LIKE @1)", + string: "INSERT INTO [post] ([content], [userId]) SELECT 'test', [user].[id] FROM [user] WHERE ([user].[name] LIKE 'A%')" + }, + oracle: { + text: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE :1)', + string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' + }, + params: ['A%'] +}); + +Harness.test({ + query: post + .insert(post.userId) + .select(user.id) + .from(user) + .where(user.name.like('A%')), + pg: { + text: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' + }, + sqlite: { + text: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' + }, + mysql: { + text: 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user` WHERE (`user`.`name` LIKE ?)', + string: "INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user` WHERE (`user`.`name` LIKE 'A%')" + }, + oracle: { + text: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE :1)', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' + }, + params: ['A%'] +}); + +Harness.test({ + query: post + .insert(post.userId) + .select(post.userId) + .from(user.join(post).on(user.id.equals(post.userId))) + .where(post.tags.like('A%')), + pg: { + text: + 'INSERT INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE $1)', + string: + 'INSERT INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE \'A%\')' + }, + sqlite: { + text: + 'INSERT INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE $1)', + string: + 'INSERT INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE \'A%\')' + }, + mysql: { + text: + 'INSERT INTO `post` (`userId`) SELECT `post`.`userId` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`post`.`tags` LIKE ?)', + string: + "INSERT INTO `post` (`userId`) SELECT `post`.`userId` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`post`.`tags` LIKE 'A%')" + }, + mssql: { + text: + 'INSERT INTO [post] ([userId]) SELECT [post].[userId] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) WHERE ([post].[tags] LIKE @1)', + string: + "INSERT INTO [post] ([userId]) SELECT [post].[userId] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) WHERE ([post].[tags] LIKE 'A%')" + }, + oracle: { + text: + 'INSERT INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE :1)', + string: + 'INSERT INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE \'A%\')' + }, + params: ['A%'] +}); + +Harness.test({ + query: post + .insert(post.userId) + .select(user.id) + .distinct() + .from(user), + pg: { + text: 'INSERT INTO "post" ("userId") SELECT DISTINCT "user"."id" FROM "user"', + string: 'INSERT INTO "post" ("userId") SELECT DISTINCT "user"."id" FROM "user"' + }, + sqlite: { + text: 'INSERT INTO "post" ("userId") SELECT DISTINCT "user"."id" FROM "user"', + string: 'INSERT INTO "post" ("userId") SELECT DISTINCT "user"."id" FROM "user"' + }, + mysql: { + text: 'INSERT INTO `post` (`userId`) SELECT DISTINCT `user`.`id` FROM `user`', + string: 'INSERT INTO `post` (`userId`) SELECT DISTINCT `user`.`id` FROM `user`' + }, + mssql: { + text: 'INSERT INTO [post] ([userId]) SELECT DISTINCT [user].[id] FROM [user]', + string: 'INSERT INTO [post] ([userId]) SELECT DISTINCT [user].[id] FROM [user]' + }, + oracle: { + text: 'INSERT INTO "post" ("userId") SELECT DISTINCT "user"."id" FROM "user"', + string: 'INSERT INTO "post" ("userId") SELECT DISTINCT "user"."id" FROM "user"' + }, + params: [] +}); + +// Binary inserts +Harness.test({ + query: post.insert(post.content.value(Buffer.from('test')), post.userId.value(2)), + pg: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'\\x74657374\', 2)' + }, + sqlite: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (x\'74657374\', 2)' + }, + mysql: { + text: 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', + string: "INSERT INTO `post` (`content`, `userId`) VALUES (x'74657374', 2)" + }, + mssql: { + text: 'INSERT INTO [post] ([content], [userId]) VALUES (@1, @2)', + string: "INSERT INTO [post] ([content], [userId]) VALUES ('\\x74657374', 2)" + }, + oracle: { + text: 'INSERT INTO "post" ("content", "userId") VALUES (:1, :2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (utl_raw.cast_to_varchar2(hextoraw(\'74657374\')), 2)' + }, + params: [Buffer.from('test'), 2] +}); + +Harness.test({ + query: post.insert({ + content: Buffer.from('test'), + userId: 2 + }), + pg: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'\\x74657374\', 2)' + }, + sqlite: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (x\'74657374\', 2)' + }, + mysql: { + text: 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', + string: "INSERT INTO `post` (`content`, `userId`) VALUES (x'74657374', 2)" + }, + mssql: { + text: 'INSERT INTO [post] ([content], [userId]) VALUES (@1, @2)', + string: "INSERT INTO [post] ([content], [userId]) VALUES ('\\x74657374', 2)" + }, + oracle: { + text: 'INSERT INTO "post" ("content", "userId") VALUES (:1, :2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (utl_raw.cast_to_varchar2(hextoraw(\'74657374\')), 2)' + }, + params: [Buffer.from('test'), 2] +}); + +Harness.test({ + query: post.insert([ + { + content: Buffer.from('whoah') + }, + { + content: Buffer.from('hey') + } + ]), + pg: { + text: 'INSERT INTO "post" ("content") VALUES ($1), ($2)', + string: 'INSERT INTO "post" ("content") ' + "VALUES ('\\x77686f6168'), ('\\x686579')" + }, + sqlite: { + text: 'INSERT INTO "post" ("content") VALUES ($1), ($2)', + string: 'INSERT INTO "post" ("content") VALUES (x\'77686f6168\'), (x\'686579\')' + }, + mysql: { + text: 'INSERT INTO `post` (`content`) VALUES (?), (?)', + string: "INSERT INTO `post` (`content`) VALUES (x'77686f6168'), (x'686579')" + }, + mssql: { + text: 'INSERT INTO [post] ([content]) VALUES (@1), (@2)', + string: "INSERT INTO [post] ([content]) VALUES ('\\x77686f6168'), ('\\x686579')" + }, + oracle: { + text: 'INSERT INTO "post" ("content") VALUES (:1), (:2)', + string: + 'INSERT INTO "post" ("content") VALUES (utl_raw.cast_to_varchar2(hextoraw(\'77686f6168\'))), (utl_raw.cast_to_varchar2(hextoraw(\'686579\')))' + }, + params: [Buffer.from('whoah'), Buffer.from('hey')] +}); + +Harness.test({ + query: post + .insert({ + content: 'test', + userId: 2 + }) + .onDuplicate({ + content: 'testupdate' + }), + pg: { + throws: true + }, + sqlite: { + throws: true + }, + mysql: { + text: 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?) ON DUPLICATE KEY UPDATE `post`.`content` = ?', + string: "INSERT INTO `post` (`content`, `userId`) VALUES ('test', 2) ON DUPLICATE KEY UPDATE `post`.`content` = 'testupdate'" + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2, 'testupdate'] +}); + +Harness.test({ + query: customerAliasTable + .insert({ + id_alias: 2, + name_alias: 'test' + }) + .onConflict({ + columns: ['id'], + update: ['name'] + }), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + text: 'INSERT INTO "customer" ("id", "name") VALUES ($1, $2) ON CONFLICT ("id") DO UPDATE SET "name" = EXCLUDED."name"', + string: 'INSERT INTO "customer" ("id", "name") VALUES (2, \'test\') ON CONFLICT ("id") DO UPDATE SET "name" = EXCLUDED."name"' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [2, 'test'] +}); + +Harness.test({ + query: customerAliasTable + .insert({ + id_alias: 2, + name_alias: 'test' + }) + .orIgnore(), + mysql: { + throws: true + }, + sqlite: { + text: 'INSERT OR IGNORE INTO "customer" ("id", "name") VALUES ($1, $2)', + string: 'INSERT OR IGNORE INTO "customer" ("id", "name") VALUES (2, \'test\')' + }, + pg: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [2, 'test'] +}); + +Harness.test({ + query: post + .insert({ + content: 'test', + userId: 2 + }) + .onConflict({ + columns: ['userId'], + update: ['content'] + }), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + text: + 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2) ON CONFLICT ("userId") DO UPDATE SET "content" = EXCLUDED."content"', + string: + 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2) ON CONFLICT ("userId") DO UPDATE SET "content" = EXCLUDED."content"' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2] +}); + +Harness.test({ + query: post + .insert({ + content: 'test', + userId: 2 + }) + .onConflict({ + columns: ['userId', 'content'], + update: ['content', 'userId'] + }), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + text: + 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2) ON CONFLICT ("userId", "content") DO UPDATE SET "content" = EXCLUDED."content", "userId" = EXCLUDED."userId"', + string: + 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2) ON CONFLICT ("userId", "content") DO UPDATE SET "content" = EXCLUDED."content", "userId" = EXCLUDED."userId"' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2] +}); + +Harness.test({ + query: post + .insert({ + content: 'test', + userId: 2 + }) + .onConflict({ + columns: ['userId', 'content'], + where: post.length.gt(250), + update: ['content', 'userId'], + }), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + text: + 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2) ON CONFLICT ("userId", "content") WHERE ("post"."length" > $3) DO UPDATE SET "content" = EXCLUDED."content", "userId" = EXCLUDED."userId"', + string: + 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2) ON CONFLICT ("userId", "content") WHERE ("post"."length" > 250) DO UPDATE SET "content" = EXCLUDED."content", "userId" = EXCLUDED."userId"' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2, 250] +}); + +Harness.test({ + query: post + .insert({ + content: 'test', + userId: 2 + }) + .onConflict({ + columns: ['userId'], + update: ['content'] + }) + .where(post.userId.equals(2)), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + text: + 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2) ON CONFLICT ("userId") DO UPDATE SET "content" = EXCLUDED."content" WHERE ("post"."userId" = $3)', + string: + 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2) ON CONFLICT ("userId") DO UPDATE SET "content" = EXCLUDED."content" WHERE ("post"."userId" = 2)' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2, 2] +}); + +Harness.test({ + query: post + .insert({ + content: 'test', + userId: 2 + }) + .onConflict({ + constraint: 'conc_userId', + update: ['content'] + }) + .where(post.userId.equals(2)), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + text: + 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2) ON CONFLICT ON CONSTRAINT "conc_userId" DO UPDATE SET "content" = EXCLUDED."content" WHERE ("post"."userId" = $3)', + string: + 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2) ON CONFLICT ON CONSTRAINT "conc_userId" DO UPDATE SET "content" = EXCLUDED."content" WHERE ("post"."userId" = 2)' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2, 2] +}); + +Harness.test({ + query: post + .insert({ + content: 'test', + userId: 2 + }) + .onConflict({ + columns: ['userId'] + }), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2) ON CONFLICT ("userId") DO NOTHING', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2) ON CONFLICT ("userId") DO NOTHING' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2] +}); + +Harness.test({ + query: post + .insert({ + content: 'test', + userId: 2 + }) + .onConflict(), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2) ON CONFLICT DO NOTHING', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2) ON CONFLICT DO NOTHING' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2] +}); + +Harness.test({ + query: post + .insert({ + content: 'test', + userId: 2 + }) + .onConflict({ + constraint: 'conc_userId' + }), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2) ON CONFLICT ON CONSTRAINT "conc_userId" DO NOTHING', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2) ON CONFLICT ON CONSTRAINT "conc_userId" DO NOTHING' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2] +}); + +Harness.test({ + query: contentTable + .insert({ + contentId: 20, + text: 'something' + }) + .onConflict({ + columns: ['contentId'] + }), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + text: 'INSERT INTO "content" ("content_id", "text") VALUES ($1, $2) ON CONFLICT ("content_id") DO NOTHING', + string: 'INSERT INTO "content" ("content_id", "text") VALUES (20, \'something\') ON CONFLICT ("content_id") DO NOTHING' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [20, 'something'] +}); + +Harness.test({ + query: contentTable + .insert({ + contentId: 20, + text: 'something', + contentPosts: 'another thing' + }) + .onConflict({ + columns: ['contentId'], + update: ['contentPosts'] + }), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + text: + 'INSERT INTO "content" ("content_id", "text", "content_posts") VALUES ($1, $2, $3) ON CONFLICT ("content_id") DO UPDATE SET "content_posts" = EXCLUDED."content_posts"', + string: + 'INSERT INTO "content" ("content_id", "text", "content_posts") VALUES (20, \'something\', \'another thing\') ON CONFLICT ("content_id") DO UPDATE SET "content_posts" = EXCLUDED."content_posts"' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [20, 'something', 'another thing'] +}); + +Harness.test({ + query: post.insert([]), + + mysql: { + text: 'SELECT `post`.* FROM `post` WHERE (1=2)', + string: 'SELECT `post`.* FROM `post` WHERE (1=2)' + }, + params: [] +}); + +Harness.test({ + query: arrayTable.insert(arrayTable.id.value(1), arrayTable.numbers.value([2, 3, 4])), + pg: { + text: 'INSERT INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', + string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, \'{2,3,4}\')' + }, + sqlite: { + text: 'INSERT INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', + string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, \'[2,3,4]\')' + }, + mysql: { + text: 'INSERT INTO `arraytest` (`id`, `numbers`) VALUES (?, ?)', + string: 'INSERT INTO `arraytest` (`id`, `numbers`) VALUES (1, (2, 3, 4))' + }, + oracle: { + text: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (:1, :2)', + string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, (2, 3, 4))' + } +}); + +Harness.test({ + query: arrayTable.insert(arrayTable.id.value(1), arrayTable.numbers.value(['one', 'two', 'three'])), + pg: { + text: 'INSERT INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', + string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, \'{"one","two","three"}\')' + }, + sqlite: { + text: 'INSERT INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', + string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, \'["one","two","three"]\')' + }, + mysql: { + text: 'INSERT INTO `arraytest` (`id`, `numbers`) VALUES (?, ?)', + string: "INSERT INTO `arraytest` (`id`, `numbers`) VALUES (1, ('one', 'two', 'three'))" + }, + oracle: { + text: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (:1, :2)', + string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, (\'one\', \'two\', \'three\'))' + } +}); + +Harness.test({ + query: post + .insert(post.userId) + .select(user.id) + .from(user), + pg: { + text: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + sqlite: { + text: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + mysql: { + text: 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user`', + string: 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user`' + }, + mssql: { + text: 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user]', + string: 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user]' + }, + oracle: { + text: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: post + .insert(post.userId) + .select(user.id) + .from(user) + .onConflict({ + columns: ['userId'], + update: ['content'] + }), + pg: { + text: + 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" ON CONFLICT ("userId") DO UPDATE SET "content" = EXCLUDED."content"', + string: + 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" ON CONFLICT ("userId") DO UPDATE SET "content" = EXCLUDED."content"' + }, + sqlite: { + throws: true + }, + mysql: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.insert(post.userId).add(user.select(user.id)), + pg: { + text: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + sqlite: { + text: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + mysql: { + text: 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user`', + string: 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user`' + }, + mssql: { + text: 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user]', + string: 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user]' + }, + oracle: { + text: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: post.insert(post.userId).add(user.select(user.id).from(user)), + pg: { + text: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + sqlite: { + text: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + mysql: { + text: 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user`', + string: 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user`' + }, + mssql: { + text: 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user]', + string: 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user]' + }, + oracle: { + text: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: post.insert(post.userId).add(user.select(user.id).order(user.id)), + pg: { + text: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"' + }, + sqlite: { + text: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"' + }, + mysql: { + text: 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user` ORDER BY `user`.`id`', + string: 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user` ORDER BY `user`.`id`' + }, + mssql: { + text: 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user] ORDER BY [user].[id]', + string: 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user] ORDER BY [user].[id]' + }, + oracle: { + text: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"' + }, + params: [] +}); diff --git a/test/dialects/join-tests.js b/test/dialects/join-tests.js deleted file mode 100644 index abebdb01..00000000 --- a/test/dialects/join-tests.js +++ /dev/null @@ -1,176 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var user = Harness.defineUserTable(); -var post = Harness.definePostTable(); -var comment = Harness.defineCommentTable(); - -Harness.test({ - query: user.select(user.name, post.content).from(user.join(post).on(user.id.equals(post.userId))), - pg: { - text : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', - string: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' - }, - sqlite: { - text : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', - string: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' - }, - mysql: { - text : 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)', - string: 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' - }, - mssql: { - text : 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId])', - string: 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId])' - }, - oracle: { - text : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', - string: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' - }, - params: [] -}); - -Harness.test({ - query: user.join(post).on(user.id.equals(post.userId)), - pg: { - text : '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', - string: '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' - }, - sqlite: { - text : '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', - string: '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' - }, - mysql: { - text : '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)', - string: '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' - }, - mssql: { - text : '[user] INNER JOIN [post] ON ([user].[id] = [post].[userId])', - string: '[user] INNER JOIN [post] ON ([user].[id] = [post].[userId])' - }, - oracle: { - text : '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', - string: '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' - }, - params: [] -}); - -Harness.test({ - query: user - .select(user.name, post.content, comment.text) - .from( - user - .join(post).on(user.id.equals(post.userId)) - .join(comment).on(post.id.equals(comment.postId))), - pg: { - text : 'SELECT "user"."name", "post"."content", "comment"."text" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") INNER JOIN "comment" ON ("post"."id" = "comment"."postId")', - string: 'SELECT "user"."name", "post"."content", "comment"."text" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") INNER JOIN "comment" ON ("post"."id" = "comment"."postId")' - }, - sqlite: { - text : 'SELECT "user"."name", "post"."content", "comment"."text" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") INNER JOIN "comment" ON ("post"."id" = "comment"."postId")', - string: 'SELECT "user"."name", "post"."content", "comment"."text" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") INNER JOIN "comment" ON ("post"."id" = "comment"."postId")' - }, - mysql: { - text : 'SELECT `user`.`name`, `post`.`content`, `comment`.`text` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) INNER JOIN `comment` ON (`post`.`id` = `comment`.`postId`)', - string: 'SELECT `user`.`name`, `post`.`content`, `comment`.`text` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) INNER JOIN `comment` ON (`post`.`id` = `comment`.`postId`)' - }, - mssql: { - text : 'SELECT [user].[name], [post].[content], [comment].[text] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) INNER JOIN [comment] ON ([post].[id] = [comment].[postId])', - string: 'SELECT [user].[name], [post].[content], [comment].[text] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) INNER JOIN [comment] ON ([post].[id] = [comment].[postId])' - }, - oracle: { - text : 'SELECT "user"."name", "post"."content", "comment"."text" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") INNER JOIN "comment" ON ("post"."id" = "comment"."postId")', - string: 'SELECT "user"."name", "post"."content", "comment"."text" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") INNER JOIN "comment" ON ("post"."id" = "comment"."postId")' - }, - params: [] -}); - -Harness.test({ - query: user.select(user.name, post.content).from(user.leftJoin(post).on(user.id.equals(post.userId))), - pg: { - text : 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")', - string: 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")' - }, - sqlite: { - text : 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")', - string: 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")' - }, - mysql: { - text : 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`)', - string: 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`)' - }, - mssql: { - text : 'SELECT [user].[name], [post].[content] FROM [user] LEFT JOIN [post] ON ([user].[id] = [post].[userId])', - string: 'SELECT [user].[name], [post].[content] FROM [user] LEFT JOIN [post] ON ([user].[id] = [post].[userId])' - }, - oracle: { - text : 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")', - string: 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")' - }, - params: [] -}); - -Harness.test({ - query: user - .select(user.name, post.content) - .from( - user - .leftJoin(post).on(user.id.equals(post.userId)) - .leftJoin(comment).on(post.id.equals(comment.postId))), - pg: { - text : 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId") LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")', - string: 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId") LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")' - }, - sqlite: { - text : 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId") LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")', - string: 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId") LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")' - }, - mysql: { - text : 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`) LEFT JOIN `comment` ON (`post`.`id` = `comment`.`postId`)', - string: 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`) LEFT JOIN `comment` ON (`post`.`id` = `comment`.`postId`)' - }, - mssql: { - text : 'SELECT [user].[name], [post].[content] FROM [user] LEFT JOIN [post] ON ([user].[id] = [post].[userId]) LEFT JOIN [comment] ON ([post].[id] = [comment].[postId])', - string: 'SELECT [user].[name], [post].[content] FROM [user] LEFT JOIN [post] ON ([user].[id] = [post].[userId]) LEFT JOIN [comment] ON ([post].[id] = [comment].[postId])' - }, - oracle: { - text : 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId") LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")', - string: 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId") LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")' - }, - params: [] -}); - -var subposts = post - .subQuery('subposts') - .select( - post.content, - post.userId.as('subpostUserId')) - .from(post); - -Harness.test({ - query: user - .select(user.name, subposts.content) - .from(user.join(subposts) - .on(user.id.equals(subposts.subpostUserId))), - pg: { - text : 'SELECT "user"."name", "subposts"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" AS "subpostUserId" FROM "post") "subposts" ON ("user"."id" = "subposts"."subpostUserId")', - string: 'SELECT "user"."name", "subposts"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" AS "subpostUserId" FROM "post") "subposts" ON ("user"."id" = "subposts"."subpostUserId")' - }, - sqlite: { - text : 'SELECT "user"."name", "subposts"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" AS "subpostUserId" FROM "post") "subposts" ON ("user"."id" = "subposts"."subpostUserId")', - string: 'SELECT "user"."name", "subposts"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" AS "subpostUserId" FROM "post") "subposts" ON ("user"."id" = "subposts"."subpostUserId")' - }, - mysql: { - text : 'SELECT `user`.`name`, `subposts`.`content` FROM `user` INNER JOIN (SELECT `post`.`content`, `post`.`userId` AS `subpostUserId` FROM `post`) `subposts` ON (`user`.`id` = `subposts`.`subpostUserId`)', - string: 'SELECT `user`.`name`, `subposts`.`content` FROM `user` INNER JOIN (SELECT `post`.`content`, `post`.`userId` AS `subpostUserId` FROM `post`) `subposts` ON (`user`.`id` = `subposts`.`subpostUserId`)' - }, - mssql: { - text : 'SELECT [user].[name], [subposts].[content] FROM [user] INNER JOIN (SELECT [post].[content], [post].[userId] AS [subpostUserId] FROM [post]) [subposts] ON ([user].[id] = [subposts].[subpostUserId])', - string: 'SELECT [user].[name], [subposts].[content] FROM [user] INNER JOIN (SELECT [post].[content], [post].[userId] AS [subpostUserId] FROM [post]) [subposts] ON ([user].[id] = [subposts].[subpostUserId])' - }, - oracle: { - text : 'SELECT "user"."name", "subposts"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" "subpostUserId" FROM "post") "subposts" ON ("user"."id" = "subposts"."subpostUserId")', - string: 'SELECT "user"."name", "subposts"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" "subpostUserId" FROM "post") "subposts" ON ("user"."id" = "subposts"."subpostUserId")' - }, - params: [] -}); diff --git a/test/dialects/join-tests.ts b/test/dialects/join-tests.ts new file mode 100644 index 00000000..e8f0555e --- /dev/null +++ b/test/dialects/join-tests.ts @@ -0,0 +1,201 @@ +import * as Harness from './support.js'; +const post = Harness.definePostTable(); +const user = Harness.defineUserTable(); +const comment = Harness.defineCommentTable(); + +Harness.test({ + query: user.select(user.name, post.content).from(user.join(post).on(user.id.equals(post.userId))), + pg: { + text: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + string: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' + }, + sqlite: { + text: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + string: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' + }, + mysql: { + text: 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)', + string: 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' + }, + mssql: { + text: 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId])', + string: 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId])' + }, + oracle: { + text: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + string: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' + }, + params: [] +}); + +Harness.test({ + query: user.join(post).on(user.id.equals(post.userId)), + pg: { + text: '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + string: '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' + }, + sqlite: { + text: '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + string: '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' + }, + mysql: { + text: '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)', + string: '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' + }, + mssql: { + text: '[user] INNER JOIN [post] ON ([user].[id] = [post].[userId])', + string: '[user] INNER JOIN [post] ON ([user].[id] = [post].[userId])' + }, + oracle: { + text: '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + string: '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' + }, + params: [] +}); + +Harness.test({ + query: user.select(user.name, post.content, comment.text).from( + user + .join(post) + .on(user.id.equals(post.userId)) + .join(comment) + .on(post.id.equals(comment.postId)) + ), + pg: { + text: + 'SELECT "user"."name", "post"."content", "comment"."text" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") INNER JOIN "comment" ON ("post"."id" = "comment"."postId")', + string: + 'SELECT "user"."name", "post"."content", "comment"."text" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") INNER JOIN "comment" ON ("post"."id" = "comment"."postId")' + }, + sqlite: { + text: + 'SELECT "user"."name", "post"."content", "comment"."text" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") INNER JOIN "comment" ON ("post"."id" = "comment"."postId")', + string: + 'SELECT "user"."name", "post"."content", "comment"."text" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") INNER JOIN "comment" ON ("post"."id" = "comment"."postId")' + }, + mysql: { + text: + 'SELECT `user`.`name`, `post`.`content`, `comment`.`text` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) INNER JOIN `comment` ON (`post`.`id` = `comment`.`postId`)', + string: + 'SELECT `user`.`name`, `post`.`content`, `comment`.`text` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) INNER JOIN `comment` ON (`post`.`id` = `comment`.`postId`)' + }, + mssql: { + text: + 'SELECT [user].[name], [post].[content], [comment].[text] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) INNER JOIN [comment] ON ([post].[id] = [comment].[postId])', + string: + 'SELECT [user].[name], [post].[content], [comment].[text] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) INNER JOIN [comment] ON ([post].[id] = [comment].[postId])' + }, + oracle: { + text: + 'SELECT "user"."name", "post"."content", "comment"."text" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") INNER JOIN "comment" ON ("post"."id" = "comment"."postId")', + string: + 'SELECT "user"."name", "post"."content", "comment"."text" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") INNER JOIN "comment" ON ("post"."id" = "comment"."postId")' + }, + params: [] +}); + +Harness.test({ + query: user.select(user.name, post.content).from(user.leftJoin(post).on(user.id.equals(post.userId))), + pg: { + text: 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")', + string: 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")' + }, + sqlite: { + text: 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")', + string: 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")' + }, + mysql: { + text: 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`)', + string: 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`)' + }, + mssql: { + text: 'SELECT [user].[name], [post].[content] FROM [user] LEFT JOIN [post] ON ([user].[id] = [post].[userId])', + string: 'SELECT [user].[name], [post].[content] FROM [user] LEFT JOIN [post] ON ([user].[id] = [post].[userId])' + }, + oracle: { + text: 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")', + string: 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")' + }, + params: [] +}); + +Harness.test({ + query: user.select(user.name, post.content).from( + user + .leftJoin(post) + .on(user.id.equals(post.userId)) + .leftJoin(comment) + .on(post.id.equals(comment.postId)) + ), + pg: { + text: + 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId") LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")', + string: + 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId") LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")' + }, + sqlite: { + text: + 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId") LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")', + string: + 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId") LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")' + }, + mysql: { + text: + 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`) LEFT JOIN `comment` ON (`post`.`id` = `comment`.`postId`)', + string: + 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`) LEFT JOIN `comment` ON (`post`.`id` = `comment`.`postId`)' + }, + mssql: { + text: + 'SELECT [user].[name], [post].[content] FROM [user] LEFT JOIN [post] ON ([user].[id] = [post].[userId]) LEFT JOIN [comment] ON ([post].[id] = [comment].[postId])', + string: + 'SELECT [user].[name], [post].[content] FROM [user] LEFT JOIN [post] ON ([user].[id] = [post].[userId]) LEFT JOIN [comment] ON ([post].[id] = [comment].[postId])' + }, + oracle: { + text: + 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId") LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")', + string: + 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId") LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")' + }, + params: [] +}); + +const subposts = post + .subQuery<{ content?: string, subpostUserId: number }>('subposts') + .select(post.content, post.userId.as('subpostUserId')) + .from(post); + +Harness.test({ + query: user.select(user.name, subposts.content).from(user.join(subposts).on(user.id.equals(subposts.subpostUserId))), + pg: { + text: + 'SELECT "user"."name", "subposts"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" AS "subpostUserId" FROM "post") "subposts" ON ("user"."id" = "subposts"."subpostUserId")', + string: + 'SELECT "user"."name", "subposts"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" AS "subpostUserId" FROM "post") "subposts" ON ("user"."id" = "subposts"."subpostUserId")' + }, + sqlite: { + text: + 'SELECT "user"."name", "subposts"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" AS "subpostUserId" FROM "post") "subposts" ON ("user"."id" = "subposts"."subpostUserId")', + string: + 'SELECT "user"."name", "subposts"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" AS "subpostUserId" FROM "post") "subposts" ON ("user"."id" = "subposts"."subpostUserId")' + }, + mysql: { + text: + 'SELECT `user`.`name`, `subposts`.`content` FROM `user` INNER JOIN (SELECT `post`.`content`, `post`.`userId` AS `subpostUserId` FROM `post`) `subposts` ON (`user`.`id` = `subposts`.`subpostUserId`)', + string: + 'SELECT `user`.`name`, `subposts`.`content` FROM `user` INNER JOIN (SELECT `post`.`content`, `post`.`userId` AS `subpostUserId` FROM `post`) `subposts` ON (`user`.`id` = `subposts`.`subpostUserId`)' + }, + mssql: { + text: + 'SELECT [user].[name], [subposts].[content] FROM [user] INNER JOIN (SELECT [post].[content], [post].[userId] AS [subpostUserId] FROM [post]) [subposts] ON ([user].[id] = [subposts].[subpostUserId])', + string: + 'SELECT [user].[name], [subposts].[content] FROM [user] INNER JOIN (SELECT [post].[content], [post].[userId] AS [subpostUserId] FROM [post]) [subposts] ON ([user].[id] = [subposts].[subpostUserId])' + }, + oracle: { + text: + 'SELECT "user"."name", "subposts"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" "subpostUserId" FROM "post") "subposts" ON ("user"."id" = "subposts"."subpostUserId")', + string: + 'SELECT "user"."name", "subposts"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" "subpostUserId" FROM "post") "subposts" ON ("user"."id" = "subposts"."subpostUserId")' + }, + params: [] +}); diff --git a/test/dialects/join-to-tests.js b/test/dialects/join-to-tests.js deleted file mode 100644 index d50f8817..00000000 --- a/test/dialects/join-to-tests.js +++ /dev/null @@ -1,112 +0,0 @@ -'use strict'; -var sql = require(__dirname + '/../../lib'); - -var Harness = require('./support'); - -var user = sql.define({ - name: 'user', - columns: { - id: { - primaryKey: true - } - } -}); - -var photo = sql.define({ - name: 'photo', - columns: { - ownerId: { - references: 'user' - } - } -}); - -var post = sql.define({ - name: 'post', - columns: { - id: { - primaryKey: true - }, - ownerId: { - references: { - table: 'user', - column: 'id' - } - } - } -}); - -Harness.test({ - query: user.joinTo(post), - pg: { - text : '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")', - string: '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")' - }, - sqlite: { - text : '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")', - string: '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")' - }, - mysql: { - text : '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`ownerId`)', - string: '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`ownerId`)' - }, - mssql: { - text : '[user] INNER JOIN [post] ON ([user].[id] = [post].[ownerId])', - string: '[user] INNER JOIN [post] ON ([user].[id] = [post].[ownerId])' - }, - oracle: { - text : '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")', - string: '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")' - }, - params: [] -}); - -Harness.test({ - query: post.joinTo(user), - pg: { - text : '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")', - string: '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")' - }, - sqlite: { - text : '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")', - string: '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")' - }, - mysql: { - text : '`post` INNER JOIN `user` ON (`user`.`id` = `post`.`ownerId`)', - string: '`post` INNER JOIN `user` ON (`user`.`id` = `post`.`ownerId`)' - }, - mssql: { - text : '[post] INNER JOIN [user] ON ([user].[id] = [post].[ownerId])', - string: '[post] INNER JOIN [user] ON ([user].[id] = [post].[ownerId])' - }, - oracle: { - text : '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")', - string: '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")' - }, - params: [] -}); - -Harness.test({ - query: user.joinTo(photo), - pg: { - text : '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")', - string: '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")' - }, - sqlite: { - text : '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")', - string: '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")' - }, - mysql: { - text : '`user` INNER JOIN `photo` ON (`user`.`id` = `photo`.`ownerId`)', - string: '`user` INNER JOIN `photo` ON (`user`.`id` = `photo`.`ownerId`)' - }, - mssql: { - text : '[user] INNER JOIN [photo] ON ([user].[id] = [photo].[ownerId])', - string: '[user] INNER JOIN [photo] ON ([user].[id] = [photo].[ownerId])' - }, - oracle: { - text : '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")', - string: '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")' - }, - params: [] -}); diff --git a/test/dialects/join-to-tests.ts b/test/dialects/join-to-tests.ts new file mode 100644 index 00000000..44155f61 --- /dev/null +++ b/test/dialects/join-to-tests.ts @@ -0,0 +1,111 @@ +import * as Harness from './support.js'; +import { Sql } from '../../dist/lib.js'; +const instance = new Sql('postgres'); + +const user = instance.define({ + name: 'user', + columns: { + id: { + primaryKey: true + } + } +}); + +const photo = instance.define({ + name: 'photo', + columns: { + ownerId: { + references: 'user' + } + } +}); + +const post = instance.define({ + name: 'post', + columns: { + id: { + primaryKey: true + }, + ownerId: { + references: { + table: 'user', + column: 'id' + } + } + } +}); + +Harness.test({ + query: user.joinTo(post), + pg: { + text: '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")', + string: '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")' + }, + sqlite: { + text: '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")', + string: '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")' + }, + mysql: { + text: '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`ownerId`)', + string: '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`ownerId`)' + }, + mssql: { + text: '[user] INNER JOIN [post] ON ([user].[id] = [post].[ownerId])', + string: '[user] INNER JOIN [post] ON ([user].[id] = [post].[ownerId])' + }, + oracle: { + text: '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")', + string: '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")' + }, + params: [] +}); + +Harness.test({ + query: post.joinTo(user), + pg: { + text: '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")', + string: '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")' + }, + sqlite: { + text: '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")', + string: '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")' + }, + mysql: { + text: '`post` INNER JOIN `user` ON (`user`.`id` = `post`.`ownerId`)', + string: '`post` INNER JOIN `user` ON (`user`.`id` = `post`.`ownerId`)' + }, + mssql: { + text: '[post] INNER JOIN [user] ON ([user].[id] = [post].[ownerId])', + string: '[post] INNER JOIN [user] ON ([user].[id] = [post].[ownerId])' + }, + oracle: { + text: '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")', + string: '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")' + }, + params: [] +}); + +Harness.test({ + query: user.joinTo(photo), + pg: { + text: '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")', + string: '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")' + }, + sqlite: { + text: '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")', + string: '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")' + }, + mysql: { + text: '`user` INNER JOIN `photo` ON (`user`.`id` = `photo`.`ownerId`)', + string: '`user` INNER JOIN `photo` ON (`user`.`id` = `photo`.`ownerId`)' + }, + mssql: { + text: '[user] INNER JOIN [photo] ON ([user].[id] = [photo].[ownerId])', + string: '[user] INNER JOIN [photo] ON ([user].[id] = [photo].[ownerId])' + }, + oracle: { + text: '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")', + string: '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")' + }, + params: [] +}); diff --git a/test/dialects/json-tests.js b/test/dialects/json-tests.js deleted file mode 100644 index b610b96f..00000000 --- a/test/dialects/json-tests.js +++ /dev/null @@ -1,41 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var customer = Harness.defineCustomerTable(); -var Sql = require('../../lib').setDialect('postgres'); - -Harness.test({ - query: customer.select(customer.metadata.key('age')), - pg: { - text : 'SELECT ("customer"."metadata" -> $1) FROM "customer"', - string: 'SELECT ("customer"."metadata" -> \'age\') FROM "customer"' - }, - params: ['age'] -}); - -Harness.test({ - query: customer.select(customer.metadata.keyText('age')), - pg: { - text : 'SELECT ("customer"."metadata" ->> $1) FROM "customer"', - string: 'SELECT ("customer"."metadata" ->> \'age\') FROM "customer"' - }, - params: ['age'] -}); - -Harness.test({ - query: customer.select(customer.metadata.path('{address,city}')), - pg: { - text : 'SELECT ("customer"."metadata" #> $1) FROM "customer"', - string: 'SELECT ("customer"."metadata" #> \'{address,city}\') FROM "customer"' - }, - params: ['{address,city}'] -}); - -Harness.test({ - query: customer.select(customer.metadata.pathText('{address,city}')), - pg: { - text : 'SELECT ("customer"."metadata" #>> $1) FROM "customer"', - string: 'SELECT ("customer"."metadata" #>> \'{address,city}\') FROM "customer"' - }, - params: ['{address,city}'] -}); diff --git a/test/dialects/json-tests.ts b/test/dialects/json-tests.ts new file mode 100644 index 00000000..7d8bcc16 --- /dev/null +++ b/test/dialects/json-tests.ts @@ -0,0 +1,38 @@ +import * as Harness from './support.js'; +const customer = Harness.defineCustomerTable(); + +Harness.test({ + query: customer.select(customer.metadata.key('age')), + pg: { + text: 'SELECT ("customer"."metadata" -> $1) FROM "customer"', + string: 'SELECT ("customer"."metadata" -> \'age\') FROM "customer"' + }, + params: ['age'] +}); + +Harness.test({ + query: customer.select(customer.metadata.keyText('age')), + pg: { + text: 'SELECT ("customer"."metadata" ->> $1) FROM "customer"', + string: 'SELECT ("customer"."metadata" ->> \'age\') FROM "customer"' + }, + params: ['age'] +}); + +Harness.test({ + query: customer.select(customer.metadata.path('{address,city}')), + pg: { + text: 'SELECT ("customer"."metadata" #> $1) FROM "customer"', + string: 'SELECT ("customer"."metadata" #> \'{address,city}\') FROM "customer"' + }, + params: ['{address,city}'] +}); + +Harness.test({ + query: customer.select(customer.metadata.pathText('{address,city}')), + pg: { + text: 'SELECT ("customer"."metadata" #>> $1) FROM "customer"', + string: 'SELECT ("customer"."metadata" #>> \'{address,city}\') FROM "customer"' + }, + params: ['{address,city}'] +}); diff --git a/test/dialects/limit-and-offset-tests.js b/test/dialects/limit-and-offset-tests.js deleted file mode 100644 index 6561c14b..00000000 --- a/test/dialects/limit-and-offset-tests.js +++ /dev/null @@ -1,105 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var user = Harness.defineUserTable(); - -// For compatibility with PostgreSQL, MySQL also supports the LIMIT row_count OFFSET offset syntax. -// http://dev.mysql.com/doc/refman/5.0/en/select.html - -Harness.test({ - query: user.select(user.star()).from(user).order(user.name.asc).limit(1), - pg: { - text : 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 1', - string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 1' - }, - sqlite: { - text : 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 1', - string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 1' - }, - mysql: { - text : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 1', - string: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 1' - }, - mssql: { - text : 'SELECT TOP(1) [user].* FROM [user] ORDER BY [user].[name]', - string: 'SELECT TOP(1) [user].* FROM [user] ORDER BY [user].[name]' - }, - params: [] -}); - -Harness.test({ - query: user.select(user.star()).from(user).order(user.name.asc).limit(3).offset(6), - pg: { - text : 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 3 OFFSET 6', - string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 3 OFFSET 6' - }, - sqlite: { - text : 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 3 OFFSET 6', - string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 3 OFFSET 6' - }, - mysql: { - text : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 3 OFFSET 6', - string: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 3 OFFSET 6' - }, - mssql: { - text : 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 6 ROWS FETCH NEXT 3 ROWS ONLY', - string: 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 6 ROWS FETCH NEXT 3 ROWS ONLY' - }, - params: [] -}); - -Harness.test({ - query: user.select(user.star()).from(user).order(user.name.asc).offset(10), - pg: { - text : 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10', - string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10' - }, - sqlite: { - text : 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10', - string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10' - }, - mysql: { - text : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` OFFSET 10', - string: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` OFFSET 10' - }, - mssql: { - text : 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 10 ROWS', - string: 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 10 ROWS' - }, - oracle: { - text : 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10 ROWS', - string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10 ROWS' - }, - params: [] -}); - -Harness.test({ - query: user.select(user.star()).where({ - name: 'John' - }).offset(user.subQuery().select('FLOOR(RANDOM() * COUNT(*))').where({ - name: 'John' - })).limit(1), - pg: { - text : 'SELECT "user".* FROM "user" WHERE ("user"."name" = $1) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = $2)) LIMIT 1', - string: 'SELECT "user".* FROM "user" WHERE ("user"."name" = \'John\') OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = \'John\')) LIMIT 1' - }, - sqlite: { - text : 'SELECT "user".* FROM "user" WHERE ("user"."name" = $1) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = $2)) LIMIT 1', - string: 'SELECT "user".* FROM "user" WHERE ("user"."name" = \'John\') OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = \'John\')) LIMIT 1' - }, - mysql: { - text : 'SELECT `user`.* FROM `user` WHERE (`user`.`name` = ?) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM `user` WHERE (`user`.`name` = ?)) LIMIT 1', - string: 'SELECT `user`.* FROM `user` WHERE (`user`.`name` = \'John\') OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM `user` WHERE (`user`.`name` = \'John\')) LIMIT 1' - }, - mssql: { - text : 'Microsoft SQL Server does not support OFFSET without and ORDER BY.', - throws: true - }, - oracle: { - text : 'SELECT "user".* FROM "user" WHERE ("user"."name" = :1) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = :2)) ROWS FETCH NEXT 1 ROWS ONLY', - string: 'SELECT "user".* FROM "user" WHERE ("user"."name" = \'John\') OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = \'John\')) ROWS FETCH NEXT 1 ROWS ONLY' - }, - values: ['John', 'John'] -}); - -// TODO: Should probably have a test case like the one above but including an ORDER BY clause so the mssql case can be tested \ No newline at end of file diff --git a/test/dialects/limit-and-offset-tests.ts b/test/dialects/limit-and-offset-tests.ts new file mode 100644 index 00000000..6d8551c3 --- /dev/null +++ b/test/dialects/limit-and-offset-tests.ts @@ -0,0 +1,143 @@ +import * as Harness from './support.js'; +const user = Harness.defineUserTable(); + +// For compatibility with PostgreSQL, MySQL also supports the LIMIT row_count OFFSET offset syntax. +// http://dev.mysql.com/doc/refman/5.0/en/select.html + +Harness.test({ + query: user + .select(user.star()) + .from(user) + .order(user.name.asc()) + .limit(1), + pg: { + text: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT $1', + string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 1' + }, + sqlite: { + text: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT $1', + string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 1' + }, + mysql: { + text: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT ?', + string: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 1' + }, + mssql: { + text: 'SELECT TOP(@1) [user].* FROM [user] ORDER BY [user].[name]', + string: 'SELECT TOP(1) [user].* FROM [user] ORDER BY [user].[name]' + }, + params: [1] +}); + +Harness.test({ + query: user + .select(user.star()) + .from(user) + .order(user.name.asc()) + .limit(3) + .offset(6), + pg: { + text: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT $1 OFFSET $2', + string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 3 OFFSET 6' + }, + sqlite: { + text: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT $1 OFFSET $2', + string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 3 OFFSET 6' + }, + mysql: { + text: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT ? OFFSET ?', + string: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 3 OFFSET 6' + }, + params: [3, 6] +}); + +Harness.test({ + query: user + .select(user.star()) + .from(user) + .order(user.name.asc()) + .limit(3) + .offset(6), + mssql: { + text: 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET @1 ROWS FETCH NEXT @2 ROWS ONLY', + string: 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 6 ROWS FETCH NEXT 3 ROWS ONLY' + }, + params: [6, 3] +}); + +Harness.test({ + query: user + .select(user.star()) + .from(user) + .order(user.name.asc()) + .offset(10), + pg: { + text: 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET $1', + string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10' + }, + sqlite: { + text: 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET $1', + string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10' + }, + mysql: { + text: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` OFFSET ?', + string: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` OFFSET 10' + }, + mssql: { + text: 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET @1 ROWS', + string: 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 10 ROWS' + }, + oracle: { + text: 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET :1 ROWS', + string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10 ROWS' + }, + params: [10] +}); + +Harness.test({ + query: user + .select(user.star()) + .where({ + name: 'John' + }) + .offset( + user + .subQuery() + .select('FLOOR(RANDOM() * COUNT(*))') + .where({ + name: 'John' + }) + ) + .limit(1), + pg: { + text: + 'SELECT "user".* FROM "user" WHERE ("user"."name" = $1) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = $2)) LIMIT $3', + string: + 'SELECT "user".* FROM "user" WHERE ("user"."name" = \'John\') OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = \'John\')) LIMIT 1' + }, + sqlite: { + text: + 'SELECT "user".* FROM "user" WHERE ("user"."name" = $1) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = $2)) LIMIT $3', + string: + 'SELECT "user".* FROM "user" WHERE ("user"."name" = \'John\') OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = \'John\')) LIMIT 1' + }, + mysql: { + text: + 'SELECT `user`.* FROM `user` WHERE (`user`.`name` = ?) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM `user` WHERE (`user`.`name` = ?)) LIMIT ?', + string: + "SELECT `user`.* FROM `user` WHERE (`user`.`name` = 'John') OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM `user` WHERE (`user`.`name` = 'John')) LIMIT 1" + }, + mssql: { + text: 'Microsoft SQL Server does not support OFFSET without and ORDER BY.', + throws: true + }, + oracle: { + text: + 'SELECT "user".* FROM "user" WHERE ("user"."name" = :1) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = :2)) ROWS FETCH NEXT :3 ROWS ONLY', + string: + 'SELECT "user".* FROM "user" WHERE ("user"."name" = \'John\') OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = \'John\')) ROWS FETCH NEXT 1 ROWS ONLY' + }, + values: ['John', 'John', 1] +}); + +// TODO: Should probably have a test case like the one above but including an ORDER BY clause so the mssql case can be tested diff --git a/test/dialects/literal-tests.js b/test/dialects/literal-tests.js deleted file mode 100644 index c31d4271..00000000 --- a/test/dialects/literal-tests.js +++ /dev/null @@ -1,72 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var user = Harness.defineUserTable(); - -Harness.test({ - query: user.select(user.literal('foo'), user.name, user.literal('123').as('onetwothree')), - pg: { - text : 'SELECT foo, "user"."name", 123 AS "onetwothree" FROM "user"', - string: 'SELECT foo, "user"."name", 123 AS "onetwothree" FROM "user"' - }, - sqlite: { - text : 'SELECT foo, "user"."name", 123 AS "onetwothree" FROM "user"', - string: 'SELECT foo, "user"."name", 123 AS "onetwothree" FROM "user"' - }, - mysql: { - text : 'SELECT foo, `user`.`name`, 123 AS `onetwothree` FROM `user`', - string: 'SELECT foo, `user`.`name`, 123 AS `onetwothree` FROM `user`' - }, - oracle: { - text : 'SELECT foo, "user"."name", 123 "onetwothree" FROM "user"', - string: 'SELECT foo, "user"."name", 123 "onetwothree" FROM "user"' - }, - params: [] -}); - - -Harness.test({ - query: user.select().where(user.literal('foo = bar')), - pg: { - text : 'SELECT "user".* FROM "user" WHERE foo = bar', - string: 'SELECT "user".* FROM "user" WHERE foo = bar' - }, - sqlite: { - text : 'SELECT "user".* FROM "user" WHERE foo = bar', - string: 'SELECT "user".* FROM "user" WHERE foo = bar' - }, - mysql: { - text : 'SELECT `user`.* FROM `user` WHERE foo = bar', - string: 'SELECT `user`.* FROM `user` WHERE foo = bar' - }, - oracle: { - text : 'SELECT "user".* FROM "user" WHERE foo = bar', - string: 'SELECT "user".* FROM "user" WHERE foo = bar' - }, - params: [] -}); - -// A real world example: "How many records does page 3 have?" -// This could be less than 10 (the limit) if we are on the last page. -var subquery = user.subQuery('subquery_for_count').select(user.literal(1).as('count_column')).limit(10).offset(20); - -Harness.test({ - query: user.select(subquery.count_column.count()).from(subquery), - pg: { - text : 'SELECT COUNT("subquery_for_count"."count_column") AS "count_column_count" FROM (SELECT 1 AS "count_column" FROM "user" LIMIT 10 OFFSET 20) "subquery_for_count"', - string: 'SELECT COUNT("subquery_for_count"."count_column") AS "count_column_count" FROM (SELECT 1 AS "count_column" FROM "user" LIMIT 10 OFFSET 20) "subquery_for_count"' - }, - sqlite: { - text : 'SELECT COUNT("subquery_for_count"."count_column") AS "count_column_count" FROM (SELECT 1 AS "count_column" FROM "user" LIMIT 10 OFFSET 20) "subquery_for_count"', - string: 'SELECT COUNT("subquery_for_count"."count_column") AS "count_column_count" FROM (SELECT 1 AS "count_column" FROM "user" LIMIT 10 OFFSET 20) "subquery_for_count"' - }, - mysql: { - text : 'SELECT COUNT(`subquery_for_count`.`count_column`) AS `count_column_count` FROM (SELECT 1 AS `count_column` FROM `user` LIMIT 10 OFFSET 20) `subquery_for_count`', - string: 'SELECT COUNT(`subquery_for_count`.`count_column`) AS `count_column_count` FROM (SELECT 1 AS `count_column` FROM `user` LIMIT 10 OFFSET 20) `subquery_for_count`' - }, - oracle: { - text : 'SELECT COUNT("subquery_for_count"."count_column") "count_column_count" FROM (SELECT 1 "count_column" FROM "user" OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY) "subquery_for_count"', - string: 'SELECT COUNT("subquery_for_count"."count_column") "count_column_count" FROM (SELECT 1 "count_column" FROM "user" OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY) "subquery_for_count"' - }, - params: [] -}); diff --git a/test/dialects/literal-tests.ts b/test/dialects/literal-tests.ts new file mode 100644 index 00000000..16c0fce9 --- /dev/null +++ b/test/dialects/literal-tests.ts @@ -0,0 +1,83 @@ +import * as Harness from './support.js'; +import { Sql } from '../../dist/lib.js'; +const user = Harness.defineUserTable(); +const instance = new Sql('postgres'); + +Harness.test({ + query: user.select(instance.literal('foo'), user.name, instance.literal('123').as('onetwothree')), + pg: { + text: 'SELECT foo, "user"."name", 123 AS "onetwothree" FROM "user"', + string: 'SELECT foo, "user"."name", 123 AS "onetwothree" FROM "user"' + }, + sqlite: { + text: 'SELECT foo, "user"."name", 123 AS "onetwothree" FROM "user"', + string: 'SELECT foo, "user"."name", 123 AS "onetwothree" FROM "user"' + }, + mysql: { + text: 'SELECT foo, `user`.`name`, 123 AS `onetwothree` FROM `user`', + string: 'SELECT foo, `user`.`name`, 123 AS `onetwothree` FROM `user`' + }, + oracle: { + text: 'SELECT foo, "user"."name", 123 "onetwothree" FROM "user"', + string: 'SELECT foo, "user"."name", 123 "onetwothree" FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: user.select().where(instance.literal('foo = bar')), + pg: { + text: 'SELECT "user".* FROM "user" WHERE foo = bar', + string: 'SELECT "user".* FROM "user" WHERE foo = bar' + }, + sqlite: { + text: 'SELECT "user".* FROM "user" WHERE foo = bar', + string: 'SELECT "user".* FROM "user" WHERE foo = bar' + }, + mysql: { + text: 'SELECT `user`.* FROM `user` WHERE foo = bar', + string: 'SELECT `user`.* FROM `user` WHERE foo = bar' + }, + oracle: { + text: 'SELECT "user".* FROM "user" WHERE foo = bar', + string: 'SELECT "user".* FROM "user" WHERE foo = bar' + }, + params: [] +}); + +// A real world example: "How many records does page 3 have?" +// This could be less than 10 (the limit) if we are on the last page. +const subquery = user + .subQuery<{ count_column: number }>('subquery_for_count') + .select(instance.literal(1).as('count_column')) + .limit(10) + .offset(20); + +Harness.test({ + query: user.select(subquery.count_column.count()).from(subquery), + pg: { + text: + 'SELECT COUNT("subquery_for_count"."count_column") AS "count_column_count" FROM (SELECT 1 AS "count_column" FROM "user" LIMIT $1 OFFSET $2) "subquery_for_count"', + string: + 'SELECT COUNT("subquery_for_count"."count_column") AS "count_column_count" FROM (SELECT 1 AS "count_column" FROM "user" LIMIT 10 OFFSET 20) "subquery_for_count"' + }, + sqlite: { + text: + 'SELECT COUNT("subquery_for_count"."count_column") AS "count_column_count" FROM (SELECT 1 AS "count_column" FROM "user" LIMIT $1 OFFSET $2) "subquery_for_count"', + string: + 'SELECT COUNT("subquery_for_count"."count_column") AS "count_column_count" FROM (SELECT 1 AS "count_column" FROM "user" LIMIT 10 OFFSET 20) "subquery_for_count"' + }, + mysql: { + text: + 'SELECT COUNT(`subquery_for_count`.`count_column`) AS `count_column_count` FROM (SELECT 1 AS `count_column` FROM `user` LIMIT ? OFFSET ?) `subquery_for_count`', + string: + 'SELECT COUNT(`subquery_for_count`.`count_column`) AS `count_column_count` FROM (SELECT 1 AS `count_column` FROM `user` LIMIT 10 OFFSET 20) `subquery_for_count`' + }, + oracle: { + text: + 'SELECT COUNT("subquery_for_count"."count_column") "count_column_count" FROM (SELECT 1 "count_column" FROM "user" OFFSET :2 ROWS FETCH NEXT :1 ROWS ONLY) "subquery_for_count"', + string: + 'SELECT COUNT("subquery_for_count"."count_column") "count_column_count" FROM (SELECT 1 "count_column" FROM "user" OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY) "subquery_for_count"' + }, + params: [10, 20] +}); diff --git a/test/dialects/matches-test.js b/test/dialects/matches-test.js deleted file mode 100644 index c385641c..00000000 --- a/test/dialects/matches-test.js +++ /dev/null @@ -1,49 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var post = Harness.definePostTable(); -var customerAlias = Harness.defineCustomerAliasTable(); -var sql = require(__dirname + '/../../lib').setDialect('postgres'); - -//Postgres needs the to_tsquery function to use with @@ operator -Harness.test({ - query: post.select(post.star()).where(post.content.match(sql.functions.TO_TSQUERY('hello'))), - pg: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."content" @@ TO_TSQUERY($1))', - string: 'SELECT "post".* FROM "post" WHERE ("post"."content" @@ TO_TSQUERY(\'hello\'))' - }, - params: ['hello'] -}); - - -Harness.test({ - query: post.select(post.star()).where(post.content.match('hello')), - sqlite: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."content" MATCH $1)', - string: 'SELECT "post".* FROM "post" WHERE ("post"."content" MATCH \'hello\')' - }, - mysql: { - text : 'SELECT `post`.* FROM `post` WHERE (MATCH `post`.`content` AGAINST ?)', - string: 'SELECT `post`.* FROM `post` WHERE (MATCH `post`.`content` AGAINST \'hello\')' - }, - mssql: { - text : 'SELECT [post].* FROM [post] WHERE (CONTAINS ([post].[content], @1))', - string: 'SELECT [post].* FROM [post] WHERE (CONTAINS ([post].[content], \'hello\'))' - }, - oracle: { - text : 'SELECT "post".* FROM "post" WHERE (INSTR ("post"."content", :1) > 0)', - string: 'SELECT "post".* FROM "post" WHERE (INSTR ("post"."content", \'hello\') > 0)' - }, - params: ['hello'] -}); - -//matches, ordered by best rank first -Harness.test({ - query: post.select(post.id, sql.functions.TS_RANK_CD(post.content, sql.functions.TO_TSQUERY('hello')).as('rank')). - where(post.content.match(sql.functions.TO_TSQUERY('hello'))).order(sql.functions.TS_RANK_CD(post.content, sql.functions.TO_TSQUERY('hello')).descending()), - pg: { - text : 'SELECT "post"."id", TS_RANK_CD("post"."content", TO_TSQUERY($1)) AS "rank" FROM "post" WHERE ("post"."content" @@ TO_TSQUERY($2)) ORDER BY TS_RANK_CD("post"."content", TO_TSQUERY($3)) DESC', - string: 'SELECT "post"."id", TS_RANK_CD("post"."content", TO_TSQUERY(\'hello\')) AS "rank" FROM "post" WHERE ("post"."content" @@ TO_TSQUERY(\'hello\')) ORDER BY TS_RANK_CD("post"."content", TO_TSQUERY(\'hello\')) DESC' - }, - params: ['hello','hello','hello'] -}); diff --git a/test/dialects/matches-test.ts b/test/dialects/matches-test.ts new file mode 100644 index 00000000..5ea5793a --- /dev/null +++ b/test/dialects/matches-test.ts @@ -0,0 +1,50 @@ +import * as Harness from './support.js'; +import { Sql } from '../../dist/lib.js'; +const post = Harness.definePostTable(); +const instance = new Sql('postgres'); + +// Postgres needs the to_tsquery function to use with @@ operator +Harness.test({ + query: post.select(post.star()).where(post.content.match(instance.functions.TO_TSQUERY('hello'))), + pg: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."content" @@ TO_TSQUERY($1))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."content" @@ TO_TSQUERY(\'hello\'))' + }, + params: ['hello'] +}); + +Harness.test({ + query: post.select(post.star()).where(post.content.match('hello')), + sqlite: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."content" MATCH $1)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."content" MATCH \'hello\')' + }, + mysql: { + text: 'SELECT `post`.* FROM `post` WHERE (MATCH `post`.`content` AGAINST ?)', + string: "SELECT `post`.* FROM `post` WHERE (MATCH `post`.`content` AGAINST 'hello')" + }, + mssql: { + text: 'SELECT [post].* FROM [post] WHERE (CONTAINS ([post].[content], @1))', + string: "SELECT [post].* FROM [post] WHERE (CONTAINS ([post].[content], 'hello'))" + }, + oracle: { + text: 'SELECT "post".* FROM "post" WHERE (INSTR ("post"."content", :1) > 0)', + string: 'SELECT "post".* FROM "post" WHERE (INSTR ("post"."content", \'hello\') > 0)' + }, + params: ['hello'] +}); + +// matches, ordered by best rank first +Harness.test({ + query: post + .select(post.id, instance.functions.TS_RANK_CD(post.content, instance.functions.TO_TSQUERY('hello')).as('rank')) + .where(post.content.match(instance.functions.TO_TSQUERY('hello'))) + .order(instance.functions.TS_RANK_CD(post.content, instance.functions.TO_TSQUERY('hello')).descending()), + pg: { + text: + 'SELECT "post"."id", TS_RANK_CD("post"."content", TO_TSQUERY($1)) AS "rank" FROM "post" WHERE ("post"."content" @@ TO_TSQUERY($2)) ORDER BY TS_RANK_CD("post"."content", TO_TSQUERY($3)) DESC', + string: + 'SELECT "post"."id", TS_RANK_CD("post"."content", TO_TSQUERY(\'hello\')) AS "rank" FROM "post" WHERE ("post"."content" @@ TO_TSQUERY(\'hello\')) ORDER BY TS_RANK_CD("post"."content", TO_TSQUERY(\'hello\')) DESC' + }, + params: ['hello', 'hello', 'hello'] +}); diff --git a/test/dialects/namespace-tests.js b/test/dialects/namespace-tests.js deleted file mode 100644 index 5f6b4a56..00000000 --- a/test/dialects/namespace-tests.js +++ /dev/null @@ -1,146 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var Table = require('../../lib/table'); -var user = Harness.defineUserTable(); -var post = Harness.definePostTable(); - -var u = user.as('u'); -Harness.test({ - query: u.select(u.name).from(u), - pg: { - text : 'SELECT "u"."name" FROM "user" AS "u"', - string: 'SELECT "u"."name" FROM "user" AS "u"' - }, - sqlite: { - text : 'SELECT "u"."name" FROM "user" AS "u"', - string: 'SELECT "u"."name" FROM "user" AS "u"' - }, - mysql: { - text : 'SELECT `u`.`name` FROM `user` AS `u`', - string: 'SELECT `u`.`name` FROM `user` AS `u`' - }, - mssql: { - text : 'SELECT [u].[name] FROM [user] AS [u]', - string: 'SELECT [u].[name] FROM [user] AS [u]' - }, - oracle: { - text : 'SELECT "u"."name" FROM "user" "u"', - string: 'SELECT "u"."name" FROM "user" "u"' - }, - params: [] -}); - -Harness.test({ - query: u.select(u.star()).from(u), - pg: { - text : 'SELECT "u".* FROM "user" AS "u"', - string: 'SELECT "u".* FROM "user" AS "u"' - }, - sqlite: { - text : 'SELECT "u".* FROM "user" AS "u"', - string: 'SELECT "u".* FROM "user" AS "u"' - }, - mysql: { - text : 'SELECT `u`.* FROM `user` AS `u`', - string: 'SELECT `u`.* FROM `user` AS `u`' - }, - mssql: { - text : 'SELECT [u].* FROM [user] AS [u]', - string: 'SELECT [u].* FROM [user] AS [u]' - }, - oracle: { - text : 'SELECT "u".* FROM "user" "u"', - string: 'SELECT "u".* FROM "user" "u"' - }, - params: [] -}); - -var p = post.as('p'); -Harness.test({ - query: u.select(u.name).from(u.join(p).on(u.id.equals(p.userId).and(p.id.equals(3)))), - pg: { - text : 'SELECT "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."id" = $1))', - string: 'SELECT "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."id" = 3))' - }, - sqlite: { - text : 'SELECT "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."id" = $1))', - string: 'SELECT "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."id" = 3))' - }, - mysql: { - text : 'SELECT `u`.`name` FROM `user` AS `u` INNER JOIN `post` AS `p` ON ((`u`.`id` = `p`.`userId`) AND (`p`.`id` = ?))', - string: 'SELECT `u`.`name` FROM `user` AS `u` INNER JOIN `post` AS `p` ON ((`u`.`id` = `p`.`userId`) AND (`p`.`id` = 3))' - }, - mssql: { - text : 'SELECT [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[id] = @1))', - string: 'SELECT [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[id] = 3))' - }, - oracle: { - text : 'SELECT "u"."name" FROM "user" "u" INNER JOIN "post" "p" ON (("u"."id" = "p"."userId") AND ("p"."id" = :1))', - string: 'SELECT "u"."name" FROM "user" "u" INNER JOIN "post" "p" ON (("u"."id" = "p"."userId") AND ("p"."id" = 3))' - }, - params: [3] -}); - -Harness.test({ - query: u.select(p.content, u.name).from(u.join(p).on(u.id.equals(p.userId).and(p.content.isNotNull()))), - pg: { - text : 'SELECT "p"."content", "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."content" IS NOT NULL))', - string: 'SELECT "p"."content", "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."content" IS NOT NULL))' - }, - sqlite: { - text : 'SELECT "p"."content", "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."content" IS NOT NULL))', - string: 'SELECT "p"."content", "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."content" IS NOT NULL))' - }, - mysql: { - text : 'SELECT `p`.`content`, `u`.`name` FROM `user` AS `u` INNER JOIN `post` AS `p` ON ((`u`.`id` = `p`.`userId`) AND (`p`.`content` IS NOT NULL))', - string: 'SELECT `p`.`content`, `u`.`name` FROM `user` AS `u` INNER JOIN `post` AS `p` ON ((`u`.`id` = `p`.`userId`) AND (`p`.`content` IS NOT NULL))' - }, - mssql: { - text : 'SELECT [p].[content], [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[content] IS NOT NULL))', - string: 'SELECT [p].[content], [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[content] IS NOT NULL))' - }, - oracle: { - text : 'SELECT "p"."content", "u"."name" FROM "user" "u" INNER JOIN "post" "p" ON (("u"."id" = "p"."userId") AND ("p"."content" IS NOT NULL))', - string: 'SELECT "p"."content", "u"."name" FROM "user" "u" INNER JOIN "post" "p" ON (("u"."id" = "p"."userId") AND ("p"."content" IS NOT NULL))' - }, - params: [] -}); - -// the quote property isn't implemented for columns, so all columns are quoted in generated queries -var comment = Table.define({ - name: 'comment', - columns: [{ - name: 'text', - quote: true - }, { - name: 'userId', - quote: false - } - ] -}); - -Harness.test({ - query: comment.select(comment.text, comment.userId), - pg: { - text : 'SELECT "comment"."text", "comment"."userId" FROM "comment"', - string: 'SELECT "comment"."text", "comment"."userId" FROM "comment"' - }, - sqlite: { - text : 'SELECT "comment"."text", "comment"."userId" FROM "comment"', - string: 'SELECT "comment"."text", "comment"."userId" FROM "comment"' - }, - mysql: { - text : 'SELECT `comment`.`text`, `comment`.`userId` FROM `comment`', - string: 'SELECT `comment`.`text`, `comment`.`userId` FROM `comment`' - }, - mssql: { - text : 'SELECT [comment].[text], [comment].[userId] FROM [comment]', - string: 'SELECT [comment].[text], [comment].[userId] FROM [comment]' - }, - orcle: { - text : 'SELECT "comment"."text", "comment"."userId" FROM "comment"', - string: 'SELECT "comment"."text", "comment"."userId" FROM "comment"' - }, - params: [] -}); diff --git a/test/dialects/namespace-tests.ts b/test/dialects/namespace-tests.ts new file mode 100644 index 00000000..87631c63 --- /dev/null +++ b/test/dialects/namespace-tests.ts @@ -0,0 +1,154 @@ +import * as Harness from './support.js'; +import { Table } from '../../dist/lib.js'; +const user = Harness.defineUserTable(); +const post = Harness.definePostTable(); + +const u = user.as('u'); +Harness.test({ + query: u.select(u.name).from(u), + pg: { + text: 'SELECT "u"."name" FROM "user" AS "u"', + string: 'SELECT "u"."name" FROM "user" AS "u"' + }, + sqlite: { + text: 'SELECT "u"."name" FROM "user" AS "u"', + string: 'SELECT "u"."name" FROM "user" AS "u"' + }, + mysql: { + text: 'SELECT `u`.`name` FROM `user` AS `u`', + string: 'SELECT `u`.`name` FROM `user` AS `u`' + }, + mssql: { + text: 'SELECT [u].[name] FROM [user] AS [u]', + string: 'SELECT [u].[name] FROM [user] AS [u]' + }, + oracle: { + text: 'SELECT "u"."name" FROM "user" "u"', + string: 'SELECT "u"."name" FROM "user" "u"' + }, + params: [] +}); + +Harness.test({ + query: u.select(u.star()).from(u), + pg: { + text: 'SELECT "u".* FROM "user" AS "u"', + string: 'SELECT "u".* FROM "user" AS "u"' + }, + sqlite: { + text: 'SELECT "u".* FROM "user" AS "u"', + string: 'SELECT "u".* FROM "user" AS "u"' + }, + mysql: { + text: 'SELECT `u`.* FROM `user` AS `u`', + string: 'SELECT `u`.* FROM `user` AS `u`' + }, + mssql: { + text: 'SELECT [u].* FROM [user] AS [u]', + string: 'SELECT [u].* FROM [user] AS [u]' + }, + oracle: { + text: 'SELECT "u".* FROM "user" "u"', + string: 'SELECT "u".* FROM "user" "u"' + }, + params: [] +}); + +const p = post.as('p'); +Harness.test({ + query: u.select(u.name).from(u.join(p).on(u.id.equals(p.userId).and(p.id.equals(3)))), + pg: { + text: 'SELECT "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."id" = $1))', + string: 'SELECT "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."id" = 3))' + }, + sqlite: { + text: 'SELECT "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."id" = $1))', + string: 'SELECT "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."id" = 3))' + }, + mysql: { + text: 'SELECT `u`.`name` FROM `user` AS `u` INNER JOIN `post` AS `p` ON ((`u`.`id` = `p`.`userId`) AND (`p`.`id` = ?))', + string: 'SELECT `u`.`name` FROM `user` AS `u` INNER JOIN `post` AS `p` ON ((`u`.`id` = `p`.`userId`) AND (`p`.`id` = 3))' + }, + mssql: { + text: 'SELECT [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[id] = @1))', + string: 'SELECT [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[id] = 3))' + }, + oracle: { + text: 'SELECT "u"."name" FROM "user" "u" INNER JOIN "post" "p" ON (("u"."id" = "p"."userId") AND ("p"."id" = :1))', + string: 'SELECT "u"."name" FROM "user" "u" INNER JOIN "post" "p" ON (("u"."id" = "p"."userId") AND ("p"."id" = 3))' + }, + params: [3] +}); + +Harness.test({ + query: u.select(p.content, u.name).from(u.join(p).on(u.id.equals(p.userId).and(p.content.isNotNull()))), + pg: { + text: + 'SELECT "p"."content", "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."content" IS NOT NULL))', + string: + 'SELECT "p"."content", "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."content" IS NOT NULL))' + }, + sqlite: { + text: + 'SELECT "p"."content", "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."content" IS NOT NULL))', + string: + 'SELECT "p"."content", "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."content" IS NOT NULL))' + }, + mysql: { + text: + 'SELECT `p`.`content`, `u`.`name` FROM `user` AS `u` INNER JOIN `post` AS `p` ON ((`u`.`id` = `p`.`userId`) AND (`p`.`content` IS NOT NULL))', + string: + 'SELECT `p`.`content`, `u`.`name` FROM `user` AS `u` INNER JOIN `post` AS `p` ON ((`u`.`id` = `p`.`userId`) AND (`p`.`content` IS NOT NULL))' + }, + mssql: { + text: + 'SELECT [p].[content], [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[content] IS NOT NULL))', + string: + 'SELECT [p].[content], [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[content] IS NOT NULL))' + }, + oracle: { + text: + 'SELECT "p"."content", "u"."name" FROM "user" "u" INNER JOIN "post" "p" ON (("u"."id" = "p"."userId") AND ("p"."content" IS NOT NULL))', + string: + 'SELECT "p"."content", "u"."name" FROM "user" "u" INNER JOIN "post" "p" ON (("u"."id" = "p"."userId") AND ("p"."content" IS NOT NULL))' + }, + params: [] +}); + +// the quote property isn't implemented for columns, so all columns are quoted in generated queries +const comment = Table.define<{ text: string; userId: number }>({ + name: 'comment', + columns: [ + { + name: 'text' + }, + { + name: 'userId' + } + ] +}); + +Harness.test({ + query: comment.select(comment.text, comment.userId), + pg: { + text: 'SELECT "comment"."text", "comment"."userId" FROM "comment"', + string: 'SELECT "comment"."text", "comment"."userId" FROM "comment"' + }, + sqlite: { + text: 'SELECT "comment"."text", "comment"."userId" FROM "comment"', + string: 'SELECT "comment"."text", "comment"."userId" FROM "comment"' + }, + mysql: { + text: 'SELECT `comment`.`text`, `comment`.`userId` FROM `comment`', + string: 'SELECT `comment`.`text`, `comment`.`userId` FROM `comment`' + }, + mssql: { + text: 'SELECT [comment].[text], [comment].[userId] FROM [comment]', + string: 'SELECT [comment].[text], [comment].[userId] FROM [comment]' + }, + orcle: { + text: 'SELECT "comment"."text", "comment"."userId" FROM "comment"', + string: 'SELECT "comment"."text", "comment"."userId" FROM "comment"' + }, + params: [] +}); diff --git a/test/dialects/not-in-clause-tests.js b/test/dialects/not-in-clause-tests.js deleted file mode 100644 index 11647fee..00000000 --- a/test/dialects/not-in-clause-tests.js +++ /dev/null @@ -1,179 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var post = Harness.definePostTable(); - -Harness.test({ - query: post.select(post.star()).where(post.id.notIn([])), - pg: { - text : 'SELECT "post".* FROM "post" WHERE (1=1)', - string: 'SELECT "post".* FROM "post" WHERE (1=1)' - }, - sqlite: { - text : 'SELECT "post".* FROM "post" WHERE (1=1)', - string: 'SELECT "post".* FROM "post" WHERE (1=1)' - }, - mysql: { - text : 'SELECT `post`.* FROM `post` WHERE (1=1)', - string: 'SELECT `post`.* FROM `post` WHERE (1=1)' - }, - mssql: { - text : 'SELECT [post].* FROM [post] WHERE (1=1)', - string: 'SELECT [post].* FROM [post] WHERE (1=1)' - }, - oracle: { - text : 'SELECT "post".* FROM "post" WHERE (1=1)', - string: 'SELECT "post".* FROM "post" WHERE (1=1)' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.star()).where(post.id.notIn([1])), - pg: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN ($1))', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (1))' - }, - sqlite: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN ($1))', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (1))' - }, - mysql: { - text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` NOT IN (?))', - string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` NOT IN (1))' - }, - mssql: { - text : 'SELECT [post].* FROM [post] WHERE ([post].[id] NOT IN (@1))', - string: 'SELECT [post].* FROM [post] WHERE ([post].[id] NOT IN (1))' - }, - oracle: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (:1))', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (1))' - }, - params: [1] -}); - -Harness.test({ - query: post.select(post.star()).where(post.id.notIn([null])), - pg: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)' - }, - sqlite: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)' - }, - mysql: { - text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NOT NULL)', - string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NOT NULL)' - }, - mssql: { - text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NOT NULL)', - string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NOT NULL)' - }, - oracle: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.star()).where(post.id.notIn([1, 2])), - pg: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN ($1, $2))', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (1, 2))' - }, - sqlite: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN ($1, $2))', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (1, 2))' - }, - mysql: { - text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` NOT IN (?, ?))', - string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` NOT IN (1, 2))' - }, - mssql: { - text : 'SELECT [post].* FROM [post] WHERE ([post].[id] NOT IN (@1, @2))', - string: 'SELECT [post].* FROM [post] WHERE ([post].[id] NOT IN (1, 2))' - }, - oracle: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (:1, :2))', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (1, 2))' - }, - params: [1, 2] -}); - -Harness.test({ - query: post.select(post.star()).where(post.id.notIn([null, null])), - pg: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)' - }, - sqlite: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)' - }, - mysql: { - text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NOT NULL)', - string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NOT NULL)' - }, - mssql: { - text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NOT NULL)', - string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NOT NULL)' - }, - oracle: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)', - string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.star()).where(post.id.notIn([1, null, 2])), - pg: { - text : 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN ($1, $2) OR "post"."id" IS NULL))', - string: 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN (1, 2) OR "post"."id" IS NULL))' - }, - sqlite: { - text : 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN ($1, $2) OR "post"."id" IS NULL))', - string: 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN (1, 2) OR "post"."id" IS NULL))' - }, - mysql: { - text : 'SELECT `post`.* FROM `post` WHERE (NOT (`post`.`id` IN (?, ?) OR `post`.`id` IS NULL))', - string: 'SELECT `post`.* FROM `post` WHERE (NOT (`post`.`id` IN (1, 2) OR `post`.`id` IS NULL))' - }, - mssql: { - text : 'SELECT [post].* FROM [post] WHERE (NOT ([post].[id] IN (@1, @2) OR [post].[id] IS NULL))', - string: 'SELECT [post].* FROM [post] WHERE (NOT ([post].[id] IN (1, 2) OR [post].[id] IS NULL))' - }, - oracle: { - text : 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN (:1, :2) OR "post"."id" IS NULL))', - string: 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN (1, 2) OR "post"."id" IS NULL))' - }, - params: [1, 2] -}); - -Harness.test({ - query: post.select(post.star()).where(post.id.notIn([1, null, 2, null])), - pg: { - text : 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN ($1, $2) OR "post"."id" IS NULL))', - string: 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN (1, 2) OR "post"."id" IS NULL))' - }, - sqlite: { - text : 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN ($1, $2) OR "post"."id" IS NULL))', - string: 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN (1, 2) OR "post"."id" IS NULL))' - }, - mysql: { - text : 'SELECT `post`.* FROM `post` WHERE (NOT (`post`.`id` IN (?, ?) OR `post`.`id` IS NULL))', - string: 'SELECT `post`.* FROM `post` WHERE (NOT (`post`.`id` IN (1, 2) OR `post`.`id` IS NULL))' - }, - mssql: { - text : 'SELECT [post].* FROM [post] WHERE (NOT ([post].[id] IN (@1, @2) OR [post].[id] IS NULL))', - string: 'SELECT [post].* FROM [post] WHERE (NOT ([post].[id] IN (1, 2) OR [post].[id] IS NULL))' - }, - oracle: { - text : 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN (:1, :2) OR "post"."id" IS NULL))', - string: 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN (1, 2) OR "post"."id" IS NULL))' - }, - params: [1, 2] -}); diff --git a/test/dialects/not-in-clause-tests.ts b/test/dialects/not-in-clause-tests.ts new file mode 100644 index 00000000..b933ab95 --- /dev/null +++ b/test/dialects/not-in-clause-tests.ts @@ -0,0 +1,177 @@ +import * as Harness from './support.js'; +const post = Harness.definePostTable(); + +Harness.test({ + query: post.select(post.star()).where(post.id.notIn([])), + pg: { + text: 'SELECT "post".* FROM "post" WHERE (1=1)', + string: 'SELECT "post".* FROM "post" WHERE (1=1)' + }, + sqlite: { + text: 'SELECT "post".* FROM "post" WHERE (1=1)', + string: 'SELECT "post".* FROM "post" WHERE (1=1)' + }, + mysql: { + text: 'SELECT `post`.* FROM `post` WHERE (1=1)', + string: 'SELECT `post`.* FROM `post` WHERE (1=1)' + }, + mssql: { + text: 'SELECT [post].* FROM [post] WHERE (1=1)', + string: 'SELECT [post].* FROM [post] WHERE (1=1)' + }, + oracle: { + text: 'SELECT "post".* FROM "post" WHERE (1=1)', + string: 'SELECT "post".* FROM "post" WHERE (1=1)' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.notIn([1])), + pg: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN ($1))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (1))' + }, + sqlite: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN ($1))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (1))' + }, + mysql: { + text: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` NOT IN (?))', + string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` NOT IN (1))' + }, + mssql: { + text: 'SELECT [post].* FROM [post] WHERE ([post].[id] NOT IN (@1))', + string: 'SELECT [post].* FROM [post] WHERE ([post].[id] NOT IN (1))' + }, + oracle: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (:1))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (1))' + }, + params: [1] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.notIn([null])), + pg: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)' + }, + sqlite: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)' + }, + mysql: { + text: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NOT NULL)', + string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NOT NULL)' + }, + mssql: { + text: 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NOT NULL)', + string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NOT NULL)' + }, + oracle: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.notIn([1, 2])), + pg: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN ($1, $2))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (1, 2))' + }, + sqlite: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN ($1, $2))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (1, 2))' + }, + mysql: { + text: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` NOT IN (?, ?))', + string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` NOT IN (1, 2))' + }, + mssql: { + text: 'SELECT [post].* FROM [post] WHERE ([post].[id] NOT IN (@1, @2))', + string: 'SELECT [post].* FROM [post] WHERE ([post].[id] NOT IN (1, 2))' + }, + oracle: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (:1, :2))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (1, 2))' + }, + params: [1, 2] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.notIn([null, null])), + pg: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)' + }, + sqlite: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)' + }, + mysql: { + text: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NOT NULL)', + string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NOT NULL)' + }, + mssql: { + text: 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NOT NULL)', + string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NOT NULL)' + }, + oracle: { + text: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.notIn([1, null, 2])), + pg: { + text: 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN ($1, $2) OR "post"."id" IS NULL))', + string: 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN (1, 2) OR "post"."id" IS NULL))' + }, + sqlite: { + text: 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN ($1, $2) OR "post"."id" IS NULL))', + string: 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN (1, 2) OR "post"."id" IS NULL))' + }, + mysql: { + text: 'SELECT `post`.* FROM `post` WHERE (NOT (`post`.`id` IN (?, ?) OR `post`.`id` IS NULL))', + string: 'SELECT `post`.* FROM `post` WHERE (NOT (`post`.`id` IN (1, 2) OR `post`.`id` IS NULL))' + }, + mssql: { + text: 'SELECT [post].* FROM [post] WHERE (NOT ([post].[id] IN (@1, @2) OR [post].[id] IS NULL))', + string: 'SELECT [post].* FROM [post] WHERE (NOT ([post].[id] IN (1, 2) OR [post].[id] IS NULL))' + }, + oracle: { + text: 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN (:1, :2) OR "post"."id" IS NULL))', + string: 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN (1, 2) OR "post"."id" IS NULL))' + }, + params: [1, 2] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.notIn([1, null, 2, null])), + pg: { + text: 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN ($1, $2) OR "post"."id" IS NULL))', + string: 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN (1, 2) OR "post"."id" IS NULL))' + }, + sqlite: { + text: 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN ($1, $2) OR "post"."id" IS NULL))', + string: 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN (1, 2) OR "post"."id" IS NULL))' + }, + mysql: { + text: 'SELECT `post`.* FROM `post` WHERE (NOT (`post`.`id` IN (?, ?) OR `post`.`id` IS NULL))', + string: 'SELECT `post`.* FROM `post` WHERE (NOT (`post`.`id` IN (1, 2) OR `post`.`id` IS NULL))' + }, + mssql: { + text: 'SELECT [post].* FROM [post] WHERE (NOT ([post].[id] IN (@1, @2) OR [post].[id] IS NULL))', + string: 'SELECT [post].* FROM [post] WHERE (NOT ([post].[id] IN (1, 2) OR [post].[id] IS NULL))' + }, + oracle: { + text: 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN (:1, :2) OR "post"."id" IS NULL))', + string: 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN (1, 2) OR "post"."id" IS NULL))' + }, + params: [1, 2] +}); diff --git a/test/dialects/order-tests.js b/test/dialects/order-tests.js deleted file mode 100644 index a0813d8e..00000000 --- a/test/dialects/order-tests.js +++ /dev/null @@ -1,365 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var post = Harness.definePostTable(); -var sql = require('../../lib'); - -Harness.test({ - query: post.select(post.content).order(post.content), - pg: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' - }, - sqlite: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' - }, - mysql: { - text : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`', - string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`' - }, - mssql: { - text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content]', - string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content]' - }, - oracle: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.content).order(post.content, post.userId.descending), - pg: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' - }, - sqlite: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' - }, - mysql: { - text : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC', - string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' - }, - mssql: { - text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC', - string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC' - }, - oracle: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.content).order(post.content.asc, post.userId.desc), - pg: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' - }, - sqlite: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' - }, - mysql: { - text : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC', - string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' - }, - mssql: { - text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC', - string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC' - }, - oracle: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.content).order([post.content, post.userId.descending]), - pg: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' - }, - sqlite: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' - }, - mysql: { - text : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC', - string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' - }, - mssql: { - text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC', - string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC' - }, - oracle: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.content).order(post.content).order(post.userId.descending), - pg: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' - }, - sqlite: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' - }, - mysql: { - text : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC', - string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' - }, - mssql: { - text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC', - string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC' - }, - oracle: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.content.isNull()).order(post.content.isNull()), - pg: { - text : 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)', - string: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)' - }, - sqlite: { - text : 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)', - string: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)' - }, - mysql: { - text : 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL)', - string: 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL)' - }, - mssql: { - text : 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL)', - string: 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL)' - }, - oracle: { - text : 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)', - string: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.content.isNull()).order(post.content.isNull().descending()), - pg: { - text : 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL) DESC', - string: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL) DESC' - }, - sqlite: { - text : 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL) DESC', - string: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL) DESC' - }, - mysql: { - text : 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL) DESC', - string: 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL) DESC' - }, - mssql: { - text : 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL) DESC', - string: 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL) DESC' - }, - oracle: { - text : 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL) DESC', - string: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL) DESC' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.content.isNull()).order(post.content.isNull()), - pg: { - text : 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)', - string: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)' - }, - sqlite: { - text : 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)', - string: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)' - }, - mysql: { - text : 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL)', - string: 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL)' - }, - mssql: { - text : 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL)', - string: 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL)' - }, - oracle: { - text : 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)', - string: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)' - }, - params: [] -}); - -Harness.test({ - query: post.select(sql.functions.RTRIM(post.content)).order(sql.functions.RTRIM(post.content)), - pg: { - text : 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content")', - string: 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content")' - }, - sqlite: { - text : 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content")', - string: 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content")' - }, - mysql: { - text : 'SELECT RTRIM(`post`.`content`) FROM `post` ORDER BY RTRIM(`post`.`content`)', - string: 'SELECT RTRIM(`post`.`content`) FROM `post` ORDER BY RTRIM(`post`.`content`)' - }, - mssql: { - text : 'SELECT RTRIM([post].[content]) FROM [post] ORDER BY RTRIM([post].[content])', - string: 'SELECT RTRIM([post].[content]) FROM [post] ORDER BY RTRIM([post].[content])' - }, - oracle: { - text : 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content")', - string: 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content")' - }, - params: [] -}); - -Harness.test({ - query: post.select(sql.functions.RTRIM(post.content)).order(sql.functions.RTRIM(post.content).descending()), - pg: { - text : 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content") DESC', - string: 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content") DESC' - }, - sqlite: { - text : 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content") DESC', - string: 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content") DESC' - }, - mysql: { - text : 'SELECT RTRIM(`post`.`content`) FROM `post` ORDER BY RTRIM(`post`.`content`) DESC', - string: 'SELECT RTRIM(`post`.`content`) FROM `post` ORDER BY RTRIM(`post`.`content`) DESC' - }, - mssql: { - text : 'SELECT RTRIM([post].[content]) FROM [post] ORDER BY RTRIM([post].[content]) DESC', - string: 'SELECT RTRIM([post].[content]) FROM [post] ORDER BY RTRIM([post].[content]) DESC' - }, - oracle: { - text : 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content") DESC', - string: 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content") DESC' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.content).order(post.content.descending), - pg: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" DESC NULLS LAST', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" DESC NULLS LAST', - config: { - nullOrder: "last" - } - }, - sqlite: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" DESC', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" DESC' - }, - mysql: { - text : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content` DESC', - string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content` DESC' - }, - mssql: { - text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content] DESC', - string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content] DESC' - }, - oracle: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" DESC', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" DESC' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.content).order(post.content), - pg: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" NULLS LAST', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" NULLS LAST', - config: { - nullOrder: "last" - } - }, - sqlite: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' - }, - mysql: { - text : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`', - string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`' - }, - mssql: { - text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content]', - string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content]' - }, - oracle: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.content).order(post.content.asc), - pg: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" NULLS FIRST', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" NULLS FIRST', - config: { - nullOrder: "first" - } - }, - sqlite: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' - }, - mysql: { - text : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`', - string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`' - }, - mssql: { - text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content]', - string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content]' - }, - oracle: { - text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', - string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.content).order([]), - pg: { - text : 'SELECT "post"."content" FROM "post"', - string: 'SELECT "post"."content" FROM "post"' - }, - sqlite: { - text : 'SELECT "post"."content" FROM "post"', - string: 'SELECT "post"."content" FROM "post"' - }, - mysql: { - text : 'SELECT `post`.`content` FROM `post`', - string: 'SELECT `post`.`content` FROM `post`' - }, - mssql: { - text : 'SELECT [post].[content] FROM [post]', - string: 'SELECT [post].[content] FROM [post]' - }, - oracle: { - text : 'SELECT "post"."content" FROM "post"', - string: 'SELECT "post"."content" FROM "post"' - }, - params: [] -}); - diff --git a/test/dialects/order-tests.ts b/test/dialects/order-tests.ts new file mode 100644 index 00000000..98035820 --- /dev/null +++ b/test/dialects/order-tests.ts @@ -0,0 +1,366 @@ +import * as Harness from './support.js'; +import { Sql } from '../../dist/lib.js'; +const post = Harness.definePostTable(); +const instance = new Sql('postgres'); + +Harness.test({ + query: post.select(post.content).order(post.content), + pg: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' + }, + sqlite: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' + }, + mysql: { + text: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`', + string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`' + }, + mssql: { + text: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content]', + string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content]' + }, + oracle: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.content).order(post.content, post.userId.desc()), + pg: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' + }, + sqlite: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' + }, + mysql: { + text: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC', + string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' + }, + mssql: { + text: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC', + string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC' + }, + oracle: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.content).order(post.content.asc(), post.userId.desc()), + pg: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' + }, + sqlite: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' + }, + mysql: { + text: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC', + string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' + }, + mssql: { + text: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC', + string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC' + }, + oracle: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.content).order([post.content, post.userId.desc()]), + pg: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' + }, + sqlite: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' + }, + mysql: { + text: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC', + string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' + }, + mssql: { + text: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC', + string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC' + }, + oracle: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' + }, + params: [] +}); + +Harness.test({ + query: post + .select(post.content) + .order(post.content) + .order(post.userId.desc()), + pg: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' + }, + sqlite: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' + }, + mysql: { + text: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC', + string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' + }, + mssql: { + text: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC', + string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC' + }, + oracle: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.content.isNull()).order(post.content.isNull()), + pg: { + text: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)', + string: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)' + }, + sqlite: { + text: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)', + string: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)' + }, + mysql: { + text: 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL)', + string: 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL)' + }, + mssql: { + text: 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL)', + string: 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL)' + }, + oracle: { + text: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)', + string: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.content.isNull()).order(post.content.isNull().descending()), + pg: { + text: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL) DESC', + string: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL) DESC' + }, + sqlite: { + text: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL) DESC', + string: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL) DESC' + }, + mysql: { + text: 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL) DESC', + string: 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL) DESC' + }, + mssql: { + text: 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL) DESC', + string: 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL) DESC' + }, + oracle: { + text: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL) DESC', + string: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL) DESC' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.content.isNull()).order(post.content.isNull()), + pg: { + text: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)', + string: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)' + }, + sqlite: { + text: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)', + string: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)' + }, + mysql: { + text: 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL)', + string: 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL)' + }, + mssql: { + text: 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL)', + string: 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL)' + }, + oracle: { + text: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)', + string: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)' + }, + params: [] +}); + +Harness.test({ + query: post.select(instance.functions.RTRIM(post.content)).order(instance.functions.RTRIM(post.content)), + pg: { + text: 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content")', + string: 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content")' + }, + sqlite: { + text: 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content")', + string: 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content")' + }, + mysql: { + text: 'SELECT RTRIM(`post`.`content`) FROM `post` ORDER BY RTRIM(`post`.`content`)', + string: 'SELECT RTRIM(`post`.`content`) FROM `post` ORDER BY RTRIM(`post`.`content`)' + }, + mssql: { + text: 'SELECT RTRIM([post].[content]) FROM [post] ORDER BY RTRIM([post].[content])', + string: 'SELECT RTRIM([post].[content]) FROM [post] ORDER BY RTRIM([post].[content])' + }, + oracle: { + text: 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content")', + string: 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content")' + }, + params: [] +}); + +Harness.test({ + query: post.select(instance.functions.RTRIM(post.content)).order(instance.functions.RTRIM(post.content).descending()), + pg: { + text: 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content") DESC', + string: 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content") DESC' + }, + sqlite: { + text: 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content") DESC', + string: 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content") DESC' + }, + mysql: { + text: 'SELECT RTRIM(`post`.`content`) FROM `post` ORDER BY RTRIM(`post`.`content`) DESC', + string: 'SELECT RTRIM(`post`.`content`) FROM `post` ORDER BY RTRIM(`post`.`content`) DESC' + }, + mssql: { + text: 'SELECT RTRIM([post].[content]) FROM [post] ORDER BY RTRIM([post].[content]) DESC', + string: 'SELECT RTRIM([post].[content]) FROM [post] ORDER BY RTRIM([post].[content]) DESC' + }, + oracle: { + text: 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content") DESC', + string: 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content") DESC' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.content).order(post.content.desc()), + pg: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" DESC NULLS LAST', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" DESC NULLS LAST', + config: { + nullOrder: 'last' + } + }, + sqlite: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" DESC', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" DESC' + }, + mysql: { + text: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content` DESC', + string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content` DESC' + }, + mssql: { + text: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content] DESC', + string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content] DESC' + }, + oracle: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" DESC', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" DESC' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.content).order(post.content), + pg: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" NULLS LAST', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" NULLS LAST', + config: { + nullOrder: 'last' + } + }, + sqlite: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' + }, + mysql: { + text: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`', + string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`' + }, + mssql: { + text: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content]', + string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content]' + }, + oracle: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.content).order(post.content.asc()), + pg: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" NULLS FIRST', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" NULLS FIRST', + config: { + nullOrder: 'first' + } + }, + sqlite: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' + }, + mysql: { + text: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`', + string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`' + }, + mssql: { + text: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content]', + string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content]' + }, + oracle: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.content).order([]), + pg: { + text: 'SELECT "post"."content" FROM "post"', + string: 'SELECT "post"."content" FROM "post"' + }, + sqlite: { + text: 'SELECT "post"."content" FROM "post"', + string: 'SELECT "post"."content" FROM "post"' + }, + mysql: { + text: 'SELECT `post`.`content` FROM `post`', + string: 'SELECT `post`.`content` FROM `post`' + }, + mssql: { + text: 'SELECT [post].[content] FROM [post]', + string: 'SELECT [post].[content] FROM [post]' + }, + oracle: { + text: 'SELECT "post"."content" FROM "post"', + string: 'SELECT "post"."content" FROM "post"' + }, + params: [] +}); diff --git a/test/dialects/regex-tests.js b/test/dialects/regex-tests.js deleted file mode 100644 index 40dde618..00000000 --- a/test/dialects/regex-tests.js +++ /dev/null @@ -1,41 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var customer = Harness.defineCustomerTable(); -var Sql = require('../../lib').setDialect('postgres'); - -Harness.test({ - query: customer.select(customer.metadata.regex('age')), - pg: { - text : 'SELECT ("customer"."metadata" ~ $1) FROM "customer"', - string: 'SELECT ("customer"."metadata" ~ \'age\') FROM "customer"' - }, - params: ['age'] -}); - -Harness.test({ - query: customer.select(customer.metadata.iregex('age')), - pg: { - text : 'SELECT ("customer"."metadata" ~* $1) FROM "customer"', - string: 'SELECT ("customer"."metadata" ~* \'age\') FROM "customer"' - }, - params: ['age'] -}); - -Harness.test({ - query: customer.select(customer.metadata.notRegex('age')), - pg: { - text : 'SELECT ("customer"."metadata" !~ $1) FROM "customer"', - string: 'SELECT ("customer"."metadata" !~ \'age\') FROM "customer"' - }, - params: ['age'] -}); - -Harness.test({ - query: customer.select(customer.metadata.notIregex('age')), - pg: { - text : 'SELECT ("customer"."metadata" !~* $1) FROM "customer"', - string: 'SELECT ("customer"."metadata" !~* \'age\') FROM "customer"' - }, - params: ['age'] -}); diff --git a/test/dialects/regex-tests.ts b/test/dialects/regex-tests.ts new file mode 100644 index 00000000..375d3119 --- /dev/null +++ b/test/dialects/regex-tests.ts @@ -0,0 +1,38 @@ +import * as Harness from './support.js'; +const customer = Harness.defineCustomerTable(); + +Harness.test({ + query: customer.select(customer.metadata.regex('age')), + pg: { + text: 'SELECT ("customer"."metadata" ~ $1) FROM "customer"', + string: 'SELECT ("customer"."metadata" ~ \'age\') FROM "customer"' + }, + params: ['age'] +}); + +Harness.test({ + query: customer.select(customer.metadata.iregex('age')), + pg: { + text: 'SELECT ("customer"."metadata" ~* $1) FROM "customer"', + string: 'SELECT ("customer"."metadata" ~* \'age\') FROM "customer"' + }, + params: ['age'] +}); + +Harness.test({ + query: customer.select(customer.metadata.notRegex('age')), + pg: { + text: 'SELECT ("customer"."metadata" !~ $1) FROM "customer"', + string: 'SELECT ("customer"."metadata" !~ \'age\') FROM "customer"' + }, + params: ['age'] +}); + +Harness.test({ + query: customer.select(customer.metadata.notIregex('age')), + pg: { + text: 'SELECT ("customer"."metadata" !~* $1) FROM "customer"', + string: 'SELECT ("customer"."metadata" !~* \'age\') FROM "customer"' + }, + params: ['age'] +}); diff --git a/test/dialects/replace-tests.js b/test/dialects/replace-tests.js deleted file mode 100644 index 72af0e4b..00000000 --- a/test/dialects/replace-tests.js +++ /dev/null @@ -1,1000 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var post = Harness.definePostTable(); -var user = Harness.defineUserTable(); -var contentTable = Harness.defineContentTable(); -var customerAliasTable = Harness.defineCustomerAliasTable(); - -var arrayTable = require('../../lib/table').define({ - name: 'arraytest', - columns: ['id', 'numbers'] -}); - -Harness.test({ - query: post.replace(post.content.value('test'), post.userId.value(1)), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "post" ("content", "userId") VALUES ($1, $2)', - string: 'REPLACE INTO "post" ("content", "userId") VALUES (\'test\', 1)' - }, - mysql: { - text : 'REPLACE INTO `post` (`content`, `userId`) VALUES (?, ?)', - string: 'REPLACE INTO `post` (`content`, `userId`) VALUES (\'test\', 1)' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['test', 1] -}); - -Harness.test({ - query: post.replace(post.content.value('whoah')), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "post" ("content") VALUES ($1)', - string: 'REPLACE INTO "post" ("content") VALUES (\'whoah\')' - }, - mysql: { - text : 'REPLACE INTO `post` (`content`) VALUES (?)', - string: 'REPLACE INTO `post` (`content`) VALUES (\'whoah\')' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['whoah'] -}); - -Harness.test({ - query: post.replace({length: 0}), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "post" ("length") VALUES ($1)', - string: 'REPLACE INTO "post" ("length") VALUES (0)' - }, - mysql: { - text : 'REPLACE INTO `post` (`length`) VALUES (?)', - string: 'REPLACE INTO `post` (`length`) VALUES (0)' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [0] -}); - -Harness.test({ - query: post.replace({ - content: 'test', - userId: 2 - }), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "post" ("content", "userId") VALUES ($1, $2)', - string: 'REPLACE INTO "post" ("content", "userId") VALUES (\'test\', 2)' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['test', 2] -}); - -Harness.test({ - query: post.replace({ - content: post.sql.functions.LOWER('TEST'), - userId: 2 - }), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "post" ("content", "userId") VALUES (LOWER($1), $2)', - string: 'REPLACE INTO "post" ("content", "userId") VALUES (LOWER(\'TEST\'), 2)' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['TEST', 2] -}); - -// allow bulk replace -Harness.test({ - query: post.replace([{ - content: 'whoah' - }, { - content: 'hey' - } - ]), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "post" ("content") VALUES ($1), ($2)', - string: 'REPLACE INTO "post" ("content") VALUES (\'whoah\'), (\'hey\')' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['whoah', 'hey'] -}); - -Harness.test({ - query: post.replace([{ - content: 'whoah', - userId: 1 - }, { - content: 'hey', - userId: 2 - } - ]), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', - string: 'REPLACE INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['whoah', 1, 'hey', 2] -}); - -// consistent order -Harness.test({ - query: post.replace([{ - content: 'whoah', - userId: 1 - }, { - userId: 2, - content: 'hey' - } - ]), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', - string: 'REPLACE INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' - }, - mysql: { - text : 'REPLACE INTO `post` (`content`, `userId`) VALUES (?, ?), (?, ?)', - string: 'REPLACE INTO `post` (`content`, `userId`) VALUES (\'whoah\', 1), (\'hey\', 2)' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['whoah', 1, 'hey', 2] -}); - -Harness.test({ - query: post.replace({}), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "post" DEFAULT VALUES', - string: 'REPLACE INTO "post" DEFAULT VALUES' - }, - mysql: { - text : 'REPLACE INTO `post` () VALUES ()', - string: 'REPLACE INTO `post` () VALUES ()' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [] -}); - -Harness.test({ - query: post.replace({}).returning('*'), - pg: { - throws: true - }, - sqlite: { - throws: true - }, - mysql: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [] -}); - -Harness.test({ - query: post.replace({}).returning(post.star()), - pg: { - throws: true - }, - sqlite: { - throws: true - }, - mysql: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [] -}); - -Harness.test({ - query: post.replace({}).returning(post.id), - pg: { - throws: true - }, - sqlite: { - throws: true - }, - mysql: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [] -}); - -Harness.test({ - query: post.replace({}).returning(post.id, post.content), - pg: { - throws: true - }, - sqlite: { - throws: true - }, - mysql: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [] -}); - -Harness.test({ - query: post.replace({}).returning([post.id, post.content]), - pg: { - throws: true - }, - sqlite: { - throws: true - }, - mysql: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [] -}); - -// handle missing columns -Harness.test({ - query: post.replace([{ - content: 'whoah', - userId: 1 - }, { - content: 'hey' - } - ]), - pg: { - throws: true - }, - sqlite: { - text : 'Sqlite requires the same number of columns in each replace row', - throws: true - }, - mysql: { - text : 'REPLACE INTO `post` (`content`, `userId`) VALUES (?, ?), (?, DEFAULT)', - string: 'REPLACE INTO `post` (`content`, `userId`) VALUES (\'whoah\', 1), (\'hey\', DEFAULT)', - params: ['whoah', 1, 'hey'] - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, -}); - -Harness.test({ - query: post.replace([{ - userId: 1 - }, { - content: 'hey', - userId: 2 - } - ]), - pg: { - throws: true - }, - sqlite: { - text : 'Sqlite requires the same number of columns in each replace row', - throws: true - }, - mysql: { - text : 'REPLACE INTO `post` (`userId`, `content`) VALUES (?, DEFAULT), (?, ?)', - string: 'REPLACE INTO `post` (`userId`, `content`) VALUES (1, DEFAULT), (2, \'hey\')', - params: [1, 2, 'hey'] - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, -}); - -Harness.test({ - query: post.replace(post.content, post.userId) - .select('\'test\'', user.id).from(user).where(user.name.like('A%')), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', - string: 'REPLACE INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' - }, - mysql: { - text : 'REPLACE INTO `post` (`content`, `userId`) SELECT \'test\', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE ?)', - string: 'REPLACE INTO `post` (`content`, `userId`) SELECT \'test\', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE \'A%\')' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['A%'] -}); - -Harness.test({ - query: post.replace([post.content, post.userId]) - .select('\'test\'', user.id).from(user).where(user.name.like('A%')), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', - string: 'REPLACE INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' - }, - mysql: { - text : 'REPLACE INTO `post` (`content`, `userId`) SELECT \'test\', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE ?)', - string: 'REPLACE INTO `post` (`content`, `userId`) SELECT \'test\', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE \'A%\')' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['A%'] -}); - -Harness.test({ - query: post.replace(post.userId) - .select(user.id).from(user).where(user.name.like('A%')), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', - string: 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['A%'] -}); - -Harness.test({ - query: post.replace(post.userId) - .select(post.userId).from(user.join(post).on(user.id.equals(post.userId))).where(post.tags.like('A%')), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE $1)', - string: 'REPLACE INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE \'A%\')' - }, - mysql: { - text : 'REPLACE INTO `post` (`userId`) SELECT `post`.`userId` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`post`.`tags` LIKE ?)', - string: 'REPLACE INTO `post` (`userId`) SELECT `post`.`userId` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`post`.`tags` LIKE \'A%\')' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['A%'] -}); - -Harness.test({ - query: post.replace(post.userId).select(user.id).distinct().from(user), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "post" ("userId") SELECT DISTINCT "user"."id" FROM "user"', - string: 'REPLACE INTO "post" ("userId") SELECT DISTINCT "user"."id" FROM "user"' - }, - mysql: { - text : 'REPLACE INTO `post` (`userId`) SELECT DISTINCT `user`.`id` FROM `user`', - string: 'REPLACE INTO `post` (`userId`) SELECT DISTINCT `user`.`id` FROM `user`' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [] -}); - -// Binary replaces -Harness.test({ - query: post.replace(post.content.value(new Buffer('test')), post.userId.value(2)), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "post" ("content", "userId") VALUES ($1, $2)', - string: 'REPLACE INTO "post" ("content", "userId") VALUES (x\'74657374\', 2)' - }, - mysql: { - text : 'REPLACE INTO `post` (`content`, `userId`) VALUES (?, ?)', - string: 'REPLACE INTO `post` (`content`, `userId`) VALUES (x\'74657374\', 2)' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [new Buffer('test'), 2] -}); - -Harness.test({ - query: post.replace({ - content: new Buffer('test'), - userId: 2 - }), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "post" ("content", "userId") VALUES ($1, $2)', - string: 'REPLACE INTO "post" ("content", "userId") VALUES (x\'74657374\', 2)' - }, - mysql: { - text : 'REPLACE INTO `post` (`content`, `userId`) VALUES (?, ?)', - string: 'REPLACE INTO `post` (`content`, `userId`) VALUES (x\'74657374\', 2)' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [new Buffer('test'), 2] -}); - -Harness.test({ - query: post.replace([{ - content: new Buffer('whoah') - }, { - content: new Buffer('hey') - } - ]), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "post" ("content") VALUES ($1), ($2)', - string: 'REPLACE INTO "post" ("content") VALUES (x\'77686f6168\'), (x\'686579\')' - }, - mysql: { - text : 'REPLACE INTO `post` (`content`) VALUES (?), (?)', - string: 'REPLACE INTO `post` (`content`) VALUES (x\'77686f6168\'), (x\'686579\')' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [new Buffer('whoah'), new Buffer('hey')] -}); - -Harness.test({ - query: post.replace({ - content: 'test', - userId: 2 - }).onDuplicate({ - content: 'testupdate', - }), - pg: { - throws: true - }, - sqlite: { - throws: true - }, - mysql: { - text : 'REPLACE INTO `post` (`content`, `userId`) VALUES (?, ?) ON DUPLICATE KEY UPDATE `post`.`content` = ?', - string: 'REPLACE INTO `post` (`content`, `userId`) VALUES (\'test\', 2) ON DUPLICATE KEY UPDATE `post`.`content` = \'testupdate\'' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['test', 2, 'testupdate'] -}); - -Harness.test({ - query: customerAliasTable.replace({ - id : 2, - name : 'test' - }).onConflict({ - columns: ['id'], - update: ['name'] - }), - mysql: { - throws: true - }, - sqlite: { - throws: true - }, - pg: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [2, 'test'] -}); - -Harness.test({ - query: customerAliasTable.replace({ - id : 2, - name : 'test' - }).orIgnore(), - mysql: { - throws: true - }, - sqlite: { - text : 'REPLACE OR IGNORE INTO "customer" ("id", "name") VALUES ($1, $2)', - string: 'REPLACE OR IGNORE INTO "customer" ("id", "name") VALUES (2, \'test\')' - }, - pg: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [2, 'test'] -}); - -Harness.test({ - query: post.replace({ - content: 'test', - userId: 2 - }).onConflict({ - columns: ['userId'], - update: ['content'] - }), - mysql: { - throws: true - }, - sqlite: { - throws: true - }, - pg: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['test', 2] -}); - -Harness.test({ - query: post.replace({ - content: 'test', - userId: 2 - }).onConflict({ - columns: ['userId','content'], - update: ['content','userId'] - }), - mysql: { - throws: true - }, - sqlite: { - throws: true - }, - pg: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['test', 2] -}); - -Harness.test({ - query: post.replace({ - content: 'test', - userId: 2 - }).onConflict({ - columns: ['userId'], - update: ['content'] - }).where(post.userId.equals(2)), - mysql: { - throws: true - }, - sqlite: { - throws: true - }, - pg: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['test', 2, 2] -}); - -Harness.test({ - query: post.replace({ - content: 'test', - userId: 2 - }).onConflict({ - constraint: 'conc_userId', - update: ['content'] - }).where(post.userId.equals(2)), - mysql: { - throws: true - }, - sqlite: { - throws: true - }, - pg: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['test', 2, 2] -}); - -Harness.test({ - query: post.replace({ - content: 'test', - userId: 2 - }).onConflict({ - columns: ['userId'], - }), - mysql: { - throws: true - }, - sqlite: { - throws: true - }, - pg: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['test', 2] -}); - -Harness.test({ - query: post.replace({ - content: 'test', - userId: 2 - }).onConflict({ - constraint: 'conc_userId', - }), - mysql: { - throws: true - }, - sqlite: { - throws: true - }, - pg: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: ['test', 2] -}); - -Harness.test({ - query: contentTable.replace({ - contentId: 20, - text : "something" - }).onConflict({ - columns: ['contentId'], - }), - mysql: { - throws: true - }, - sqlite: { - throws: true - }, - pg: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [20, "something"] -}); - -Harness.test({ - query: contentTable.replace({ - contentId: 20, - text : "something", - contentPosts : "another thing", - }).onConflict({ - columns: ['contentId'], - update: ['contentPosts'] - }), - mysql: { - throws: true - }, - sqlite: { - throws: true - }, - pg: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [20, "something", "another thing"] -}); - -Harness.test({ - query: post.replace([]), - - mysql: { - text : 'SELECT `post`.* FROM `post` WHERE (1=2)', - string: 'SELECT `post`.* FROM `post` WHERE (1=2)' - }, - params: [] -}); - -Harness.test({ - query: arrayTable.replace(arrayTable.id.value(1), arrayTable.numbers.value([2, 3, 4])), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', - string: 'REPLACE INTO "arraytest" ("id", "numbers") VALUES (1, \'[2,3,4]\')' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - } -}); - -Harness.test({ - query: arrayTable.replace(arrayTable.id.value(1), arrayTable.numbers.value(["one", "two", "three"])), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', - string: 'REPLACE INTO "arraytest" ("id", "numbers") VALUES (1, \'["one","two","three"]\')' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - } -}); - -Harness.test({ - query: post.replace(post.userId).select(user.id).from(user), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user"', - string: 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user"' - }, - mysql: { - text : 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user`', - string: 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user`' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [] -}); - -Harness.test({ - query: post.replace(post.userId).select(user.id).from(user).onConflict({ - columns: ['userId'], - update: ['content'] - }), - pg: { - throws: true - }, - sqlite: { - throws: true - }, - mysql: { - throws: true - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [] -}); - -Harness.test({ - query: post.replace(post.userId).add(user.select(user.id)), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user"', - string: 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user"' - }, - mysql: { - text : 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user`', - string: 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user`' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [] -}); - -Harness.test({ - query: post.replace(post.userId).add(user.select(user.id).from(user)), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user"', - string: 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user"' - }, - mysql: { - text : 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user`', - string: 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user`' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [] -}); - -Harness.test({ - query: post.replace(post.userId).add(user.select(user.id).order(user.id)), - pg: { - throws: true - }, - sqlite: { - text : 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"', - string: 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"' - }, - mysql: { - text : 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user` ORDER BY `user`.`id`', - string: 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user` ORDER BY `user`.`id`' - }, - mssql: { - throws: true - }, - oracle: { - throws: true - }, - params: [] -}); diff --git a/test/dialects/replace-tests.ts b/test/dialects/replace-tests.ts new file mode 100644 index 00000000..2dcd0ced --- /dev/null +++ b/test/dialects/replace-tests.ts @@ -0,0 +1,1062 @@ +import * as Harness from './support.js'; +import { Table } from '../../dist/lib.js'; +const post = Harness.definePostTable(); +const user = Harness.defineUserTable(); +const contentTable = Harness.defineContentTable(); +const customerAliasTable = Harness.defineCustomerAliasTable(); + +const arrayTable = Table.define<{ id: number; numbers: any[] }>({ + name: 'arraytest', + columns: ['id', 'numbers'] +}); + +Harness.test({ + query: post.replace(post.content.value('test'), post.userId.value(1)), + pg: { + throws: true + }, + sqlite: { + text: 'REPLACE INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'REPLACE INTO "post" ("content", "userId") VALUES (\'test\', 1)' + }, + mysql: { + text: 'REPLACE INTO `post` (`content`, `userId`) VALUES (?, ?)', + string: "REPLACE INTO `post` (`content`, `userId`) VALUES ('test', 1)" + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 1] +}); + +Harness.test({ + query: post.replace(post.content.value('whoah')), + pg: { + throws: true + }, + sqlite: { + text: 'REPLACE INTO "post" ("content") VALUES ($1)', + string: 'REPLACE INTO "post" ("content") VALUES (\'whoah\')' + }, + mysql: { + text: 'REPLACE INTO `post` (`content`) VALUES (?)', + string: "REPLACE INTO `post` (`content`) VALUES ('whoah')" + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['whoah'] +}); + +Harness.test({ + query: post.replace({ length: 0 }), + pg: { + throws: true + }, + sqlite: { + text: 'REPLACE INTO "post" ("length") VALUES ($1)', + string: 'REPLACE INTO "post" ("length") VALUES (0)' + }, + mysql: { + text: 'REPLACE INTO `post` (`length`) VALUES (?)', + string: 'REPLACE INTO `post` (`length`) VALUES (0)' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [0] +}); + +Harness.test({ + query: post.replace({ + content: 'test', + userId: 2 + }), + pg: { + throws: true + }, + sqlite: { + text: 'REPLACE INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'REPLACE INTO "post" ("content", "userId") VALUES (\'test\', 2)' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2] +}); + +Harness.test({ + query: post.replace({ + content: post.sql.functions.LOWER('TEST'), + userId: 2 + }), + pg: { + throws: true + }, + sqlite: { + text: 'REPLACE INTO "post" ("content", "userId") VALUES (LOWER($1), $2)', + string: 'REPLACE INTO "post" ("content", "userId") VALUES (LOWER(\'TEST\'), 2)' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['TEST', 2] +}); + +// allow bulk replace +Harness.test({ + query: post.replace([ + { + content: 'whoah' + }, + { + content: 'hey' + } + ]), + pg: { + throws: true + }, + sqlite: { + text: 'REPLACE INTO "post" ("content") VALUES ($1), ($2)', + string: 'REPLACE INTO "post" ("content") VALUES (\'whoah\'), (\'hey\')' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['whoah', 'hey'] +}); + +Harness.test({ + query: post.replace([ + { + content: 'whoah', + userId: 1 + }, + { + content: 'hey', + userId: 2 + } + ]), + pg: { + throws: true + }, + sqlite: { + text: 'REPLACE INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', + string: 'REPLACE INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['whoah', 1, 'hey', 2] +}); + +// consistent order +Harness.test({ + query: post.replace([ + { + content: 'whoah', + userId: 1 + }, + { + userId: 2, + content: 'hey' + } + ]), + pg: { + throws: true + }, + sqlite: { + text: 'REPLACE INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', + string: 'REPLACE INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' + }, + mysql: { + text: 'REPLACE INTO `post` (`content`, `userId`) VALUES (?, ?), (?, ?)', + string: "REPLACE INTO `post` (`content`, `userId`) VALUES ('whoah', 1), ('hey', 2)" + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['whoah', 1, 'hey', 2] +}); + +Harness.test({ + query: post.replace({}), + pg: { + throws: true + }, + sqlite: { + text: 'REPLACE INTO "post" DEFAULT VALUES', + string: 'REPLACE INTO "post" DEFAULT VALUES' + }, + mysql: { + text: 'REPLACE INTO `post` () VALUES ()', + string: 'REPLACE INTO `post` () VALUES ()' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.replace({}).returning('*'), + pg: { + throws: true + }, + sqlite: { + throws: true + }, + mysql: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.replace({}).returning(post.star()), + pg: { + throws: true + }, + sqlite: { + throws: true + }, + mysql: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.replace({}).returning(post.id), + pg: { + throws: true + }, + sqlite: { + throws: true + }, + mysql: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.replace({}).returning(post.id, post.content), + pg: { + throws: true + }, + sqlite: { + throws: true + }, + mysql: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.replace({}).returning([post.id, post.content]), + pg: { + throws: true + }, + sqlite: { + throws: true + }, + mysql: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +// handle missing columns +Harness.test({ + query: post.replace([ + { + content: 'whoah', + userId: 1 + }, + { + content: 'hey' + } + ]), + pg: { + throws: true + }, + sqlite: { + text: 'Sqlite requires the same number of columns in each replace row', + throws: true + }, + mysql: { + text: 'REPLACE INTO `post` (`content`, `userId`) VALUES (?, ?), (?, DEFAULT)', + string: "REPLACE INTO `post` (`content`, `userId`) VALUES ('whoah', 1), ('hey', DEFAULT)", + params: ['whoah', 1, 'hey'] + }, + mssql: { + throws: true + }, + oracle: { + throws: true + } +}); + +Harness.test({ + query: post.replace([ + { + userId: 1 + }, + { + content: 'hey', + userId: 2 + } + ]), + pg: { + throws: true + }, + sqlite: { + text: 'Sqlite requires the same number of columns in each replace row', + throws: true + }, + mysql: { + text: 'REPLACE INTO `post` (`userId`, `content`) VALUES (?, DEFAULT), (?, ?)', + string: "REPLACE INTO `post` (`userId`, `content`) VALUES (1, DEFAULT), (2, 'hey')", + params: [1, 2, 'hey'] + }, + mssql: { + throws: true + }, + oracle: { + throws: true + } +}); + +Harness.test({ + query: post + .replace(post.content, post.userId) + .select("'test'", user.id) + .from(user) + .where(user.name.like('A%')), + pg: { + throws: true + }, + sqlite: { + text: 'REPLACE INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', + string: 'REPLACE INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' + }, + mysql: { + text: "REPLACE INTO `post` (`content`, `userId`) SELECT 'test', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE ?)", + string: "REPLACE INTO `post` (`content`, `userId`) SELECT 'test', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE 'A%')" + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['A%'] +}); + +Harness.test({ + query: post + .replace([post.content, post.userId]) + .select("'test'", user.id) + .from(user) + .where(user.name.like('A%')), + pg: { + throws: true + }, + sqlite: { + text: 'REPLACE INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', + string: 'REPLACE INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' + }, + mysql: { + text: "REPLACE INTO `post` (`content`, `userId`) SELECT 'test', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE ?)", + string: "REPLACE INTO `post` (`content`, `userId`) SELECT 'test', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE 'A%')" + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['A%'] +}); + +Harness.test({ + query: post + .replace(post.userId) + .select(user.id) + .from(user) + .where(user.name.like('A%')), + pg: { + throws: true + }, + sqlite: { + text: 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', + string: 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['A%'] +}); + +Harness.test({ + query: post + .replace(post.userId) + .select(post.userId) + .from(user.join(post).on(user.id.equals(post.userId))) + .where(post.tags.like('A%')), + pg: { + throws: true + }, + sqlite: { + text: + 'REPLACE INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE $1)', + string: + 'REPLACE INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE \'A%\')' + }, + mysql: { + text: + 'REPLACE INTO `post` (`userId`) SELECT `post`.`userId` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`post`.`tags` LIKE ?)', + string: + "REPLACE INTO `post` (`userId`) SELECT `post`.`userId` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`post`.`tags` LIKE 'A%')" + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['A%'] +}); + +Harness.test({ + query: post + .replace(post.userId) + .select(user.id) + .distinct() + .from(user), + pg: { + throws: true + }, + sqlite: { + text: 'REPLACE INTO "post" ("userId") SELECT DISTINCT "user"."id" FROM "user"', + string: 'REPLACE INTO "post" ("userId") SELECT DISTINCT "user"."id" FROM "user"' + }, + mysql: { + text: 'REPLACE INTO `post` (`userId`) SELECT DISTINCT `user`.`id` FROM `user`', + string: 'REPLACE INTO `post` (`userId`) SELECT DISTINCT `user`.`id` FROM `user`' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +// Binary replaces +Harness.test({ + query: post.replace(post.content.value(Buffer.from('test')), post.userId.value(2)), + pg: { + throws: true + }, + sqlite: { + text: 'REPLACE INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'REPLACE INTO "post" ("content", "userId") VALUES (x\'74657374\', 2)' + }, + mysql: { + text: 'REPLACE INTO `post` (`content`, `userId`) VALUES (?, ?)', + string: "REPLACE INTO `post` (`content`, `userId`) VALUES (x'74657374', 2)" + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [Buffer.from('test'), 2] +}); + +Harness.test({ + query: post.replace({ + content: Buffer.from('test'), + userId: 2 + }), + pg: { + throws: true + }, + sqlite: { + text: 'REPLACE INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'REPLACE INTO "post" ("content", "userId") VALUES (x\'74657374\', 2)' + }, + mysql: { + text: 'REPLACE INTO `post` (`content`, `userId`) VALUES (?, ?)', + string: "REPLACE INTO `post` (`content`, `userId`) VALUES (x'74657374', 2)" + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [Buffer.from('test'), 2] +}); + +Harness.test({ + query: post.replace([ + { + content: Buffer.from('whoah') + }, + { + content: Buffer.from('hey') + } + ]), + pg: { + throws: true + }, + sqlite: { + text: 'REPLACE INTO "post" ("content") VALUES ($1), ($2)', + string: 'REPLACE INTO "post" ("content") VALUES (x\'77686f6168\'), (x\'686579\')' + }, + mysql: { + text: 'REPLACE INTO `post` (`content`) VALUES (?), (?)', + string: "REPLACE INTO `post` (`content`) VALUES (x'77686f6168'), (x'686579')" + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [Buffer.from('whoah'), Buffer.from('hey')] +}); + +Harness.test({ + query: post + .replace({ + content: 'test', + userId: 2 + }) + .onDuplicate({ + content: 'testupdate' + }), + pg: { + throws: true + }, + sqlite: { + throws: true + }, + mysql: { + text: 'REPLACE INTO `post` (`content`, `userId`) VALUES (?, ?) ON DUPLICATE KEY UPDATE `post`.`content` = ?', + string: "REPLACE INTO `post` (`content`, `userId`) VALUES ('test', 2) ON DUPLICATE KEY UPDATE `post`.`content` = 'testupdate'" + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2, 'testupdate'] +}); + +Harness.test({ + query: customerAliasTable + .replace({ + id_alias: 2, + name_alias: 'test' + }) + .onConflict({ + columns: ['id'], + update: ['name'] + }), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [2, 'test'] +}); + +Harness.test({ + query: customerAliasTable + .replace({ + id_alias: 2, + name_alias: 'test' + }) + .orIgnore(), + mysql: { + throws: true + }, + sqlite: { + text: 'REPLACE OR IGNORE INTO "customer" ("id", "name") VALUES ($1, $2)', + string: 'REPLACE OR IGNORE INTO "customer" ("id", "name") VALUES (2, \'test\')' + }, + pg: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [2, 'test'] +}); + +Harness.test({ + query: post + .replace({ + content: 'test', + userId: 2 + }) + .onConflict({ + columns: ['userId'], + update: ['content'] + }), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2] +}); + +Harness.test({ + query: post + .replace({ + content: 'test', + userId: 2 + }) + .onConflict({ + columns: ['userId', 'content'], + update: ['content', 'userId'] + }), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2] +}); + +Harness.test({ + query: post + .replace({ + content: 'test', + userId: 2 + }) + .onConflict({ + columns: ['userId'], + update: ['content'] + }) + .where(post.userId.equals(2)), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2, 2] +}); + +Harness.test({ + query: post + .replace({ + content: 'test', + userId: 2 + }) + .onConflict({ + constraint: 'conc_userId', + update: ['content'] + }) + .where(post.userId.equals(2)), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2, 2] +}); + +Harness.test({ + query: post + .replace({ + content: 'test', + userId: 2 + }) + .onConflict({ + columns: ['userId'] + }), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2] +}); + +Harness.test({ + query: post + .replace({ + content: 'test', + userId: 2 + }) + .onConflict({ + constraint: 'conc_userId' + }), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2] +}); + +Harness.test({ + query: contentTable + .replace({ + contentId: 20, + text: 'something' + }) + .onConflict({ + columns: ['contentId'] + }), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [20, 'something'] +}); + +Harness.test({ + query: contentTable + .replace({ + contentId: 20, + text: 'something', + contentPosts: 'another thing' + }) + .onConflict({ + columns: ['contentId'], + update: ['contentPosts'] + }), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [20, 'something', 'another thing'] +}); + +Harness.test({ + query: post.replace([]), + + mysql: { + text: 'SELECT `post`.* FROM `post` WHERE (1=2)', + string: 'SELECT `post`.* FROM `post` WHERE (1=2)' + }, + params: [] +}); + +Harness.test({ + query: arrayTable.replace(arrayTable.id.value(1), arrayTable.numbers.value([2, 3, 4])), + pg: { + throws: true + }, + sqlite: { + text: 'REPLACE INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', + string: 'REPLACE INTO "arraytest" ("id", "numbers") VALUES (1, \'[2,3,4]\')' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + } +}); + +Harness.test({ + query: arrayTable.replace(arrayTable.id.value(1), arrayTable.numbers.value(['one', 'two', 'three'])), + pg: { + throws: true + }, + sqlite: { + text: 'REPLACE INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', + string: 'REPLACE INTO "arraytest" ("id", "numbers") VALUES (1, \'["one","two","three"]\')' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + } +}); + +Harness.test({ + query: post + .replace(post.userId) + .select(user.id) + .from(user), + pg: { + throws: true + }, + sqlite: { + text: 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + mysql: { + text: 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user`', + string: 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user`' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post + .replace(post.userId) + .select(user.id) + .from(user) + .onConflict({ + columns: ['userId'], + update: ['content'] + }), + pg: { + throws: true + }, + sqlite: { + throws: true + }, + mysql: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.replace(post.userId).add(user.select(user.id)), + pg: { + throws: true + }, + sqlite: { + text: 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + mysql: { + text: 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user`', + string: 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user`' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.replace(post.userId).add(user.select(user.id).from(user)), + pg: { + throws: true + }, + sqlite: { + text: 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + mysql: { + text: 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user`', + string: 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user`' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.replace(post.userId).add(user.select(user.id).order(user.id)), + pg: { + throws: true + }, + sqlite: { + text: 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"', + string: 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"' + }, + mysql: { + text: 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user` ORDER BY `user`.`id`', + string: 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user` ORDER BY `user`.`id`' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); diff --git a/test/dialects/returning-tests.js b/test/dialects/returning-tests.js deleted file mode 100644 index ebbb0b2e..00000000 --- a/test/dialects/returning-tests.js +++ /dev/null @@ -1,20 +0,0 @@ -var Harness = require('./support'); -var user = Harness.defineUserTable(); - -Harness.test({ - query: user.insert({name: 'joe'}).returning(), - pg: { - text : 'INSERT INTO "user" ("name") VALUES ($1) RETURNING *', - string: 'INSERT INTO "user" ("name") VALUES (\'joe\') RETURNING *' - }, - params: ['joe'] -}); - -Harness.test({ - query: user.insert({name: 'joe'}).returning('id'), - pg: { - text : 'INSERT INTO "user" ("name") VALUES ($1) RETURNING id', - string: 'INSERT INTO "user" ("name") VALUES (\'joe\') RETURNING id' - }, - params: ['joe'] -}); diff --git a/test/dialects/returning-tests.ts b/test/dialects/returning-tests.ts new file mode 100644 index 00000000..3bfee9a2 --- /dev/null +++ b/test/dialects/returning-tests.ts @@ -0,0 +1,20 @@ +import * as Harness from './support.js'; +const user = Harness.defineUserTable(); + +Harness.test({ + query: user.insert({ name: 'joe' }).returning(), + pg: { + text: 'INSERT INTO "user" ("name") VALUES ($1) RETURNING *', + string: 'INSERT INTO "user" ("name") VALUES (\'joe\') RETURNING *' + }, + params: ['joe'] +}); + +Harness.test({ + query: user.insert({ name: 'joe' }).returning('id'), + pg: { + text: 'INSERT INTO "user" ("name") VALUES ($1) RETURNING id', + string: 'INSERT INTO "user" ("name") VALUES (\'joe\') RETURNING id' + }, + params: ['joe'] +}); diff --git a/test/dialects/row-tests.ts b/test/dialects/row-tests.ts new file mode 100644 index 00000000..0ad77761 --- /dev/null +++ b/test/dialects/row-tests.ts @@ -0,0 +1,32 @@ +import * as Harness from './support.js'; +import { Sql } from '../../dist/lib.js'; +const post = Harness.definePostTable(); +const instance = new Sql('postgres'); + +// Array columns +Harness.test({ + query: instance.row(post.userId, 'some new content', instance.array('nodejs')), + pg: { + text: '("post"."userId", $1, ARRAY[$2])', + string: '("post"."userId", \'some new content\', ARRAY[\'nodejs\'])' + }, + params: ['some new content', 'nodejs'] +}); + +Harness.test({ + query: post.select(post.star()).where(instance.row(post.userId, post.content).equals(instance.row(1234, 'some new content'))), + pg: { + text: 'SELECT "post".* FROM "post" WHERE (("post"."userId", "post"."content") = ($1, $2))', + string: 'SELECT "post".* FROM "post" WHERE (("post"."userId", "post"."content") = (1234, \'some new content\'))' + }, + params: [1234, 'some new content'] +}); + +Harness.test({ + query: post.select(post.star()).where(instance.row(post.userId, post.content).in([instance.row(1234, 'some new content'), instance.row(5678, 'some other content')])), + pg: { + text: 'SELECT "post".* FROM "post" WHERE (("post"."userId", "post"."content") IN (($1, $2), ($3, $4)))', + string: 'SELECT "post".* FROM "post" WHERE (("post"."userId", "post"."content") IN ((1234, \'some new content\'), (5678, \'some other content\')))' + }, + params: [1234, 'some new content', 5678, 'some other content'] +}); diff --git a/test/dialects/schema-tests.js b/test/dialects/schema-tests.js deleted file mode 100644 index 11e330da..00000000 --- a/test/dialects/schema-tests.js +++ /dev/null @@ -1,168 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var Table = require(__dirname + '/../../lib/table'); - -var userWithSchema = Table.define({ - schema: 'staging', - name: 'user', - quote: true, - columns: ['id', 'name'] -}); - -Harness.test({ - query: userWithSchema.select(userWithSchema.id).from(userWithSchema), - pg: { - text : 'SELECT "staging"."user"."id" FROM "staging"."user"', - string: 'SELECT "staging"."user"."id" FROM "staging"."user"' - }, - sqlite: { - text : 'SELECT "staging"."user"."id" FROM "staging"."user"', - string: 'SELECT "staging"."user"."id" FROM "staging"."user"' - }, - mysql: { - text : 'SELECT `staging`.`user`.`id` FROM `staging`.`user`', - string: 'SELECT `staging`.`user`.`id` FROM `staging`.`user`' - }, - mssql: { - text : 'SELECT [staging].[user].[id] FROM [staging].[user]', - string: 'SELECT [staging].[user].[id] FROM [staging].[user]' - }, - oracle: { - text : 'SELECT "staging"."user"."id" FROM "staging"."user"', - string: 'SELECT "staging"."user"."id" FROM "staging"."user"' - }, - params: [] -}); - -Harness.test({ - query: userWithSchema.select(userWithSchema.id.count()).from(userWithSchema), - pg: { - text : 'SELECT COUNT("staging"."user"."id") AS "id_count" FROM "staging"."user"', - string: 'SELECT COUNT("staging"."user"."id") AS "id_count" FROM "staging"."user"' - }, - sqlite: { - text : 'SELECT COUNT("staging"."user"."id") AS "id_count" FROM "staging"."user"', - string: 'SELECT COUNT("staging"."user"."id") AS "id_count" FROM "staging"."user"' - }, - mysql: { - text : 'SELECT COUNT(`staging`.`user`.`id`) AS `id_count` FROM `staging`.`user`', - string: 'SELECT COUNT(`staging`.`user`.`id`) AS `id_count` FROM `staging`.`user`' - }, - mssql: { - text : 'SELECT COUNT([staging].[user].[id]) AS [id_count] FROM [staging].[user]', - string: 'SELECT COUNT([staging].[user].[id]) AS [id_count] FROM [staging].[user]' - }, - oracle: { - text : 'SELECT COUNT("staging"."user"."id") "id_count" FROM "staging"."user"', - string: 'SELECT COUNT("staging"."user"."id") "id_count" FROM "staging"."user"' - }, - params: [] -}); - -Harness.test({ - query: userWithSchema.select(userWithSchema.id, userWithSchema.name).from(userWithSchema), - pg: { - text : 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"', - string: 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"' - }, - sqlite: { - text : 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"', - string: 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"' - }, - mysql: { - text : 'SELECT `staging`.`user`.`id`, `staging`.`user`.`name` FROM `staging`.`user`', - string: 'SELECT `staging`.`user`.`id`, `staging`.`user`.`name` FROM `staging`.`user`' - }, - mssql: { - text : 'SELECT [staging].[user].[id], [staging].[user].[name] FROM [staging].[user]', - string: 'SELECT [staging].[user].[id], [staging].[user].[name] FROM [staging].[user]' - }, - oracle: { - text : 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"', - string: 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"' - }, - params: [] -}); - -var uws = userWithSchema.as('uws'); -Harness.test({ - query: uws.select(uws.name).from(uws), - pg: { - text : 'SELECT "uws"."name" FROM "staging"."user" AS "uws"', - string: 'SELECT "uws"."name" FROM "staging"."user" AS "uws"' - }, - sqlite: { - text : 'SELECT "uws"."name" FROM "staging"."user" AS "uws"', - string: 'SELECT "uws"."name" FROM "staging"."user" AS "uws"' - }, - mysql: { - text : 'SELECT `uws`.`name` FROM `staging`.`user` AS `uws`', - string: 'SELECT `uws`.`name` FROM `staging`.`user` AS `uws`' - }, - mssql: { - text : 'SELECT [uws].[name] FROM [staging].[user] AS [uws]', - string: 'SELECT [uws].[name] FROM [staging].[user] AS [uws]' - }, - oracle: { - text : 'SELECT "uws"."name" FROM "staging"."user" "uws"', - string: 'SELECT "uws"."name" FROM "staging"."user" "uws"' - }, - params: [] -}); - -var postWithSchema = Table.define({ - schema: 'dev', - name: 'post', - columns: ['id', 'userId', 'content'] -}); - -Harness.test({ - query: userWithSchema.select(userWithSchema.name, postWithSchema.content).from(userWithSchema.join(postWithSchema).on(userWithSchema.id.equals(postWithSchema.userId))), - pg: { - text : 'SELECT "staging"."user"."name", "dev"."post"."content" FROM "staging"."user" INNER JOIN "dev"."post" ON ("staging"."user"."id" = "dev"."post"."userId")', - string: 'SELECT "staging"."user"."name", "dev"."post"."content" FROM "staging"."user" INNER JOIN "dev"."post" ON ("staging"."user"."id" = "dev"."post"."userId")' - }, - sqlite: { - text : 'SELECT "staging"."user"."name", "dev"."post"."content" FROM "staging"."user" INNER JOIN "dev"."post" ON ("staging"."user"."id" = "dev"."post"."userId")', - string: 'SELECT "staging"."user"."name", "dev"."post"."content" FROM "staging"."user" INNER JOIN "dev"."post" ON ("staging"."user"."id" = "dev"."post"."userId")' - }, - mysql: { - text : 'SELECT `staging`.`user`.`name`, `dev`.`post`.`content` FROM `staging`.`user` INNER JOIN `dev`.`post` ON (`staging`.`user`.`id` = `dev`.`post`.`userId`)', - string: 'SELECT `staging`.`user`.`name`, `dev`.`post`.`content` FROM `staging`.`user` INNER JOIN `dev`.`post` ON (`staging`.`user`.`id` = `dev`.`post`.`userId`)' - }, - mssql: { - text : 'SELECT [staging].[user].[name], [dev].[post].[content] FROM [staging].[user] INNER JOIN [dev].[post] ON ([staging].[user].[id] = [dev].[post].[userId])', - string: 'SELECT [staging].[user].[name], [dev].[post].[content] FROM [staging].[user] INNER JOIN [dev].[post] ON ([staging].[user].[id] = [dev].[post].[userId])' - }, - oracle: { - text : 'SELECT "staging"."user"."name", "dev"."post"."content" FROM "staging"."user" INNER JOIN "dev"."post" ON ("staging"."user"."id" = "dev"."post"."userId")', - string: 'SELECT "staging"."user"."name", "dev"."post"."content" FROM "staging"."user" INNER JOIN "dev"."post" ON ("staging"."user"."id" = "dev"."post"."userId")' - }, - params: [] -}); - -Harness.test({ - query: uws.select(uws.name, postWithSchema.content).from(uws.join(postWithSchema).on(uws.id.equals(postWithSchema.userId))), - pg: { - text : 'SELECT "uws"."name", "dev"."post"."content" FROM "staging"."user" AS "uws" INNER JOIN "dev"."post" ON ("uws"."id" = "dev"."post"."userId")', - string: 'SELECT "uws"."name", "dev"."post"."content" FROM "staging"."user" AS "uws" INNER JOIN "dev"."post" ON ("uws"."id" = "dev"."post"."userId")' - }, - sqlite: { - text : 'SELECT "uws"."name", "dev"."post"."content" FROM "staging"."user" AS "uws" INNER JOIN "dev"."post" ON ("uws"."id" = "dev"."post"."userId")', - string: 'SELECT "uws"."name", "dev"."post"."content" FROM "staging"."user" AS "uws" INNER JOIN "dev"."post" ON ("uws"."id" = "dev"."post"."userId")' - }, - mysql: { - text : 'SELECT `uws`.`name`, `dev`.`post`.`content` FROM `staging`.`user` AS `uws` INNER JOIN `dev`.`post` ON (`uws`.`id` = `dev`.`post`.`userId`)', - string: 'SELECT `uws`.`name`, `dev`.`post`.`content` FROM `staging`.`user` AS `uws` INNER JOIN `dev`.`post` ON (`uws`.`id` = `dev`.`post`.`userId`)' - }, - mssql: { - text : 'SELECT [uws].[name], [dev].[post].[content] FROM [staging].[user] AS [uws] INNER JOIN [dev].[post] ON ([uws].[id] = [dev].[post].[userId])', - string: 'SELECT [uws].[name], [dev].[post].[content] FROM [staging].[user] AS [uws] INNER JOIN [dev].[post] ON ([uws].[id] = [dev].[post].[userId])' - }, - oracle: { - text : 'SELECT "uws"."name", "dev"."post"."content" FROM "staging"."user" "uws" INNER JOIN "dev"."post" ON ("uws"."id" = "dev"."post"."userId")', - string: 'SELECT "uws"."name", "dev"."post"."content" FROM "staging"."user" "uws" INNER JOIN "dev"."post" ON ("uws"."id" = "dev"."post"."userId")' - }, - params: [] -}); diff --git a/test/dialects/schema-tests.ts b/test/dialects/schema-tests.ts new file mode 100644 index 00000000..122f91e3 --- /dev/null +++ b/test/dialects/schema-tests.ts @@ -0,0 +1,187 @@ +import * as Harness from './support.js'; +import { Table } from '../../dist/lib.js'; + +const userWithSchema = Table.define<{ id: number; name: string }>({ + schema: 'staging', + name: 'user', + columns: ['id', 'name'] +}); + +Harness.test({ + query: userWithSchema.select(userWithSchema.id).from(userWithSchema), + pg: { + text: 'SELECT "staging"."user"."id" FROM "staging"."user"', + string: 'SELECT "staging"."user"."id" FROM "staging"."user"' + }, + sqlite: { + text: 'SELECT "staging"."user"."id" FROM "staging"."user"', + string: 'SELECT "staging"."user"."id" FROM "staging"."user"' + }, + mysql: { + text: 'SELECT `staging`.`user`.`id` FROM `staging`.`user`', + string: 'SELECT `staging`.`user`.`id` FROM `staging`.`user`' + }, + mssql: { + text: 'SELECT [staging].[user].[id] FROM [staging].[user]', + string: 'SELECT [staging].[user].[id] FROM [staging].[user]' + }, + oracle: { + text: 'SELECT "staging"."user"."id" FROM "staging"."user"', + string: 'SELECT "staging"."user"."id" FROM "staging"."user"' + }, + params: [] +}); + +Harness.test({ + query: userWithSchema.select(userWithSchema.id.count()).from(userWithSchema), + pg: { + text: 'SELECT COUNT("staging"."user"."id") AS "id_count" FROM "staging"."user"', + string: 'SELECT COUNT("staging"."user"."id") AS "id_count" FROM "staging"."user"' + }, + sqlite: { + text: 'SELECT COUNT("staging"."user"."id") AS "id_count" FROM "staging"."user"', + string: 'SELECT COUNT("staging"."user"."id") AS "id_count" FROM "staging"."user"' + }, + mysql: { + text: 'SELECT COUNT(`staging`.`user`.`id`) AS `id_count` FROM `staging`.`user`', + string: 'SELECT COUNT(`staging`.`user`.`id`) AS `id_count` FROM `staging`.`user`' + }, + mssql: { + text: 'SELECT COUNT([staging].[user].[id]) AS [id_count] FROM [staging].[user]', + string: 'SELECT COUNT([staging].[user].[id]) AS [id_count] FROM [staging].[user]' + }, + oracle: { + text: 'SELECT COUNT("staging"."user"."id") "id_count" FROM "staging"."user"', + string: 'SELECT COUNT("staging"."user"."id") "id_count" FROM "staging"."user"' + }, + params: [] +}); + +Harness.test({ + query: userWithSchema.select(userWithSchema.id, userWithSchema.name).from(userWithSchema), + pg: { + text: 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"', + string: 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"' + }, + sqlite: { + text: 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"', + string: 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"' + }, + mysql: { + text: 'SELECT `staging`.`user`.`id`, `staging`.`user`.`name` FROM `staging`.`user`', + string: 'SELECT `staging`.`user`.`id`, `staging`.`user`.`name` FROM `staging`.`user`' + }, + mssql: { + text: 'SELECT [staging].[user].[id], [staging].[user].[name] FROM [staging].[user]', + string: 'SELECT [staging].[user].[id], [staging].[user].[name] FROM [staging].[user]' + }, + oracle: { + text: 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"', + string: 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"' + }, + params: [] +}); + +const uws = userWithSchema.as('uws'); +Harness.test({ + query: uws.select(uws.name).from(uws), + pg: { + text: 'SELECT "uws"."name" FROM "staging"."user" AS "uws"', + string: 'SELECT "uws"."name" FROM "staging"."user" AS "uws"' + }, + sqlite: { + text: 'SELECT "uws"."name" FROM "staging"."user" AS "uws"', + string: 'SELECT "uws"."name" FROM "staging"."user" AS "uws"' + }, + mysql: { + text: 'SELECT `uws`.`name` FROM `staging`.`user` AS `uws`', + string: 'SELECT `uws`.`name` FROM `staging`.`user` AS `uws`' + }, + mssql: { + text: 'SELECT [uws].[name] FROM [staging].[user] AS [uws]', + string: 'SELECT [uws].[name] FROM [staging].[user] AS [uws]' + }, + oracle: { + text: 'SELECT "uws"."name" FROM "staging"."user" "uws"', + string: 'SELECT "uws"."name" FROM "staging"."user" "uws"' + }, + params: [] +}); + +const postWithSchema = Table.define<{ id: number; userId: number; content: string }>({ + schema: 'dev', + name: 'post', + columns: ['id', 'userId', 'content'] +}); + +Harness.test({ + query: userWithSchema + .select(userWithSchema.name, postWithSchema.content) + .from(userWithSchema.join(postWithSchema).on(userWithSchema.id.equals(postWithSchema.userId))), + pg: { + text: + 'SELECT "staging"."user"."name", "dev"."post"."content" FROM "staging"."user" INNER JOIN "dev"."post" ON ("staging"."user"."id" = "dev"."post"."userId")', + string: + 'SELECT "staging"."user"."name", "dev"."post"."content" FROM "staging"."user" INNER JOIN "dev"."post" ON ("staging"."user"."id" = "dev"."post"."userId")' + }, + sqlite: { + text: + 'SELECT "staging"."user"."name", "dev"."post"."content" FROM "staging"."user" INNER JOIN "dev"."post" ON ("staging"."user"."id" = "dev"."post"."userId")', + string: + 'SELECT "staging"."user"."name", "dev"."post"."content" FROM "staging"."user" INNER JOIN "dev"."post" ON ("staging"."user"."id" = "dev"."post"."userId")' + }, + mysql: { + text: + 'SELECT `staging`.`user`.`name`, `dev`.`post`.`content` FROM `staging`.`user` INNER JOIN `dev`.`post` ON (`staging`.`user`.`id` = `dev`.`post`.`userId`)', + string: + 'SELECT `staging`.`user`.`name`, `dev`.`post`.`content` FROM `staging`.`user` INNER JOIN `dev`.`post` ON (`staging`.`user`.`id` = `dev`.`post`.`userId`)' + }, + mssql: { + text: + 'SELECT [staging].[user].[name], [dev].[post].[content] FROM [staging].[user] INNER JOIN [dev].[post] ON ([staging].[user].[id] = [dev].[post].[userId])', + string: + 'SELECT [staging].[user].[name], [dev].[post].[content] FROM [staging].[user] INNER JOIN [dev].[post] ON ([staging].[user].[id] = [dev].[post].[userId])' + }, + oracle: { + text: + 'SELECT "staging"."user"."name", "dev"."post"."content" FROM "staging"."user" INNER JOIN "dev"."post" ON ("staging"."user"."id" = "dev"."post"."userId")', + string: + 'SELECT "staging"."user"."name", "dev"."post"."content" FROM "staging"."user" INNER JOIN "dev"."post" ON ("staging"."user"."id" = "dev"."post"."userId")' + }, + params: [] +}); + +Harness.test({ + query: uws.select(uws.name, postWithSchema.content).from(uws.join(postWithSchema).on(uws.id.equals(postWithSchema.userId))), + pg: { + text: + 'SELECT "uws"."name", "dev"."post"."content" FROM "staging"."user" AS "uws" INNER JOIN "dev"."post" ON ("uws"."id" = "dev"."post"."userId")', + string: + 'SELECT "uws"."name", "dev"."post"."content" FROM "staging"."user" AS "uws" INNER JOIN "dev"."post" ON ("uws"."id" = "dev"."post"."userId")' + }, + sqlite: { + text: + 'SELECT "uws"."name", "dev"."post"."content" FROM "staging"."user" AS "uws" INNER JOIN "dev"."post" ON ("uws"."id" = "dev"."post"."userId")', + string: + 'SELECT "uws"."name", "dev"."post"."content" FROM "staging"."user" AS "uws" INNER JOIN "dev"."post" ON ("uws"."id" = "dev"."post"."userId")' + }, + mysql: { + text: + 'SELECT `uws`.`name`, `dev`.`post`.`content` FROM `staging`.`user` AS `uws` INNER JOIN `dev`.`post` ON (`uws`.`id` = `dev`.`post`.`userId`)', + string: + 'SELECT `uws`.`name`, `dev`.`post`.`content` FROM `staging`.`user` AS `uws` INNER JOIN `dev`.`post` ON (`uws`.`id` = `dev`.`post`.`userId`)' + }, + mssql: { + text: + 'SELECT [uws].[name], [dev].[post].[content] FROM [staging].[user] AS [uws] INNER JOIN [dev].[post] ON ([uws].[id] = [dev].[post].[userId])', + string: + 'SELECT [uws].[name], [dev].[post].[content] FROM [staging].[user] AS [uws] INNER JOIN [dev].[post] ON ([uws].[id] = [dev].[post].[userId])' + }, + oracle: { + text: + 'SELECT "uws"."name", "dev"."post"."content" FROM "staging"."user" "uws" INNER JOIN "dev"."post" ON ("uws"."id" = "dev"."post"."userId")', + string: + 'SELECT "uws"."name", "dev"."post"."content" FROM "staging"."user" "uws" INNER JOIN "dev"."post" ON ("uws"."id" = "dev"."post"."userId")' + }, + params: [] +}); diff --git a/test/dialects/select-tests.js b/test/dialects/select-tests.js deleted file mode 100644 index 2892c8ae..00000000 --- a/test/dialects/select-tests.js +++ /dev/null @@ -1,461 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var post = Harness.definePostTable(); -var user = Harness.defineUserTable(); -var customerAlias = Harness.defineCustomerAliasTable(); -var Sql = require('../../lib'); - -Harness.test({ - query: post.select(post.id).select(post.content), - pg: { - text : 'SELECT "post"."id", "post"."content" FROM "post"', - string: 'SELECT "post"."id", "post"."content" FROM "post"' - }, - sqlite: { - text : 'SELECT "post"."id", "post"."content" FROM "post"', - string: 'SELECT "post"."id", "post"."content" FROM "post"' - }, - mysql: { - text : 'SELECT `post`.`id`, `post`.`content` FROM `post`', - string: 'SELECT `post`.`id`, `post`.`content` FROM `post`' - }, - mssql: { - text : 'SELECT [post].[id], [post].[content] FROM [post]', - string: 'SELECT [post].[id], [post].[content] FROM [post]' - }, - oracle: { - text : 'SELECT "post"."id", "post"."content" FROM "post"', - string: 'SELECT "post"."id", "post"."content" FROM "post"' - }, - params: [] -}); - -Harness.test({ - query: customerAlias.select(customerAlias.star()), - pg: { - text : 'SELECT "customer"."id" AS "id_alias", "customer"."name" AS "name_alias", "customer"."age" AS "age_alias", "customer"."income" AS "income_alias", "customer"."metadata" AS "metadata_alias" FROM "customer"', - string: 'SELECT "customer"."id" AS "id_alias", "customer"."name" AS "name_alias", "customer"."age" AS "age_alias", "customer"."income" AS "income_alias", "customer"."metadata" AS "metadata_alias" FROM "customer"' - }, - sqlite: { - text : 'SELECT "customer"."id" AS "id_alias", "customer"."name" AS "name_alias", "customer"."age" AS "age_alias", "customer"."income" AS "income_alias", "customer"."metadata" AS "metadata_alias" FROM "customer"', - string: 'SELECT "customer"."id" AS "id_alias", "customer"."name" AS "name_alias", "customer"."age" AS "age_alias", "customer"."income" AS "income_alias", "customer"."metadata" AS "metadata_alias" FROM "customer"' - }, - mysql: { - text : 'SELECT `customer`.`id` AS `id_alias`, `customer`.`name` AS `name_alias`, `customer`.`age` AS `age_alias`, `customer`.`income` AS `income_alias`, `customer`.`metadata` AS `metadata_alias` FROM `customer`', - string: 'SELECT `customer`.`id` AS `id_alias`, `customer`.`name` AS `name_alias`, `customer`.`age` AS `age_alias`, `customer`.`income` AS `income_alias`, `customer`.`metadata` AS `metadata_alias` FROM `customer`' - }, - mssql: { - text : 'SELECT [customer].[id] AS [id_alias], [customer].[name] AS [name_alias], [customer].[age] AS [age_alias], [customer].[income] AS [income_alias], [customer].[metadata] AS [metadata_alias] FROM [customer]', - string: 'SELECT [customer].[id] AS [id_alias], [customer].[name] AS [name_alias], [customer].[age] AS [age_alias], [customer].[income] AS [income_alias], [customer].[metadata] AS [metadata_alias] FROM [customer]' - }, - oracle: { - text : 'SELECT "customer"."id" "id_alias", "customer"."name" "name_alias", "customer"."age" "age_alias", "customer"."income" "income_alias", "customer"."metadata" "metadata_alias" FROM "customer"', - string: 'SELECT "customer"."id" "id_alias", "customer"."name" "name_alias", "customer"."age" "age_alias", "customer"."income" "income_alias", "customer"."metadata" "metadata_alias" FROM "customer"' - }, - params: [] -}); - -// Test that we can generate a SELECT claus without a FROM clause -Harness.test({ - query: Sql.select(), - pg: { - text : 'SELECT ', - string: 'SELECT ' - }, - sqlite: { - text : 'SELECT ', - string: 'SELECT ' - }, - mysql: { - text : 'SELECT ', - string: 'SELECT ' - }, - mssql: { - text : 'SELECT ', - string: 'SELECT ' - }, - oracle: { - text : 'SELECT ', - string: 'SELECT ' - }, - params: [] -}); - -// Test that we can generate a SELECT claus without a FROM clause -Harness.test({ - query: Sql.select("1"), - pg: { - text : 'SELECT 1', - string: 'SELECT 1' - }, - sqlite: { - text : 'SELECT 1', - string: 'SELECT 1' - }, - mysql: { - text : 'SELECT 1', - string: 'SELECT 1' - }, - mssql: { - text : 'SELECT 1', - string: 'SELECT 1' - }, - oracle: { - text : 'SELECT 1', - string: 'SELECT 1' - }, - params: [] -}); - -Harness.test({ - query: Sql.select("1").where("1=1"), - pg: { - text : 'SELECT 1 WHERE (1=1)', - string: 'SELECT 1 WHERE (1=1)' - }, - sqlite: { - text : 'SELECT 1 WHERE (1=1)', - string: 'SELECT 1 WHERE (1=1)' - }, - mysql: { - text : 'SELECT 1 WHERE (1=1)', - string: 'SELECT 1 WHERE (1=1)' - }, - mssql: { - text : 'SELECT 1 WHERE (1=1)', - string: 'SELECT 1 WHERE (1=1)' - }, - oracle: { - text : 'SELECT 1 WHERE (1=1)', - string: 'SELECT 1 WHERE (1=1)' - }, - params: [] -}); - -Harness.test({ - query: Sql.select(post.select(post.id)), - pg: { - text : 'SELECT (SELECT "post"."id" FROM "post")', - string: 'SELECT (SELECT "post"."id" FROM "post")' - }, - sqlite: { - text : 'SELECT (SELECT "post"."id" FROM "post")', - string: 'SELECT (SELECT "post"."id" FROM "post")' - }, - mysql: { - text : 'SELECT (SELECT `post`.`id` FROM `post`)', - string: 'SELECT (SELECT `post`.`id` FROM `post`)' - }, - mssql: { - text : 'SELECT (SELECT [post].[id] FROM [post])', - string: 'SELECT (SELECT [post].[id] FROM [post])' - }, - oracle: { - text : 'SELECT (SELECT "post"."id" FROM "post")', - string: 'SELECT (SELECT "post"."id" FROM "post")' - }, - params: [] -}); - -Harness.test({ - query: Sql.select(post.select(post.content).plus(post.select(post.content))), - pg: { - text : 'SELECT ((SELECT "post"."content" FROM "post") + (SELECT "post"."content" FROM "post"))', - string: 'SELECT ((SELECT "post"."content" FROM "post") + (SELECT "post"."content" FROM "post"))' - }, - sqlite: { - text : 'SELECT ((SELECT "post"."content" FROM "post") + (SELECT "post"."content" FROM "post"))', - string: 'SELECT ((SELECT "post"."content" FROM "post") + (SELECT "post"."content" FROM "post"))' - }, - mysql: { - text : 'SELECT ((SELECT `post`.`content` FROM `post`) + (SELECT `post`.`content` FROM `post`))', - string: 'SELECT ((SELECT `post`.`content` FROM `post`) + (SELECT `post`.`content` FROM `post`))' - }, - mssql: { - text : 'SELECT ((SELECT [post].[content] FROM [post]) + (SELECT [post].[content] FROM [post]))', - string: 'SELECT ((SELECT [post].[content] FROM [post]) + (SELECT [post].[content] FROM [post]))' - }, - oracle: { - text : 'SELECT ((SELECT "post"."content" FROM "post") + (SELECT "post"."content" FROM "post"))', - string: 'SELECT ((SELECT "post"."content" FROM "post") + (SELECT "post"."content" FROM "post"))' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.id.as('col1')), - pg: { - text : 'SELECT "post"."id" AS "col1" FROM "post"', - string: 'SELECT "post"."id" AS "col1" FROM "post"' - }, - sqlite: { - text : 'SELECT "post"."id" AS "col1" FROM "post"', - string: 'SELECT "post"."id" AS "col1" FROM "post"' - }, - mysql: { - text : 'SELECT `post`.`id` AS `col1` FROM `post`', - string: 'SELECT `post`.`id` AS `col1` FROM `post`' - }, - mssql: { - text : 'SELECT [post].[id] AS [col1] FROM [post]', - string: 'SELECT [post].[id] AS [col1] FROM [post]' - }, - oracle: { - text : 'SELECT "post"."id" "col1" FROM "post"', - string: 'SELECT "post"."id" "col1" FROM "post"' - }, - params: [] -}); - -Harness.test({ - query: post.select(Sql.constant(4)), - pg: { - text : 'SELECT $1 FROM "post"', - string: 'SELECT 4 FROM "post"' - }, - sqlite: { - text : 'SELECT $1 FROM "post"', - string: 'SELECT 4 FROM "post"' - }, - mysql: { - text : 'SELECT ? FROM `post`', - string: 'SELECT 4 FROM `post`' - }, - mssql: { - text : 'SELECT @1 FROM [post]', - string: 'SELECT 4 FROM [post]' - }, - oracle: { - text : 'SELECT :1 FROM "post"', - string: 'SELECT 4 FROM "post"' - }, - params: [4] -}); - -Harness.test({ - query: post.select(post.id,Sql.constant(4)), - pg: { - text : 'SELECT "post"."id", $1 FROM "post"', - string: 'SELECT "post"."id", 4 FROM "post"' - }, - sqlite: { - text : 'SELECT "post"."id", $1 FROM "post"', - string: 'SELECT "post"."id", 4 FROM "post"' - }, - mysql: { - text : 'SELECT `post`.`id`, ? FROM `post`', - string: 'SELECT `post`.`id`, 4 FROM `post`' - }, - mssql: { - text : 'SELECT [post].[id], @1 FROM [post]', - string: 'SELECT [post].[id], 4 FROM [post]' - }, - oracle: { - text : 'SELECT "post"."id", :1 FROM "post"', - string: 'SELECT "post"."id", 4 FROM "post"' - }, - params: [4] -}); - -Harness.test({ - query: post.select(Sql.constant(4).as('col1')), - pg: { - text : 'SELECT $1 AS "col1" FROM "post"', - string: 'SELECT 4 AS "col1" FROM "post"' - }, - sqlite: { - text : 'SELECT $1 AS "col1" FROM "post"', - string: 'SELECT 4 AS "col1" FROM "post"' - }, - mysql: { - text : 'SELECT ? AS `col1` FROM `post`', - string: 'SELECT 4 AS `col1` FROM `post`' - }, - mssql: { - text : 'SELECT @1 AS [col1] FROM [post]', - string: 'SELECT 4 AS [col1] FROM [post]' - }, - oracle: { - text : 'SELECT :1 "col1" FROM "post"', - string: 'SELECT 4 "col1" FROM "post"' - }, - params: [4] -}); - -Harness.test({ - query: post.select(Sql.constant(4).plus(5)), - pg: { - text : 'SELECT ($1 + $2) FROM "post"', - string: 'SELECT (4 + 5) FROM "post"' - }, - sqlite: { - text : 'SELECT ($1 + $2) FROM "post"', - string: 'SELECT (4 + 5) FROM "post"' - }, - mysql: { - text : 'SELECT (? + ?) FROM `post`', - string: 'SELECT (4 + 5) FROM `post`' - }, - mssql: { - text : 'SELECT (@1 + @2) FROM [post]', - string: 'SELECT (4 + 5) FROM [post]' - }, - oracle: { - text : 'SELECT (:1 + :2) FROM "post"', - string: 'SELECT (4 + 5) FROM "post"' - }, - params: [4,5] -}); - -Harness.test({ - query: post.select(Sql.constant(4).plus(5).as('col1')), - pg: { - text : 'SELECT ($1 + $2) AS "col1" FROM "post"', - string: 'SELECT (4 + 5) AS "col1" FROM "post"' - }, - sqlite: { - text : 'SELECT ($1 + $2) AS "col1" FROM "post"', - string: 'SELECT (4 + 5) AS "col1" FROM "post"' - }, - mysql: { - text : 'SELECT (? + ?) AS `col1` FROM `post`', - string: 'SELECT (4 + 5) AS `col1` FROM `post`' - }, - mssql: { - text : 'SELECT (@1 + @2) AS [col1] FROM [post]', - string: 'SELECT (4 + 5) AS [col1] FROM [post]' - }, - oracle: { - text : 'SELECT (:1 + :2) "col1" FROM "post"', - string: 'SELECT (4 + 5) "col1" FROM "post"' - }, - params: [4,5] -}); - -Harness.test({ - query: post.select(Sql.constant(4),Sql.constant("abc"),Sql.constant(true)), - pg: { - text : 'SELECT $1, $2, $3 FROM "post"', - string: 'SELECT 4, \'abc\', TRUE FROM "post"' - }, - sqlite: { - text : 'SELECT $1, $2, $3 FROM "post"', - string: 'SELECT 4, \'abc\', 1 FROM "post"' - }, - mysql: { - text : 'SELECT ?, ?, ? FROM `post`', - string: 'SELECT 4, \'abc\', TRUE FROM `post`' - }, - mssql: { - text : 'SELECT @1, @2, @3 FROM [post]', - string: 'SELECT 4, \'abc\', TRUE FROM [post]' - }, - oracle: { - text : 'SELECT :1, :2, :3 FROM "post"', - string: 'SELECT 4, \'abc\', TRUE FROM "post"' - }, - params: [4,'abc',true] -}); - -Harness.test({ - query: post.select(Sql.constant(1).sum()), - pg: { - text : 'SELECT SUM($1) AS "constant_sum" FROM "post"', - string: 'SELECT SUM(1) AS "constant_sum" FROM "post"' - }, - sqlite: { - text : 'SELECT SUM($1) AS "constant_sum" FROM "post"', - string: 'SELECT SUM(1) AS "constant_sum" FROM "post"' - }, - mysql: { - text : 'SELECT SUM(?) AS `constant_sum` FROM `post`', - string: 'SELECT SUM(1) AS `constant_sum` FROM `post`' - }, - mssql: { - text : 'SELECT SUM(@1) AS [constant_sum] FROM [post]', - string: 'SELECT SUM(1) AS [constant_sum] FROM [post]' - }, - oracle: { - text : 'SELECT SUM(:1) "constant_sum" FROM "post"', - string: 'SELECT SUM(1) "constant_sum" FROM "post"' - }, - params: [1] -}); - -Harness.test({ - query: Sql.select(post.select(post.id).as("column1")), - pg: { - text : 'SELECT (SELECT "post"."id" FROM "post") AS "column1"', - string: 'SELECT (SELECT "post"."id" FROM "post") AS "column1"' - }, - sqlite: { - text : 'SELECT (SELECT "post"."id" FROM "post") AS "column1"', - string: 'SELECT (SELECT "post"."id" FROM "post") AS "column1"' - }, - mysql: { - text : 'SELECT (SELECT `post`.`id` FROM `post`) AS `column1`', - string: 'SELECT (SELECT `post`.`id` FROM `post`) AS `column1`' - }, - mssql: { - text : 'SELECT (SELECT [post].[id] FROM [post]) AS [column1]', - string: 'SELECT (SELECT [post].[id] FROM [post]) AS [column1]' - }, - oracle: { - text : 'SELECT (SELECT "post"."id" FROM "post") "column1"', - string: 'SELECT (SELECT "post"."id" FROM "post") "column1"' - }, - params: [] -}); - -Harness.test({ - query: Sql.select(post.select(post.count()).as("column1")), - pg: { - text : 'SELECT (SELECT COUNT("post".*) AS "post_count" FROM "post") AS "column1"', - string: 'SELECT (SELECT COUNT("post".*) AS "post_count" FROM "post") AS "column1"' - }, - sqlite: { - text : 'SELECT (SELECT COUNT("post".*) AS "post_count" FROM "post") AS "column1"', - string: 'SELECT (SELECT COUNT("post".*) AS "post_count" FROM "post") AS "column1"' - }, - mysql: { - text : 'SELECT (SELECT COUNT(*) AS `post_count` FROM `post`) AS `column1`', - string: 'SELECT (SELECT COUNT(*) AS `post_count` FROM `post`) AS `column1`' - }, - mssql: { - text : 'SELECT (SELECT COUNT(*) AS [post_count] FROM [post]) AS [column1]', - string: 'SELECT (SELECT COUNT(*) AS [post_count] FROM [post]) AS [column1]' - }, - oracle: { - text : 'SELECT (SELECT COUNT(*) "post_count" FROM "post") "column1"', - string: 'SELECT (SELECT COUNT(*) "post_count" FROM "post") "column1"' - }, - params: [] -}); - -Harness.test({ - query: Sql.select(post.select(post.id).as("column1"),user.select(user.id).as("column2")), - pg: { - text : 'SELECT (SELECT "post"."id" FROM "post") AS "column1", (SELECT "user"."id" FROM "user") AS "column2"', - string: 'SELECT (SELECT "post"."id" FROM "post") AS "column1", (SELECT "user"."id" FROM "user") AS "column2"' - }, - sqlite: { - text : 'SELECT (SELECT "post"."id" FROM "post") AS "column1", (SELECT "user"."id" FROM "user") AS "column2"', - string: 'SELECT (SELECT "post"."id" FROM "post") AS "column1", (SELECT "user"."id" FROM "user") AS "column2"' - }, - mysql: { - text : 'SELECT (SELECT `post`.`id` FROM `post`) AS `column1`, (SELECT `user`.`id` FROM `user`) AS `column2`', - string: 'SELECT (SELECT `post`.`id` FROM `post`) AS `column1`, (SELECT `user`.`id` FROM `user`) AS `column2`' - }, - mssql: { - text : 'SELECT (SELECT [post].[id] FROM [post]) AS [column1], (SELECT [user].[id] FROM [user]) AS [column2]', - string: 'SELECT (SELECT [post].[id] FROM [post]) AS [column1], (SELECT [user].[id] FROM [user]) AS [column2]' - }, - oracle: { - text : 'SELECT (SELECT "post"."id" FROM "post") "column1", (SELECT "user"."id" FROM "user") "column2"', - string: 'SELECT (SELECT "post"."id" FROM "post") "column1", (SELECT "user"."id" FROM "user") "column2"' - }, - params: [] -}); - - diff --git a/test/dialects/select-tests.ts b/test/dialects/select-tests.ts new file mode 100644 index 00000000..de636879 --- /dev/null +++ b/test/dialects/select-tests.ts @@ -0,0 +1,473 @@ +import * as Harness from './support.js'; +import { Sql } from '../../dist/lib.js'; +const post = Harness.definePostTable(); +const user = Harness.defineUserTable(); +const customerAlias = Harness.defineCustomerAliasTable(); +const instance = new Sql('postgres'); + +Harness.test({ + query: post.select(post.id).select(post.content), + pg: { + text: 'SELECT "post"."id", "post"."content" FROM "post"', + string: 'SELECT "post"."id", "post"."content" FROM "post"' + }, + sqlite: { + text: 'SELECT "post"."id", "post"."content" FROM "post"', + string: 'SELECT "post"."id", "post"."content" FROM "post"' + }, + mysql: { + text: 'SELECT `post`.`id`, `post`.`content` FROM `post`', + string: 'SELECT `post`.`id`, `post`.`content` FROM `post`' + }, + mssql: { + text: 'SELECT [post].[id], [post].[content] FROM [post]', + string: 'SELECT [post].[id], [post].[content] FROM [post]' + }, + oracle: { + text: 'SELECT "post"."id", "post"."content" FROM "post"', + string: 'SELECT "post"."id", "post"."content" FROM "post"' + }, + params: [] +}); + +Harness.test({ + query: customerAlias.select(customerAlias.star()), + pg: { + text: + 'SELECT "customer"."id" AS "id_alias", "customer"."name" AS "name_alias", "customer"."age" AS "age_alias", "customer"."income" AS "income_alias", "customer"."metadata" AS "metadata_alias" FROM "customer"', + string: + 'SELECT "customer"."id" AS "id_alias", "customer"."name" AS "name_alias", "customer"."age" AS "age_alias", "customer"."income" AS "income_alias", "customer"."metadata" AS "metadata_alias" FROM "customer"' + }, + sqlite: { + text: + 'SELECT "customer"."id" AS "id_alias", "customer"."name" AS "name_alias", "customer"."age" AS "age_alias", "customer"."income" AS "income_alias", "customer"."metadata" AS "metadata_alias" FROM "customer"', + string: + 'SELECT "customer"."id" AS "id_alias", "customer"."name" AS "name_alias", "customer"."age" AS "age_alias", "customer"."income" AS "income_alias", "customer"."metadata" AS "metadata_alias" FROM "customer"' + }, + mysql: { + text: + 'SELECT `customer`.`id` AS `id_alias`, `customer`.`name` AS `name_alias`, `customer`.`age` AS `age_alias`, `customer`.`income` AS `income_alias`, `customer`.`metadata` AS `metadata_alias` FROM `customer`', + string: + 'SELECT `customer`.`id` AS `id_alias`, `customer`.`name` AS `name_alias`, `customer`.`age` AS `age_alias`, `customer`.`income` AS `income_alias`, `customer`.`metadata` AS `metadata_alias` FROM `customer`' + }, + mssql: { + text: + 'SELECT [customer].[id] AS [id_alias], [customer].[name] AS [name_alias], [customer].[age] AS [age_alias], [customer].[income] AS [income_alias], [customer].[metadata] AS [metadata_alias] FROM [customer]', + string: + 'SELECT [customer].[id] AS [id_alias], [customer].[name] AS [name_alias], [customer].[age] AS [age_alias], [customer].[income] AS [income_alias], [customer].[metadata] AS [metadata_alias] FROM [customer]' + }, + oracle: { + text: + 'SELECT "customer"."id" "id_alias", "customer"."name" "name_alias", "customer"."age" "age_alias", "customer"."income" "income_alias", "customer"."metadata" "metadata_alias" FROM "customer"', + string: + 'SELECT "customer"."id" "id_alias", "customer"."name" "name_alias", "customer"."age" "age_alias", "customer"."income" "income_alias", "customer"."metadata" "metadata_alias" FROM "customer"' + }, + params: [] +}); + +// Test that we can generate a SELECT claus without a FROM clause +Harness.test({ + query: instance.select(), + pg: { + text: 'SELECT ', + string: 'SELECT ' + }, + sqlite: { + text: 'SELECT ', + string: 'SELECT ' + }, + mysql: { + text: 'SELECT ', + string: 'SELECT ' + }, + mssql: { + text: 'SELECT ', + string: 'SELECT ' + }, + oracle: { + text: 'SELECT ', + string: 'SELECT ' + }, + params: [] +}); + +// Test that we can generate a SELECT claus without a FROM clause +Harness.test({ + query: instance.select('1'), + pg: { + text: 'SELECT 1', + string: 'SELECT 1' + }, + sqlite: { + text: 'SELECT 1', + string: 'SELECT 1' + }, + mysql: { + text: 'SELECT 1', + string: 'SELECT 1' + }, + mssql: { + text: 'SELECT 1', + string: 'SELECT 1' + }, + oracle: { + text: 'SELECT 1', + string: 'SELECT 1' + }, + params: [] +}); + +Harness.test({ + query: instance.select('1').where('1=1'), + pg: { + text: 'SELECT 1 WHERE (1=1)', + string: 'SELECT 1 WHERE (1=1)' + }, + sqlite: { + text: 'SELECT 1 WHERE (1=1)', + string: 'SELECT 1 WHERE (1=1)' + }, + mysql: { + text: 'SELECT 1 WHERE (1=1)', + string: 'SELECT 1 WHERE (1=1)' + }, + mssql: { + text: 'SELECT 1 WHERE (1=1)', + string: 'SELECT 1 WHERE (1=1)' + }, + oracle: { + text: 'SELECT 1 WHERE (1=1)', + string: 'SELECT 1 WHERE (1=1)' + }, + params: [] +}); + +Harness.test({ + query: instance.select(post.select(post.id)), + pg: { + text: 'SELECT (SELECT "post"."id" FROM "post")', + string: 'SELECT (SELECT "post"."id" FROM "post")' + }, + sqlite: { + text: 'SELECT (SELECT "post"."id" FROM "post")', + string: 'SELECT (SELECT "post"."id" FROM "post")' + }, + mysql: { + text: 'SELECT (SELECT `post`.`id` FROM `post`)', + string: 'SELECT (SELECT `post`.`id` FROM `post`)' + }, + mssql: { + text: 'SELECT (SELECT [post].[id] FROM [post])', + string: 'SELECT (SELECT [post].[id] FROM [post])' + }, + oracle: { + text: 'SELECT (SELECT "post"."id" FROM "post")', + string: 'SELECT (SELECT "post"."id" FROM "post")' + }, + params: [] +}); + +Harness.test({ + query: instance.select(post.select(post.content).plus(post.select(post.content))), + pg: { + text: 'SELECT ((SELECT "post"."content" FROM "post") + (SELECT "post"."content" FROM "post"))', + string: 'SELECT ((SELECT "post"."content" FROM "post") + (SELECT "post"."content" FROM "post"))' + }, + sqlite: { + text: 'SELECT ((SELECT "post"."content" FROM "post") + (SELECT "post"."content" FROM "post"))', + string: 'SELECT ((SELECT "post"."content" FROM "post") + (SELECT "post"."content" FROM "post"))' + }, + mysql: { + text: 'SELECT ((SELECT `post`.`content` FROM `post`) + (SELECT `post`.`content` FROM `post`))', + string: 'SELECT ((SELECT `post`.`content` FROM `post`) + (SELECT `post`.`content` FROM `post`))' + }, + mssql: { + text: 'SELECT ((SELECT [post].[content] FROM [post]) + (SELECT [post].[content] FROM [post]))', + string: 'SELECT ((SELECT [post].[content] FROM [post]) + (SELECT [post].[content] FROM [post]))' + }, + oracle: { + text: 'SELECT ((SELECT "post"."content" FROM "post") + (SELECT "post"."content" FROM "post"))', + string: 'SELECT ((SELECT "post"."content" FROM "post") + (SELECT "post"."content" FROM "post"))' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.id.as('col1')), + pg: { + text: 'SELECT "post"."id" AS "col1" FROM "post"', + string: 'SELECT "post"."id" AS "col1" FROM "post"' + }, + sqlite: { + text: 'SELECT "post"."id" AS "col1" FROM "post"', + string: 'SELECT "post"."id" AS "col1" FROM "post"' + }, + mysql: { + text: 'SELECT `post`.`id` AS `col1` FROM `post`', + string: 'SELECT `post`.`id` AS `col1` FROM `post`' + }, + mssql: { + text: 'SELECT [post].[id] AS [col1] FROM [post]', + string: 'SELECT [post].[id] AS [col1] FROM [post]' + }, + oracle: { + text: 'SELECT "post"."id" "col1" FROM "post"', + string: 'SELECT "post"."id" "col1" FROM "post"' + }, + params: [] +}); + +Harness.test({ + query: post.select(instance.constant(4)), + pg: { + text: 'SELECT $1 FROM "post"', + string: 'SELECT 4 FROM "post"' + }, + sqlite: { + text: 'SELECT $1 FROM "post"', + string: 'SELECT 4 FROM "post"' + }, + mysql: { + text: 'SELECT ? FROM `post`', + string: 'SELECT 4 FROM `post`' + }, + mssql: { + text: 'SELECT @1 FROM [post]', + string: 'SELECT 4 FROM [post]' + }, + oracle: { + text: 'SELECT :1 FROM "post"', + string: 'SELECT 4 FROM "post"' + }, + params: [4] +}); + +Harness.test({ + query: post.select(post.id, instance.constant(4)), + pg: { + text: 'SELECT "post"."id", $1 FROM "post"', + string: 'SELECT "post"."id", 4 FROM "post"' + }, + sqlite: { + text: 'SELECT "post"."id", $1 FROM "post"', + string: 'SELECT "post"."id", 4 FROM "post"' + }, + mysql: { + text: 'SELECT `post`.`id`, ? FROM `post`', + string: 'SELECT `post`.`id`, 4 FROM `post`' + }, + mssql: { + text: 'SELECT [post].[id], @1 FROM [post]', + string: 'SELECT [post].[id], 4 FROM [post]' + }, + oracle: { + text: 'SELECT "post"."id", :1 FROM "post"', + string: 'SELECT "post"."id", 4 FROM "post"' + }, + params: [4] +}); + +Harness.test({ + query: post.select(instance.constant(4).as('col1')), + pg: { + text: 'SELECT $1 AS "col1" FROM "post"', + string: 'SELECT 4 AS "col1" FROM "post"' + }, + sqlite: { + text: 'SELECT $1 AS "col1" FROM "post"', + string: 'SELECT 4 AS "col1" FROM "post"' + }, + mysql: { + text: 'SELECT ? AS `col1` FROM `post`', + string: 'SELECT 4 AS `col1` FROM `post`' + }, + mssql: { + text: 'SELECT @1 AS [col1] FROM [post]', + string: 'SELECT 4 AS [col1] FROM [post]' + }, + oracle: { + text: 'SELECT :1 "col1" FROM "post"', + string: 'SELECT 4 "col1" FROM "post"' + }, + params: [4] +}); + +Harness.test({ + query: post.select(instance.constant(4).plus(5)), + pg: { + text: 'SELECT ($1 + $2) FROM "post"', + string: 'SELECT (4 + 5) FROM "post"' + }, + sqlite: { + text: 'SELECT ($1 + $2) FROM "post"', + string: 'SELECT (4 + 5) FROM "post"' + }, + mysql: { + text: 'SELECT (? + ?) FROM `post`', + string: 'SELECT (4 + 5) FROM `post`' + }, + mssql: { + text: 'SELECT (@1 + @2) FROM [post]', + string: 'SELECT (4 + 5) FROM [post]' + }, + oracle: { + text: 'SELECT (:1 + :2) FROM "post"', + string: 'SELECT (4 + 5) FROM "post"' + }, + params: [4, 5] +}); + +Harness.test({ + query: post.select( + instance + .constant(4) + .plus(5) + .as('col1') + ), + pg: { + text: 'SELECT ($1 + $2) AS "col1" FROM "post"', + string: 'SELECT (4 + 5) AS "col1" FROM "post"' + }, + sqlite: { + text: 'SELECT ($1 + $2) AS "col1" FROM "post"', + string: 'SELECT (4 + 5) AS "col1" FROM "post"' + }, + mysql: { + text: 'SELECT (? + ?) AS `col1` FROM `post`', + string: 'SELECT (4 + 5) AS `col1` FROM `post`' + }, + mssql: { + text: 'SELECT (@1 + @2) AS [col1] FROM [post]', + string: 'SELECT (4 + 5) AS [col1] FROM [post]' + }, + oracle: { + text: 'SELECT (:1 + :2) "col1" FROM "post"', + string: 'SELECT (4 + 5) "col1" FROM "post"' + }, + params: [4, 5] +}); + +Harness.test({ + query: post.select(instance.constant(4), instance.constant('abc'), instance.constant(true)), + pg: { + text: 'SELECT $1, $2, $3 FROM "post"', + string: 'SELECT 4, \'abc\', TRUE FROM "post"' + }, + sqlite: { + text: 'SELECT $1, $2, $3 FROM "post"', + string: 'SELECT 4, \'abc\', 1 FROM "post"' + }, + mysql: { + text: 'SELECT ?, ?, ? FROM `post`', + string: "SELECT 4, 'abc', TRUE FROM `post`" + }, + mssql: { + text: 'SELECT @1, @2, @3 FROM [post]', + string: "SELECT 4, 'abc', TRUE FROM [post]" + }, + oracle: { + text: 'SELECT :1, :2, :3 FROM "post"', + string: 'SELECT 4, \'abc\', TRUE FROM "post"' + }, + params: [4, 'abc', true] +}); + +Harness.test({ + query: post.select(instance.constant(1).sum()), + pg: { + text: 'SELECT SUM($1) AS "constant_sum" FROM "post"', + string: 'SELECT SUM(1) AS "constant_sum" FROM "post"' + }, + sqlite: { + text: 'SELECT SUM($1) AS "constant_sum" FROM "post"', + string: 'SELECT SUM(1) AS "constant_sum" FROM "post"' + }, + mysql: { + text: 'SELECT SUM(?) AS `constant_sum` FROM `post`', + string: 'SELECT SUM(1) AS `constant_sum` FROM `post`' + }, + mssql: { + text: 'SELECT SUM(@1) AS [constant_sum] FROM [post]', + string: 'SELECT SUM(1) AS [constant_sum] FROM [post]' + }, + oracle: { + text: 'SELECT SUM(:1) "constant_sum" FROM "post"', + string: 'SELECT SUM(1) "constant_sum" FROM "post"' + }, + params: [1] +}); + +Harness.test({ + query: instance.select(post.select(post.id).as('column1')), + pg: { + text: 'SELECT (SELECT "post"."id" FROM "post") AS "column1"', + string: 'SELECT (SELECT "post"."id" FROM "post") AS "column1"' + }, + sqlite: { + text: 'SELECT (SELECT "post"."id" FROM "post") AS "column1"', + string: 'SELECT (SELECT "post"."id" FROM "post") AS "column1"' + }, + mysql: { + text: 'SELECT (SELECT `post`.`id` FROM `post`) AS `column1`', + string: 'SELECT (SELECT `post`.`id` FROM `post`) AS `column1`' + }, + mssql: { + text: 'SELECT (SELECT [post].[id] FROM [post]) AS [column1]', + string: 'SELECT (SELECT [post].[id] FROM [post]) AS [column1]' + }, + oracle: { + text: 'SELECT (SELECT "post"."id" FROM "post") "column1"', + string: 'SELECT (SELECT "post"."id" FROM "post") "column1"' + }, + params: [] +}); + +Harness.test({ + query: instance.select(post.select(post.count()).as('column1')), + pg: { + text: 'SELECT (SELECT COUNT("post".*) AS "post_count" FROM "post") AS "column1"', + string: 'SELECT (SELECT COUNT("post".*) AS "post_count" FROM "post") AS "column1"' + }, + sqlite: { + text: 'SELECT (SELECT COUNT("post".*) AS "post_count" FROM "post") AS "column1"', + string: 'SELECT (SELECT COUNT("post".*) AS "post_count" FROM "post") AS "column1"' + }, + mysql: { + text: 'SELECT (SELECT COUNT(*) AS `post_count` FROM `post`) AS `column1`', + string: 'SELECT (SELECT COUNT(*) AS `post_count` FROM `post`) AS `column1`' + }, + mssql: { + text: 'SELECT (SELECT COUNT(*) AS [post_count] FROM [post]) AS [column1]', + string: 'SELECT (SELECT COUNT(*) AS [post_count] FROM [post]) AS [column1]' + }, + oracle: { + text: 'SELECT (SELECT COUNT(*) "post_count" FROM "post") "column1"', + string: 'SELECT (SELECT COUNT(*) "post_count" FROM "post") "column1"' + }, + params: [] +}); + +Harness.test({ + query: instance.select(post.select(post.id).as('column1'), user.select(user.id).as('column2')), + pg: { + text: 'SELECT (SELECT "post"."id" FROM "post") AS "column1", (SELECT "user"."id" FROM "user") AS "column2"', + string: 'SELECT (SELECT "post"."id" FROM "post") AS "column1", (SELECT "user"."id" FROM "user") AS "column2"' + }, + sqlite: { + text: 'SELECT (SELECT "post"."id" FROM "post") AS "column1", (SELECT "user"."id" FROM "user") AS "column2"', + string: 'SELECT (SELECT "post"."id" FROM "post") AS "column1", (SELECT "user"."id" FROM "user") AS "column2"' + }, + mysql: { + text: 'SELECT (SELECT `post`.`id` FROM `post`) AS `column1`, (SELECT `user`.`id` FROM `user`) AS `column2`', + string: 'SELECT (SELECT `post`.`id` FROM `post`) AS `column1`, (SELECT `user`.`id` FROM `user`) AS `column2`' + }, + mssql: { + text: 'SELECT (SELECT [post].[id] FROM [post]) AS [column1], (SELECT [user].[id] FROM [user]) AS [column2]', + string: 'SELECT (SELECT [post].[id] FROM [post]) AS [column1], (SELECT [user].[id] FROM [user]) AS [column2]' + }, + oracle: { + text: 'SELECT (SELECT "post"."id" FROM "post") "column1", (SELECT "user"."id" FROM "user") "column2"', + string: 'SELECT (SELECT "post"."id" FROM "post") "column1", (SELECT "user"."id" FROM "user") "column2"' + }, + params: [] +}); diff --git a/test/dialects/shortcut-tests.js b/test/dialects/shortcut-tests.js deleted file mode 100644 index 35c9a90b..00000000 --- a/test/dialects/shortcut-tests.js +++ /dev/null @@ -1,161 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var user = Harness.defineUserTable(); -var post = Harness.definePostTable(); - -// shortcut: 'select * from ' -Harness.test({ - query: user, - pg: { - text : 'SELECT "user".* FROM "user"', - string: 'SELECT "user".* FROM "user"' - }, - sqlite: { - text : 'SELECT "user".* FROM "user"', - string: 'SELECT "user".* FROM "user"' - }, - mysql: { - text : 'SELECT `user`.* FROM `user`', - string: 'SELECT `user`.* FROM `user`' - }, - mssql: { - text : 'SELECT [user].* FROM [user]', - string: 'SELECT [user].* FROM [user]' - }, - oracle: { - text : 'SELECT "user".* FROM "user"', - string: 'SELECT "user".* FROM "user"' - }, - params: [] -}); - -Harness.test({ - query: user.where(user.name.equals(3)), - pg: { - text : 'SELECT * FROM "user" WHERE ("user"."name" = $1)', - string: 'SELECT * FROM "user" WHERE ("user"."name" = 3)' - }, - sqlite: { - text : 'SELECT * FROM "user" WHERE ("user"."name" = $1)', - string: 'SELECT * FROM "user" WHERE ("user"."name" = 3)' - }, - mysql: { - text : 'SELECT * FROM `user` WHERE (`user`.`name` = ?)', - string: 'SELECT * FROM `user` WHERE (`user`.`name` = 3)' - }, - mssql: { - text : 'SELECT * FROM [user] WHERE ([user].[name] = @1)', - string: 'SELECT * FROM [user] WHERE ([user].[name] = 3)' - }, - oracle: { - text : 'SELECT * FROM "user" WHERE ("user"."name" = :1)', - string: 'SELECT * FROM "user" WHERE ("user"."name" = 3)' - }, - params: [3] -}); - -Harness.test({ - query: user.where(user.name.equals(3)).where(user.id.equals(1)), - pg: { - text : 'SELECT * FROM "user" WHERE (("user"."name" = $1) AND ("user"."id" = $2))', - string: 'SELECT * FROM "user" WHERE (("user"."name" = 3) AND ("user"."id" = 1))' - }, - sqlite: { - text : 'SELECT * FROM "user" WHERE (("user"."name" = $1) AND ("user"."id" = $2))', - string: 'SELECT * FROM "user" WHERE (("user"."name" = 3) AND ("user"."id" = 1))' - }, - mysql: { - text : 'SELECT * FROM `user` WHERE ((`user`.`name` = ?) AND (`user`.`id` = ?))', - string: 'SELECT * FROM `user` WHERE ((`user`.`name` = 3) AND (`user`.`id` = 1))' - }, - mssql: { - text : 'SELECT * FROM [user] WHERE (([user].[name] = @1) AND ([user].[id] = @2))', - string: 'SELECT * FROM [user] WHERE (([user].[name] = 3) AND ([user].[id] = 1))' - }, - oracle: { - text : 'SELECT * FROM "user" WHERE (("user"."name" = :1) AND ("user"."id" = :2))', - string: 'SELECT * FROM "user" WHERE (("user"."name" = 3) AND ("user"."id" = 1))' - }, - params: [3, 1] -}); - -// shortcut: no 'from' -Harness.test({ - query: post.select(post.content), - pg: { - text : 'SELECT "post"."content" FROM "post"', - string: 'SELECT "post"."content" FROM "post"' - }, - sqlite: { - text : 'SELECT "post"."content" FROM "post"', - string: 'SELECT "post"."content" FROM "post"' - }, - mysql: { - text : 'SELECT `post`.`content` FROM `post`', - string: 'SELECT `post`.`content` FROM `post`' - }, - mssql: { - text : 'SELECT [post].[content] FROM [post]', - string: 'SELECT [post].[content] FROM [post]' - }, - oracle: { - text : 'SELECT "post"."content" FROM "post"', - string: 'SELECT "post"."content" FROM "post"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.content).where(post.userId.equals(1)), - pg: { - text : 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = $1)', - string: 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = 1)' - }, - sqlite: { - text : 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = $1)', - string: 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = 1)' - }, - mysql: { - text : 'SELECT `post`.`content` FROM `post` WHERE (`post`.`userId` = ?)', - string: 'SELECT `post`.`content` FROM `post` WHERE (`post`.`userId` = 1)' - }, - mssql: { - text : 'SELECT [post].[content] FROM [post] WHERE ([post].[userId] = @1)', - string: 'SELECT [post].[content] FROM [post] WHERE ([post].[userId] = 1)' - }, - oracle: { - text : 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = :1)', - string: 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = 1)' - }, - params: [1] -}); - -Harness.test({ - query: post.where(post.content.isNull()).or({ - content: '' - }).and({ - userId: 1 - }), - pg: { - text : 'SELECT * FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = $1)) AND ("post"."userId" = $2))', - string: 'SELECT * FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = \'\')) AND ("post"."userId" = 1))' - }, - sqlite: { - text : 'SELECT * FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = $1)) AND ("post"."userId" = $2))', - string: 'SELECT * FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = \'\')) AND ("post"."userId" = 1))' - }, - mysql: { - text : 'SELECT * FROM `post` WHERE (((`post`.`content` IS NULL) OR (`post`.`content` = ?)) AND (`post`.`userId` = ?))', - string: 'SELECT * FROM `post` WHERE (((`post`.`content` IS NULL) OR (`post`.`content` = \'\')) AND (`post`.`userId` = 1))' - }, - mssql: { - text : 'SELECT * FROM [post] WHERE ((([post].[content] IS NULL) OR ([post].[content] = @1)) AND ([post].[userId] = @2))', - string: 'SELECT * FROM [post] WHERE ((([post].[content] IS NULL) OR ([post].[content] = \'\')) AND ([post].[userId] = 1))' - }, - oracle: { - text : 'SELECT * FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = :1)) AND ("post"."userId" = :2))', - string: 'SELECT * FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = \'\')) AND ("post"."userId" = 1))' - }, - params: ['', 1] -}); diff --git a/test/dialects/shortcut-tests.ts b/test/dialects/shortcut-tests.ts new file mode 100644 index 00000000..903ad70e --- /dev/null +++ b/test/dialects/shortcut-tests.ts @@ -0,0 +1,162 @@ +import * as Harness from './support.js'; +const post = Harness.definePostTable(); +const user = Harness.defineUserTable(); + +// shortcut: 'select * from
' +Harness.test({ + query: user, + pg: { + text: 'SELECT "user".* FROM "user"', + string: 'SELECT "user".* FROM "user"' + }, + sqlite: { + text: 'SELECT "user".* FROM "user"', + string: 'SELECT "user".* FROM "user"' + }, + mysql: { + text: 'SELECT `user`.* FROM `user`', + string: 'SELECT `user`.* FROM `user`' + }, + mssql: { + text: 'SELECT [user].* FROM [user]', + string: 'SELECT [user].* FROM [user]' + }, + oracle: { + text: 'SELECT "user".* FROM "user"', + string: 'SELECT "user".* FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: user.where(user.name.equals(3)), + pg: { + text: 'SELECT * FROM "user" WHERE ("user"."name" = $1)', + string: 'SELECT * FROM "user" WHERE ("user"."name" = 3)' + }, + sqlite: { + text: 'SELECT * FROM "user" WHERE ("user"."name" = $1)', + string: 'SELECT * FROM "user" WHERE ("user"."name" = 3)' + }, + mysql: { + text: 'SELECT * FROM `user` WHERE (`user`.`name` = ?)', + string: 'SELECT * FROM `user` WHERE (`user`.`name` = 3)' + }, + mssql: { + text: 'SELECT * FROM [user] WHERE ([user].[name] = @1)', + string: 'SELECT * FROM [user] WHERE ([user].[name] = 3)' + }, + oracle: { + text: 'SELECT * FROM "user" WHERE ("user"."name" = :1)', + string: 'SELECT * FROM "user" WHERE ("user"."name" = 3)' + }, + params: [3] +}); + +Harness.test({ + query: user.where(user.name.equals(3)).where(user.id.equals(1)), + pg: { + text: 'SELECT * FROM "user" WHERE (("user"."name" = $1) AND ("user"."id" = $2))', + string: 'SELECT * FROM "user" WHERE (("user"."name" = 3) AND ("user"."id" = 1))' + }, + sqlite: { + text: 'SELECT * FROM "user" WHERE (("user"."name" = $1) AND ("user"."id" = $2))', + string: 'SELECT * FROM "user" WHERE (("user"."name" = 3) AND ("user"."id" = 1))' + }, + mysql: { + text: 'SELECT * FROM `user` WHERE ((`user`.`name` = ?) AND (`user`.`id` = ?))', + string: 'SELECT * FROM `user` WHERE ((`user`.`name` = 3) AND (`user`.`id` = 1))' + }, + mssql: { + text: 'SELECT * FROM [user] WHERE (([user].[name] = @1) AND ([user].[id] = @2))', + string: 'SELECT * FROM [user] WHERE (([user].[name] = 3) AND ([user].[id] = 1))' + }, + oracle: { + text: 'SELECT * FROM "user" WHERE (("user"."name" = :1) AND ("user"."id" = :2))', + string: 'SELECT * FROM "user" WHERE (("user"."name" = 3) AND ("user"."id" = 1))' + }, + params: [3, 1] +}); + +// shortcut: no 'from' +Harness.test({ + query: post.select(post.content), + pg: { + text: 'SELECT "post"."content" FROM "post"', + string: 'SELECT "post"."content" FROM "post"' + }, + sqlite: { + text: 'SELECT "post"."content" FROM "post"', + string: 'SELECT "post"."content" FROM "post"' + }, + mysql: { + text: 'SELECT `post`.`content` FROM `post`', + string: 'SELECT `post`.`content` FROM `post`' + }, + mssql: { + text: 'SELECT [post].[content] FROM [post]', + string: 'SELECT [post].[content] FROM [post]' + }, + oracle: { + text: 'SELECT "post"."content" FROM "post"', + string: 'SELECT "post"."content" FROM "post"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.content).where(post.userId.equals(1)), + pg: { + text: 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = $1)', + string: 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = 1)' + }, + sqlite: { + text: 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = $1)', + string: 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = 1)' + }, + mysql: { + text: 'SELECT `post`.`content` FROM `post` WHERE (`post`.`userId` = ?)', + string: 'SELECT `post`.`content` FROM `post` WHERE (`post`.`userId` = 1)' + }, + mssql: { + text: 'SELECT [post].[content] FROM [post] WHERE ([post].[userId] = @1)', + string: 'SELECT [post].[content] FROM [post] WHERE ([post].[userId] = 1)' + }, + oracle: { + text: 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = :1)', + string: 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = 1)' + }, + params: [1] +}); + +Harness.test({ + query: post + .where(post.content.isNull()) + .or({ + content: '' + }) + .and({ + userId: 1 + }), + pg: { + text: 'SELECT * FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = $1)) AND ("post"."userId" = $2))', + string: 'SELECT * FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = \'\')) AND ("post"."userId" = 1))' + }, + sqlite: { + text: 'SELECT * FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = $1)) AND ("post"."userId" = $2))', + string: 'SELECT * FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = \'\')) AND ("post"."userId" = 1))' + }, + mysql: { + text: 'SELECT * FROM `post` WHERE (((`post`.`content` IS NULL) OR (`post`.`content` = ?)) AND (`post`.`userId` = ?))', + string: "SELECT * FROM `post` WHERE (((`post`.`content` IS NULL) OR (`post`.`content` = '')) AND (`post`.`userId` = 1))" + }, + mssql: { + text: 'SELECT * FROM [post] WHERE ((([post].[content] IS NULL) OR ([post].[content] = @1)) AND ([post].[userId] = @2))', + string: "SELECT * FROM [post] WHERE ((([post].[content] IS NULL) OR ([post].[content] = '')) AND ([post].[userId] = 1))" + }, + oracle: { + text: 'SELECT * FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = :1)) AND ("post"."userId" = :2))', + string: 'SELECT * FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = \'\')) AND ("post"."userId" = 1))' + }, + params: ['', 1] +}); diff --git a/test/dialects/subfield-tests.js b/test/dialects/subfield-tests.js deleted file mode 100644 index aeaab51d..00000000 --- a/test/dialects/subfield-tests.js +++ /dev/null @@ -1,42 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var customer = Harness.defineCustomerCompositeTable(); -var Sql = require('../../lib').setDialect('postgres'); - -Harness.test({ - query: customer.select(customer.info.subfields.age), - pg: { - text : 'SELECT ("customer"."info")."age" FROM "customer"', - string: 'SELECT ("customer"."info")."age" FROM "customer"' - }, - params: [] -}); - - -Harness.test({ - query: customer.select(customer.info.subfields.age.as('years')), - pg: { - text : 'SELECT ("customer"."info")."age" AS "years" FROM "customer"', - string: 'SELECT ("customer"."info")."age" AS "years" FROM "customer"' - }, - params: [] -}); - -Harness.test({ - query: customer.select(customer.id).where(customer.info.subfields.salary.equals(10)), - pg: { - text : 'SELECT "customer"."id" FROM "customer" WHERE (("customer"."info")."salary" = $1)', - string: 'SELECT "customer"."id" FROM "customer" WHERE (("customer"."info")."salary" = 10)' - }, - params: [10] -}); - -Harness.test({ - query: customer.select(customer.info.subfields.name.distinct()), - pg: { - text : 'SELECT DISTINCT(("customer"."info")."name") FROM "customer"', - string: 'SELECT DISTINCT(("customer"."info")."name") FROM "customer"' - }, - params: [] -}); diff --git a/test/dialects/subfield-tests.ts b/test/dialects/subfield-tests.ts new file mode 100644 index 00000000..7f1cdc68 --- /dev/null +++ b/test/dialects/subfield-tests.ts @@ -0,0 +1,38 @@ +import * as Harness from './support.js'; +const customerComposite = Harness.defineCustomerCompositeTable(); + +Harness.test({ + query: customerComposite.select(customerComposite.info.subfields.age), + pg: { + text: 'SELECT ("customer"."info")."age" FROM "customer"', + string: 'SELECT ("customer"."info")."age" FROM "customer"' + }, + params: [] +}); + +Harness.test({ + query: customerComposite.select(customerComposite.info.subfields.age.as('years')), + pg: { + text: 'SELECT ("customer"."info")."age" AS "years" FROM "customer"', + string: 'SELECT ("customer"."info")."age" AS "years" FROM "customer"' + }, + params: [] +}); + +Harness.test({ + query: customerComposite.select(customerComposite.id).where(customerComposite.info.subfields.salary.equals(10)), + pg: { + text: 'SELECT "customer"."id" FROM "customer" WHERE (("customer"."info")."salary" = $1)', + string: 'SELECT "customer"."id" FROM "customer" WHERE (("customer"."info")."salary" = 10)' + }, + params: [10] +}); + +Harness.test({ + query: customerComposite.select(customerComposite.info.subfields.name.distinct()), + pg: { + text: 'SELECT DISTINCT(("customer"."info")."name") FROM "customer"', + string: 'SELECT DISTINCT(("customer"."info")."name") FROM "customer"' + }, + params: [] +}); diff --git a/test/dialects/subquery-tests.js b/test/dialects/subquery-tests.js deleted file mode 100644 index fe5b2aad..00000000 --- a/test/dialects/subquery-tests.js +++ /dev/null @@ -1,221 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var customer = Harness.defineCustomerTable(); -var user = Harness.defineUserTable(); -var post = Harness.definePostTable(); -var Sql = require('../../lib'); - -Harness.test({ - query: user.select(user.name).where(user.id.in(post.select(post.userId))), - pg: { - text: 'SELECT "user"."name" FROM "user" WHERE ("user"."id" IN (SELECT "post"."userId" FROM "post"))', - string: 'SELECT "user"."name" FROM "user" WHERE ("user"."id" IN (SELECT "post"."userId" FROM "post"))' - }, - sqlite: { - text: 'SELECT "user"."name" FROM "user" WHERE ("user"."id" IN (SELECT "post"."userId" FROM "post"))', - string: 'SELECT "user"."name" FROM "user" WHERE ("user"."id" IN (SELECT "post"."userId" FROM "post"))' - }, - mysql: { - text: 'SELECT `user`.`name` FROM `user` WHERE (`user`.`id` IN (SELECT `post`.`userId` FROM `post`))', - string: 'SELECT `user`.`name` FROM `user` WHERE (`user`.`id` IN (SELECT `post`.`userId` FROM `post`))' - }, - mssql: { - text: 'SELECT [user].[name] FROM [user] WHERE ([user].[id] IN (SELECT [post].[userId] FROM [post]))', - string: 'SELECT [user].[name] FROM [user] WHERE ([user].[id] IN (SELECT [post].[userId] FROM [post]))', - }, - oracle: { - text: 'SELECT "user"."name" FROM "user" WHERE ("user"."id" IN (SELECT "post"."userId" FROM "post"))', - string: 'SELECT "user"."name" FROM "user" WHERE ("user"."id" IN (SELECT "post"."userId" FROM "post"))' - }, - params: [] -}); - -Harness.test({ - query: user.name.in( - customer.subQuery().select(customer.name).where( - user.name.in( - customer.subQuery().select(customer.name).where( - user.name.like('%HELLO%'))))), - pg: { - text : '("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" LIKE $1)))))', - string: '("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" LIKE \'%HELLO%\')))))' - }, - sqlite: { - text : '("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" LIKE $1)))))', - string: '("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" LIKE \'%HELLO%\')))))' - }, - mysql: { - text : '(`user`.`name` IN (SELECT `customer`.`name` FROM `customer` WHERE (`user`.`name` IN (SELECT `customer`.`name` FROM `customer` WHERE (`user`.`name` LIKE ?)))))', - string: '(`user`.`name` IN (SELECT `customer`.`name` FROM `customer` WHERE (`user`.`name` IN (SELECT `customer`.`name` FROM `customer` WHERE (`user`.`name` LIKE \'%HELLO%\')))))' - }, - mssql: { - text : '([user].[name] IN (SELECT [customer].[name] FROM [customer] WHERE ([user].[name] IN (SELECT [customer].[name] FROM [customer] WHERE ([user].[name] LIKE @1)))))', - string: '([user].[name] IN (SELECT [customer].[name] FROM [customer] WHERE ([user].[name] IN (SELECT [customer].[name] FROM [customer] WHERE ([user].[name] LIKE \'%HELLO%\')))))' - }, - oracle: { - text : '("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" LIKE :1)))))', - string: '("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" LIKE \'%HELLO%\')))))' - }, - params: ['%HELLO%'] -}); - -Harness.test({ - query: Sql.select('*').from(user.subQuery()), - pg: { - text : 'SELECT * FROM (SELECT * FROM "user")', - string: 'SELECT * FROM (SELECT * FROM "user")' - }, - sqlite: { - text : 'SELECT * FROM (SELECT * FROM "user")', - string: 'SELECT * FROM (SELECT * FROM "user")' - }, - mysql: { - text : 'SELECT * FROM (SELECT * FROM `user`)', - string: 'SELECT * FROM (SELECT * FROM `user`)' - }, - mssql: { - text : 'SELECT * FROM (SELECT * FROM [user])', - string: 'SELECT * FROM (SELECT * FROM [user])' - }, - oracle: { - text : 'SELECT * FROM (SELECT * FROM "user")', - string: 'SELECT * FROM (SELECT * FROM "user")' - }, - params: [] -}); - -// Subquery with a date -Harness.test({ - query: Sql.select('*').from(post.subQuery().where(post.content.equals(new Date('Sat, 01 Jan 2000 00:00:00 GMT')))), - pg: { - text : 'SELECT * FROM (SELECT * FROM "post" WHERE ("post"."content" = $1))', - string: 'SELECT * FROM (SELECT * FROM "post" WHERE ("post"."content" = \'2000-01-01T00:00:00.000Z\'))' - }, - sqlite: { - text : 'SELECT * FROM (SELECT * FROM "post" WHERE ("post"."content" = $1))', - string: 'SELECT * FROM (SELECT * FROM "post" WHERE ("post"."content" = 946684800000))', - config: { - dateTimeMillis: true - } - }, - mysql: { - text : 'SELECT * FROM (SELECT * FROM `post` WHERE (`post`.`content` = ?))', - string: 'SELECT * FROM (SELECT * FROM `post` WHERE (`post`.`content` = \'2000-01-01T00:00:00.000Z\'))' - }, - mssql: { - text : 'SELECT * FROM (SELECT * FROM [post] WHERE ([post].[content] = @1))', - string: 'SELECT * FROM (SELECT * FROM [post] WHERE ([post].[content] = \'2000-01-01T00:00:00.000Z\'))' - }, - oracle: { - text : 'SELECT * FROM (SELECT * FROM "post" WHERE ("post"."content" = :1))', - string: 'SELECT * FROM (SELECT * FROM "post" WHERE ("post"."content" = \'2000-01-01T00:00:00.000Z\'))' - }, - params: [new Date('Sat, 01 Jan 2000 00:00:00 GMT')] -}); - - -Harness.test({ - query: Sql.select('*').from(customer.subQuery('T1')).from(user.subQuery('T2')), - pg: { - text : 'SELECT * FROM (SELECT * FROM "customer") "T1" , (SELECT * FROM "user") "T2"', - string: 'SELECT * FROM (SELECT * FROM "customer") "T1" , (SELECT * FROM "user") "T2"' - }, - sqlite: { - text : 'SELECT * FROM (SELECT * FROM "customer") "T1" , (SELECT * FROM "user") "T2"', - string: 'SELECT * FROM (SELECT * FROM "customer") "T1" , (SELECT * FROM "user") "T2"' - }, - mysql: { - text : 'SELECT * FROM (SELECT * FROM `customer`) `T1` , (SELECT * FROM `user`) `T2`', - string: 'SELECT * FROM (SELECT * FROM `customer`) `T1` , (SELECT * FROM `user`) `T2`' - }, - mssql: { - text : 'SELECT * FROM (SELECT * FROM [customer]) [T1] , (SELECT * FROM [user]) [T2]', - string: 'SELECT * FROM (SELECT * FROM [customer]) [T1] , (SELECT * FROM [user]) [T2]' - }, - oracle: { - text : 'SELECT * FROM (SELECT * FROM "customer") "T1" , (SELECT * FROM "user") "T2"', - string: 'SELECT * FROM (SELECT * FROM "customer") "T1" , (SELECT * FROM "user") "T2"' - }, - params: [] -}); - -Harness.test({ - query: customer.name.between( - customer.subQuery().select(Sql.functions.MIN(customer.name)), - customer.subQuery().select(Sql.functions.MAX(customer.name)) - ), - pg: { - text : '("customer"."name" BETWEEN (SELECT MIN("customer"."name") FROM "customer") AND (SELECT MAX("customer"."name") FROM "customer"))', - string: '("customer"."name" BETWEEN (SELECT MIN("customer"."name") FROM "customer") AND (SELECT MAX("customer"."name") FROM "customer"))' - }, - sqlite: { - text : '("customer"."name" BETWEEN (SELECT MIN("customer"."name") FROM "customer") AND (SELECT MAX("customer"."name") FROM "customer"))', - string: '("customer"."name" BETWEEN (SELECT MIN("customer"."name") FROM "customer") AND (SELECT MAX("customer"."name") FROM "customer"))' - }, - mysql: { - text : '(`customer`.`name` BETWEEN (SELECT MIN(`customer`.`name`) FROM `customer`) AND (SELECT MAX(`customer`.`name`) FROM `customer`))', - string: '(`customer`.`name` BETWEEN (SELECT MIN(`customer`.`name`) FROM `customer`) AND (SELECT MAX(`customer`.`name`) FROM `customer`))' - }, - mssql: { - text : '([customer].[name] BETWEEN (SELECT MIN([customer].[name]) FROM [customer]) AND (SELECT MAX([customer].[name]) FROM [customer]))', - string: '([customer].[name] BETWEEN (SELECT MIN([customer].[name]) FROM [customer]) AND (SELECT MAX([customer].[name]) FROM [customer]))' - }, - oracle: { - text : '("customer"."name" BETWEEN (SELECT MIN("customer"."name") FROM "customer") AND (SELECT MAX("customer"."name") FROM "customer"))', - string: '("customer"."name" BETWEEN (SELECT MIN("customer"."name") FROM "customer") AND (SELECT MAX("customer"."name") FROM "customer"))' - }, - params: [] -}); - -Harness.test({ - query: user.subQuery().where(user.name.equals(customer.name)).exists(), - pg: { - text : '(EXISTS (SELECT * FROM "user" WHERE ("user"."name" = "customer"."name")))', - string: '(EXISTS (SELECT * FROM "user" WHERE ("user"."name" = "customer"."name")))' - }, - sqlite: { - text : '(EXISTS (SELECT * FROM "user" WHERE ("user"."name" = "customer"."name")))', - string: '(EXISTS (SELECT * FROM "user" WHERE ("user"."name" = "customer"."name")))' - }, - mysql: { - text : '(EXISTS (SELECT * FROM `user` WHERE (`user`.`name` = `customer`.`name`)))', - string: '(EXISTS (SELECT * FROM `user` WHERE (`user`.`name` = `customer`.`name`)))' - }, - mssql: { - text : '(EXISTS (SELECT * FROM [user] WHERE ([user].[name] = [customer].[name])))', - string: '(EXISTS (SELECT * FROM [user] WHERE ([user].[name] = [customer].[name])))' - }, - oracle: { - text : '(EXISTS (SELECT * FROM "user" WHERE ("user"."name" = "customer"."name")))', - string: '(EXISTS (SELECT * FROM "user" WHERE ("user"."name" = "customer"."name")))' - }, - params: [] -}); - -var limitUsers = user.subQuery('limit-users').select(user.id, user.name).from(user).order(user.name).limit(10).offset(10); -Harness.test({ - query: Sql.select(limitUsers.name, post.tags).from(limitUsers.leftJoin(post).on(post.userId.equals(limitUsers.id))), - pg: { - text : 'SELECT "limit-users"."name", "post"."tags" FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" LIMIT 10 OFFSET 10) "limit-users" LEFT JOIN "post" ON ("post"."userId" = "limit-users"."id")', - string: 'SELECT "limit-users"."name", "post"."tags" FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" LIMIT 10 OFFSET 10) "limit-users" LEFT JOIN "post" ON ("post"."userId" = "limit-users"."id")' - }, - sqlite: { - text : 'SELECT "limit-users"."name", "post"."tags" FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" LIMIT 10 OFFSET 10) "limit-users" LEFT JOIN "post" ON ("post"."userId" = "limit-users"."id")', - string: 'SELECT "limit-users"."name", "post"."tags" FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" LIMIT 10 OFFSET 10) "limit-users" LEFT JOIN "post" ON ("post"."userId" = "limit-users"."id")' - }, - mysql: { - text : 'SELECT `limit-users`.`name`, `post`.`tags` FROM (SELECT `user`.`id`, `user`.`name` FROM `user` ORDER BY `user`.`name` LIMIT 10 OFFSET 10) `limit-users` LEFT JOIN `post` ON (`post`.`userId` = `limit-users`.`id`)', - string: 'SELECT `limit-users`.`name`, `post`.`tags` FROM (SELECT `user`.`id`, `user`.`name` FROM `user` ORDER BY `user`.`name` LIMIT 10 OFFSET 10) `limit-users` LEFT JOIN `post` ON (`post`.`userId` = `limit-users`.`id`)' - }, - mssql: { - text : 'SELECT [limit-users].[name], [post].[tags] FROM (SELECT [user].[id], [user].[name] FROM [user] ORDER BY [user].[name] OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY) [limit-users] LEFT JOIN [post] ON ([post].[userId] = [limit-users].[id])', - string: 'SELECT [limit-users].[name], [post].[tags] FROM (SELECT [user].[id], [user].[name] FROM [user] ORDER BY [user].[name] OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY) [limit-users] LEFT JOIN [post] ON ([post].[userId] = [limit-users].[id])' - }, - oracle: { - text : 'SELECT "limit-users"."name", "post"."tags" FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY) "limit-users" LEFT JOIN "post" ON ("post"."userId" = "limit-users"."id")', - string: 'SELECT "limit-users"."name", "post"."tags" FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY) "limit-users" LEFT JOIN "post" ON ("post"."userId" = "limit-users"."id")' - }, - params: [] -}); - diff --git a/test/dialects/subquery-tests.ts b/test/dialects/subquery-tests.ts new file mode 100644 index 00000000..3e836094 --- /dev/null +++ b/test/dialects/subquery-tests.ts @@ -0,0 +1,345 @@ +import * as Harness from './support.js'; +import { Sql } from '../../dist/lib.js'; +const customer = Harness.defineCustomerTable(); +const post = Harness.definePostTable(); +const user = Harness.defineUserTable(); +const customerAlias = Harness.defineCustomerAliasTable(); +const instance = new Sql('postgres'); + +Harness.test({ + query: user.select(user.name).where(user.id.in(post.select(post.userId))), + pg: { + text: 'SELECT "user"."name" FROM "user" WHERE ("user"."id" IN (SELECT "post"."userId" FROM "post"))', + string: 'SELECT "user"."name" FROM "user" WHERE ("user"."id" IN (SELECT "post"."userId" FROM "post"))' + }, + sqlite: { + text: 'SELECT "user"."name" FROM "user" WHERE ("user"."id" IN (SELECT "post"."userId" FROM "post"))', + string: 'SELECT "user"."name" FROM "user" WHERE ("user"."id" IN (SELECT "post"."userId" FROM "post"))' + }, + mysql: { + text: 'SELECT `user`.`name` FROM `user` WHERE (`user`.`id` IN (SELECT `post`.`userId` FROM `post`))', + string: 'SELECT `user`.`name` FROM `user` WHERE (`user`.`id` IN (SELECT `post`.`userId` FROM `post`))' + }, + mssql: { + text: 'SELECT [user].[name] FROM [user] WHERE ([user].[id] IN (SELECT [post].[userId] FROM [post]))', + string: 'SELECT [user].[name] FROM [user] WHERE ([user].[id] IN (SELECT [post].[userId] FROM [post]))' + }, + oracle: { + text: 'SELECT "user"."name" FROM "user" WHERE ("user"."id" IN (SELECT "post"."userId" FROM "post"))', + string: 'SELECT "user"."name" FROM "user" WHERE ("user"."id" IN (SELECT "post"."userId" FROM "post"))' + }, + params: [] +}); + +Harness.test({ + query: user.name.in( + customer + .subQuery() + .select(customer.name) + .where( + user.name.in( + customer + .subQuery() + .select(customer.name) + .where(user.name.like('%HELLO%')) + ) + ) + ), + pg: { + text: + '("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" LIKE $1)))))', + string: + '("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" LIKE \'%HELLO%\')))))' + }, + sqlite: { + text: + '("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" LIKE $1)))))', + string: + '("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" LIKE \'%HELLO%\')))))' + }, + mysql: { + text: + '(`user`.`name` IN (SELECT `customer`.`name` FROM `customer` WHERE (`user`.`name` IN (SELECT `customer`.`name` FROM `customer` WHERE (`user`.`name` LIKE ?)))))', + string: + "(`user`.`name` IN (SELECT `customer`.`name` FROM `customer` WHERE (`user`.`name` IN (SELECT `customer`.`name` FROM `customer` WHERE (`user`.`name` LIKE '%HELLO%')))))" + }, + mssql: { + text: + '([user].[name] IN (SELECT [customer].[name] FROM [customer] WHERE ([user].[name] IN (SELECT [customer].[name] FROM [customer] WHERE ([user].[name] LIKE @1)))))', + string: + "([user].[name] IN (SELECT [customer].[name] FROM [customer] WHERE ([user].[name] IN (SELECT [customer].[name] FROM [customer] WHERE ([user].[name] LIKE '%HELLO%')))))" + }, + oracle: { + text: + '("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" LIKE :1)))))', + string: + '("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" LIKE \'%HELLO%\')))))' + }, + params: ['%HELLO%'] +}); + +Harness.test({ + query: instance.select('*').from(user.subQuery()), + pg: { + text: 'SELECT * FROM (SELECT * FROM "user")', + string: 'SELECT * FROM (SELECT * FROM "user")' + }, + sqlite: { + text: 'SELECT * FROM (SELECT * FROM "user")', + string: 'SELECT * FROM (SELECT * FROM "user")' + }, + mysql: { + text: 'SELECT * FROM (SELECT * FROM `user`)', + string: 'SELECT * FROM (SELECT * FROM `user`)' + }, + mssql: { + text: 'SELECT * FROM (SELECT * FROM [user])', + string: 'SELECT * FROM (SELECT * FROM [user])' + }, + oracle: { + text: 'SELECT * FROM (SELECT * FROM "user")', + string: 'SELECT * FROM (SELECT * FROM "user")' + }, + params: [] +}); + +// Subquery with a date +Harness.test({ + query: instance.select('*').from(post.subQuery().where(post.content.equals(new Date('Sat, 01 Jan 2000 00:00:00 GMT')))), + pg: { + text: 'SELECT * FROM (SELECT * FROM "post" WHERE ("post"."content" = $1))', + string: 'SELECT * FROM (SELECT * FROM "post" WHERE ("post"."content" = \'2000-01-01T00:00:00.000Z\'))' + }, + sqlite: { + text: 'SELECT * FROM (SELECT * FROM "post" WHERE ("post"."content" = $1))', + string: 'SELECT * FROM (SELECT * FROM "post" WHERE ("post"."content" = 946684800000))', + config: { + dateTimeMillis: true + } + }, + mysql: { + text: 'SELECT * FROM (SELECT * FROM `post` WHERE (`post`.`content` = ?))', + string: "SELECT * FROM (SELECT * FROM `post` WHERE (`post`.`content` = '2000-01-01T00:00:00.000Z'))" + }, + mssql: { + text: 'SELECT * FROM (SELECT * FROM [post] WHERE ([post].[content] = @1))', + string: "SELECT * FROM (SELECT * FROM [post] WHERE ([post].[content] = '2000-01-01T00:00:00.000Z'))" + }, + oracle: { + text: 'SELECT * FROM (SELECT * FROM "post" WHERE ("post"."content" = :1))', + string: 'SELECT * FROM (SELECT * FROM "post" WHERE ("post"."content" = \'2000-01-01T00:00:00.000Z\'))' + }, + params: [new Date('Sat, 01 Jan 2000 00:00:00 GMT')] +}); + +Harness.test({ + query: instance + .select('*') + .from(customer.subQuery('T1')) + .from(user.subQuery('T2')), + pg: { + text: 'SELECT * FROM (SELECT * FROM "customer") "T1" , (SELECT * FROM "user") "T2"', + string: 'SELECT * FROM (SELECT * FROM "customer") "T1" , (SELECT * FROM "user") "T2"' + }, + sqlite: { + text: 'SELECT * FROM (SELECT * FROM "customer") "T1" , (SELECT * FROM "user") "T2"', + string: 'SELECT * FROM (SELECT * FROM "customer") "T1" , (SELECT * FROM "user") "T2"' + }, + mysql: { + text: 'SELECT * FROM (SELECT * FROM `customer`) `T1` , (SELECT * FROM `user`) `T2`', + string: 'SELECT * FROM (SELECT * FROM `customer`) `T1` , (SELECT * FROM `user`) `T2`' + }, + mssql: { + text: 'SELECT * FROM (SELECT * FROM [customer]) [T1] , (SELECT * FROM [user]) [T2]', + string: 'SELECT * FROM (SELECT * FROM [customer]) [T1] , (SELECT * FROM [user]) [T2]' + }, + oracle: { + text: 'SELECT * FROM (SELECT * FROM "customer") "T1" , (SELECT * FROM "user") "T2"', + string: 'SELECT * FROM (SELECT * FROM "customer") "T1" , (SELECT * FROM "user") "T2"' + }, + params: [] +}); + +Harness.test({ + query: customer.name.between( + customer.subQuery().select(instance.functions.MIN(customer.name)), + customer.subQuery().select(instance.functions.MAX(customer.name)) + ), + pg: { + text: + '("customer"."name" BETWEEN (SELECT MIN("customer"."name") FROM "customer") AND (SELECT MAX("customer"."name") FROM "customer"))', + string: + '("customer"."name" BETWEEN (SELECT MIN("customer"."name") FROM "customer") AND (SELECT MAX("customer"."name") FROM "customer"))' + }, + sqlite: { + text: + '("customer"."name" BETWEEN (SELECT MIN("customer"."name") FROM "customer") AND (SELECT MAX("customer"."name") FROM "customer"))', + string: + '("customer"."name" BETWEEN (SELECT MIN("customer"."name") FROM "customer") AND (SELECT MAX("customer"."name") FROM "customer"))' + }, + mysql: { + text: + '(`customer`.`name` BETWEEN (SELECT MIN(`customer`.`name`) FROM `customer`) AND (SELECT MAX(`customer`.`name`) FROM `customer`))', + string: + '(`customer`.`name` BETWEEN (SELECT MIN(`customer`.`name`) FROM `customer`) AND (SELECT MAX(`customer`.`name`) FROM `customer`))' + }, + mssql: { + text: + '([customer].[name] BETWEEN (SELECT MIN([customer].[name]) FROM [customer]) AND (SELECT MAX([customer].[name]) FROM [customer]))', + string: + '([customer].[name] BETWEEN (SELECT MIN([customer].[name]) FROM [customer]) AND (SELECT MAX([customer].[name]) FROM [customer]))' + }, + oracle: { + text: + '("customer"."name" BETWEEN (SELECT MIN("customer"."name") FROM "customer") AND (SELECT MAX("customer"."name") FROM "customer"))', + string: + '("customer"."name" BETWEEN (SELECT MIN("customer"."name") FROM "customer") AND (SELECT MAX("customer"."name") FROM "customer"))' + }, + params: [] +}); + +Harness.test({ + query: user + .subQuery() + .where(user.name.equals(customer.name)) + .exists(), + pg: { + text: '(EXISTS (SELECT * FROM "user" WHERE ("user"."name" = "customer"."name")))', + string: '(EXISTS (SELECT * FROM "user" WHERE ("user"."name" = "customer"."name")))' + }, + sqlite: { + text: '(EXISTS (SELECT * FROM "user" WHERE ("user"."name" = "customer"."name")))', + string: '(EXISTS (SELECT * FROM "user" WHERE ("user"."name" = "customer"."name")))' + }, + mysql: { + text: '(EXISTS (SELECT * FROM `user` WHERE (`user`.`name` = `customer`.`name`)))', + string: '(EXISTS (SELECT * FROM `user` WHERE (`user`.`name` = `customer`.`name`)))' + }, + mssql: { + text: '(EXISTS (SELECT * FROM [user] WHERE ([user].[name] = [customer].[name])))', + string: '(EXISTS (SELECT * FROM [user] WHERE ([user].[name] = [customer].[name])))' + }, + oracle: { + text: '(EXISTS (SELECT * FROM "user" WHERE ("user"."name" = "customer"."name")))', + string: '(EXISTS (SELECT * FROM "user" WHERE ("user"."name" = "customer"."name")))' + }, + params: [] +}); + +const limitUsers = user + .subQuery<{ id: string, name: string }>('limit-users') + .select(user.id, user.name) + .from(user) + .order(user.name) + .limit(10) + .offset(10); +Harness.test({ + query: instance.select(limitUsers.name, post.tags).from(limitUsers.leftJoin(post).on(post.userId.equals(limitUsers.id))), + pg: { + text: + 'SELECT "limit-users"."name", "post"."tags" FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" LIMIT $1 OFFSET $2) "limit-users" LEFT JOIN "post" ON ("post"."userId" = "limit-users"."id")', + string: + 'SELECT "limit-users"."name", "post"."tags" FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" LIMIT 10 OFFSET 10) "limit-users" LEFT JOIN "post" ON ("post"."userId" = "limit-users"."id")' + }, + sqlite: { + text: + 'SELECT "limit-users"."name", "post"."tags" FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" LIMIT $1 OFFSET $2) "limit-users" LEFT JOIN "post" ON ("post"."userId" = "limit-users"."id")', + string: + 'SELECT "limit-users"."name", "post"."tags" FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" LIMIT 10 OFFSET 10) "limit-users" LEFT JOIN "post" ON ("post"."userId" = "limit-users"."id")' + }, + mysql: { + text: + 'SELECT `limit-users`.`name`, `post`.`tags` FROM (SELECT `user`.`id`, `user`.`name` FROM `user` ORDER BY `user`.`name` LIMIT ? OFFSET ?) `limit-users` LEFT JOIN `post` ON (`post`.`userId` = `limit-users`.`id`)', + string: + 'SELECT `limit-users`.`name`, `post`.`tags` FROM (SELECT `user`.`id`, `user`.`name` FROM `user` ORDER BY `user`.`name` LIMIT 10 OFFSET 10) `limit-users` LEFT JOIN `post` ON (`post`.`userId` = `limit-users`.`id`)' + }, + mssql: { + text: + 'SELECT [limit-users].[name], [post].[tags] FROM (SELECT [user].[id], [user].[name] FROM [user] ORDER BY [user].[name] OFFSET @1 ROWS FETCH NEXT @2 ROWS ONLY) [limit-users] LEFT JOIN [post] ON ([post].[userId] = [limit-users].[id])', + string: + 'SELECT [limit-users].[name], [post].[tags] FROM (SELECT [user].[id], [user].[name] FROM [user] ORDER BY [user].[name] OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY) [limit-users] LEFT JOIN [post] ON ([post].[userId] = [limit-users].[id])' + }, + oracle: { + text: + 'SELECT "limit-users"."name", "post"."tags" FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" OFFSET :2 ROWS FETCH NEXT :1 ROWS ONLY) "limit-users" LEFT JOIN "post" ON ("post"."userId" = "limit-users"."id")', + string: + 'SELECT "limit-users"."name", "post"."tags" FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY) "limit-users" LEFT JOIN "post" ON ("post"."userId" = "limit-users"."id")' + }, + params: [10, 10] +}); + +Harness.test({ + query: instance.select(limitUsers.star()).from(limitUsers.join(post).on(post.userId.equals(limitUsers.id))), + pg: { + text: + 'SELECT "limit-users".* FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" LIMIT $1 OFFSET $2) "limit-users" INNER JOIN "post" ON ("post"."userId" = "limit-users"."id")', + string: + 'SELECT "limit-users".* FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" LIMIT 10 OFFSET 10) "limit-users" INNER JOIN "post" ON ("post"."userId" = "limit-users"."id")' + }, + sqlite: { + text: + 'SELECT "limit-users".* FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" LIMIT $1 OFFSET $2) "limit-users" INNER JOIN "post" ON ("post"."userId" = "limit-users"."id")', + string: + 'SELECT "limit-users".* FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" LIMIT 10 OFFSET 10) "limit-users" INNER JOIN "post" ON ("post"."userId" = "limit-users"."id")' + }, + mysql: { + text: + 'SELECT `limit-users`.* FROM (SELECT `user`.`id`, `user`.`name` FROM `user` ORDER BY `user`.`name` LIMIT ? OFFSET ?) `limit-users` INNER JOIN `post` ON (`post`.`userId` = `limit-users`.`id`)', + string: + 'SELECT `limit-users`.* FROM (SELECT `user`.`id`, `user`.`name` FROM `user` ORDER BY `user`.`name` LIMIT 10 OFFSET 10) `limit-users` INNER JOIN `post` ON (`post`.`userId` = `limit-users`.`id`)' + }, + mssql: { + text: + 'SELECT [limit-users].* FROM (SELECT [user].[id], [user].[name] FROM [user] ORDER BY [user].[name] OFFSET @1 ROWS FETCH NEXT @2 ROWS ONLY) [limit-users] INNER JOIN [post] ON ([post].[userId] = [limit-users].[id])', + string: + 'SELECT [limit-users].* FROM (SELECT [user].[id], [user].[name] FROM [user] ORDER BY [user].[name] OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY) [limit-users] INNER JOIN [post] ON ([post].[userId] = [limit-users].[id])' + }, + oracle: { + text: + 'SELECT "limit-users".* FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" OFFSET :2 ROWS FETCH NEXT :1 ROWS ONLY) "limit-users" INNER JOIN "post" ON ("post"."userId" = "limit-users"."id")', + string: + 'SELECT "limit-users".* FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY) "limit-users" INNER JOIN "post" ON ("post"."userId" = "limit-users"."id")' + }, + params: [10, 10] +}); + +const groupedCustomersByName = customerAlias + .subQuery<{ name_alias: string, countForName: number }>('grouped-customers') + .select(customerAlias.name_alias, customerAlias.count().as('countForName')) + .from(customerAlias) + .group(customerAlias.name_alias) + .order(customerAlias.name_alias); +Harness.test({ + query: instance.select(groupedCustomersByName.name_alias, groupedCustomersByName.countForName).from(groupedCustomersByName), + pg: { + text: + 'SELECT "grouped-customers"."name_alias", "grouped-customers"."countForName" FROM (SELECT "customer"."name" AS "name_alias", COUNT("customer".*) AS "countForName" FROM "customer" GROUP BY "customer"."name" ORDER BY "customer"."name") "grouped-customers"', + string: + 'SELECT "grouped-customers"."name_alias", "grouped-customers"."countForName" FROM (SELECT "customer"."name" AS "name_alias", COUNT("customer".*) AS "countForName" FROM "customer" GROUP BY "customer"."name" ORDER BY "customer"."name") "grouped-customers"' + }, + sqlite: { + text: + 'SELECT "grouped-customers"."name_alias", "grouped-customers"."countForName" FROM (SELECT "customer"."name" AS "name_alias", COUNT("customer".*) AS "countForName" FROM "customer" GROUP BY "customer"."name" ORDER BY "customer"."name") "grouped-customers"', + string: + 'SELECT "grouped-customers"."name_alias", "grouped-customers"."countForName" FROM (SELECT "customer"."name" AS "name_alias", COUNT("customer".*) AS "countForName" FROM "customer" GROUP BY "customer"."name" ORDER BY "customer"."name") "grouped-customers"' + }, + mysql: { + text: + 'SELECT `grouped-customers`.`name_alias`, `grouped-customers`.`countForName` FROM (SELECT `customer`.`name` AS `name_alias`, COUNT(*) AS `countForName` FROM `customer` GROUP BY `customer`.`name` ORDER BY `customer`.`name`) `grouped-customers`', + string: + 'SELECT `grouped-customers`.`name_alias`, `grouped-customers`.`countForName` FROM (SELECT `customer`.`name` AS `name_alias`, COUNT(*) AS `countForName` FROM `customer` GROUP BY `customer`.`name` ORDER BY `customer`.`name`) `grouped-customers`' + }, + mssql: { + text: + 'SELECT [grouped-customers].[name_alias], [grouped-customers].[countForName] FROM (SELECT [customer].[name] AS [name_alias], COUNT(*) AS [countForName] FROM [customer] GROUP BY [customer].[name] ORDER BY [customer].[name]) [grouped-customers]', + string: + 'SELECT [grouped-customers].[name_alias], [grouped-customers].[countForName] FROM (SELECT [customer].[name] AS [name_alias], COUNT(*) AS [countForName] FROM [customer] GROUP BY [customer].[name] ORDER BY [customer].[name]) [grouped-customers]' + }, + oracle: { + text: + 'SELECT "grouped-customers"."name_alias", "grouped-customers"."countForName" FROM (SELECT "customer"."name" "name_alias", COUNT(*) "countForName" FROM "customer" GROUP BY "customer"."name" ORDER BY "customer"."name") "grouped-customers"', + string: + 'SELECT "grouped-customers"."name_alias", "grouped-customers"."countForName" FROM (SELECT "customer"."name" "name_alias", COUNT(*) "countForName" FROM "customer" GROUP BY "customer"."name" ORDER BY "customer"."name") "grouped-customers"' + }, + params: [] +}); diff --git a/test/dialects/support.js b/test/dialects/support.js deleted file mode 100644 index 4a9fa427..00000000 --- a/test/dialects/support.js +++ /dev/null @@ -1,137 +0,0 @@ -'use strict'; -var assert = require('assert'); - -var Table = require('../../lib/table'); - -// specify dialect classes -var dialects = { - pg : require('../../lib/dialect/postgres'), - sqlite : require('../../lib/dialect/sqlite'), - mysql : require('../../lib/dialect/mysql'), - mssql : require('../../lib/dialect/mssql'), - oracle : require('../../lib/dialect/oracle') -}; - -module.exports = { - test: function(expected) { - // for each dialect - Object.keys(dialects).forEach(function(dialect) { - var expectedObject = expected[dialect]; - if (undefined !== expectedObject) { - - var DialectClass = dialects[dialect]; - - var title = dialect + ': ' + (expected.title || expectedObject.text || expectedObject); - test(title, function() { - - // check if this query is expected to throw - if (expectedObject.throws) { - assert.throws(function() { - new DialectClass(expectedObject.config).getQuery(expected.query); - }); - } else { - // build query for dialect - var compiledQuery = new DialectClass(expectedObject.config).getQuery(expected.query); - - // test result is correct - var expectedText = expectedObject.text || expectedObject; - assert.equal(compiledQuery.text, expectedText); - - // if params are specified then test these are correct - var expectedParams = expectedObject.params || expected.params; - if (undefined !== expectedParams) { - assert.equal(expectedParams.length, compiledQuery.values.length, 'params length'); - for (var i = 0; i < expectedParams.length; i++) { - assert.deepEqual(expectedParams[i], compiledQuery.values[i], 'param ' + (i + 1)); - } - } - } - - if (undefined !== expectedObject.string) { - // test the toString - if (expectedObject.throws) { - assert.throws(function() { - new DialectClass(expectedObject.config).getString(expected.query); - }); - } else { - var compiledString = new DialectClass(expectedObject.config).getString(expected.query); - - // test result is correct - assert.equal(compiledString, expectedObject.string); - } - } - }); - } // if - }); // forEach - }, - - defineUserTable: function() { - return Table.define({ - name: 'user', - quote: true, - columns: ['id', 'name'] - }); - }, - - definePostTable: function() { - return Table.define({ - name: 'post', - columns: ['id', 'userId', 'content', 'tags', 'length'] - }); - }, - - defineCommentTable: function() { - return Table.define({ - name: 'comment', - columns: ['postId', 'text'] - }); - }, - - defineCustomerTable: function() { - return Table.define({ - name: 'customer', - columns: ['id', 'name', 'age', 'income', 'metadata'] - }); - }, - - // This table defines the customer attributes as a composite field - defineCustomerCompositeTable: function() { - return Table.define({ - name: 'customer', - columns: { - id: {}, - info: {subfields: ['name', 'age', 'salary']} - } - }); - }, - - defineCustomerAliasTable: function() { - return Table.define({ - name: 'customer', - columns: { - id: {property: 'id_alias'}, - name: {property: 'name_alias'}, - age: {property: 'age_alias'}, - income: {property: 'income_alias'}, - metadata: {property: 'metadata_alias'} - } - }); - }, - - // This table contains column names that correspond to popularly used variables in formulas. - defineVariableTable: function() { - return Table.define({ - name: 'variable', - columns: ['a', 'b', 'c', 'd', 't', 'u', 'v', 'x', 'y', 'z'] - }); - }, - -// this table is for testing snakeName related stuff - defineContentTable: function() { - return Table.define({ - name: 'content', - columns: ['content_id', 'text', 'content_posts'], - snakeToCamel: true - }); - } -}; diff --git a/test/dialects/support.ts b/test/dialects/support.ts new file mode 100644 index 00000000..ad0c9c95 --- /dev/null +++ b/test/dialects/support.ts @@ -0,0 +1,191 @@ +import assert from 'assert'; + +import { Mssql, Mysql, Oracle, Postgres, Sqlite, Table } from '../../dist/lib.js'; + +// specify dialect classes +const dialects = { + pg: Postgres, + sqlite: Sqlite, + mysql: Mysql, + mssql: Mssql, + oracle: Oracle +}; + +function customTest(expected: any) { + // for each dialect + Object.keys(dialects).forEach(function(dialect) { + const expectedObject = expected[dialect]; + if (undefined !== expectedObject) { + const DialectClass = (dialects as any)[dialect]; + + const title = dialect + ': ' + (expected.title || expectedObject.text || expectedObject); + test(title, function() { + // check if this query is expected to throw + if (expectedObject.throws) { + assert.throws(function() { + new DialectClass(expectedObject.config || {}).getQuery(expected.query); + }); + } else { + // build query for dialect + const compiledQuery = new DialectClass(expectedObject.config || {}).getQuery(expected.query); + + // test result is correct + const expectedText = expectedObject.text || expectedObject; + assert.strictEqual(compiledQuery.text, expectedText); + + // if params are specified then test these are correct + const expectedParams = expectedObject.params || expected.params; + if (undefined !== expectedParams) { + assert.strictEqual(expectedParams.length, compiledQuery.values.length, 'params length'); + for (let i = 0; i < expectedParams.length; i++) { + assert.deepStrictEqual(expectedParams[i], compiledQuery.values[i], 'param ' + (i + 1)); + } + } + } + + if (undefined !== expectedObject.string) { + // test the toString + if (expectedObject.throws) { + assert.throws(function() { + new DialectClass(expectedObject.config || {}).getString(expected.query); + }); + } else { + const compiledString = new DialectClass(expectedObject.config || {}).getString(expected.query); + + // test result is correct + assert.strictEqual(compiledString, expectedObject.string); + } + } + }); + } // if + }); // forEach +} + +export interface UserTable { + id: number; + name: string; +} + +export function defineUserTable() { + return Table.define({ + name: 'user', + columns: ['id', 'name'] + }); +} + +export interface PostTable { + id: number; + userId: number; + content: string | null; + tags: string; + length: number; +} + +export function definePostTable() { + return Table.define({ + name: 'post', + columns: ['id', 'userId', 'content', 'tags', 'length'] + }); +} + +export interface CommentTable { + postId: number; + text: string; +} + +export function defineCommentTable() { + return Table.define({ + name: 'comment', + columns: ['postId', 'text'] + }); +} + +export interface CustomerTable { + id: number; + name: string; + age: number; + income: number; + metadata: Record; +} + +export function defineCustomerTable() { + return Table.define({ + name: 'customer', + columns: ['id', 'name', 'age', 'income', 'metadata'] + }); +} + +export interface CustomerCompositeTable { + id: number; + info: Record; +} + +// This table defines the customer attributes as a composite field +export function defineCustomerCompositeTable() { + return Table.define({ + name: 'customer', + columns: { + id: {}, + info: { subfields: ['name', 'age', 'salary'] } + } + }); +} + +export interface CustomerAliasTable { + id_alias: number; + name_alias: string; + age_alias: number; + income_alias: number; + metadata_alias: Record; +} + +export function defineCustomerAliasTable() { + return Table.define({ + name: 'customer', + columns: { + id: { property: 'id_alias' }, + name: { property: 'name_alias' }, + age: { property: 'age_alias' }, + income: { property: 'income_alias' }, + metadata: { property: 'metadata_alias' } + } + }); +} + +export interface VariableTable { + a: any; + b: any; + c: any; + d: any; + t: any; + u: any; + v: any; + x: any; + y: any; + z: any; +} + +// This table contains column names that correspond to popularly used variables in formulas. +export function defineVariableTable() { + return Table.define({ + name: 'variable', + columns: ['a', 'b', 'c', 'd', 't', 'u', 'v', 'x', 'y', 'z'] + }); +} + +export interface ContentTable { + contentId: number; + text: string; + contentPosts: string; +} + +// this table is for testing snakeName related stuff +export function defineContentTable() { + return Table.define({ + name: 'content', + columns: ['content_id', 'text', 'content_posts'], + snakeToCamel: true + }); +} + +export { customTest as test }; diff --git a/test/dialects/table-tests.js b/test/dialects/table-tests.js deleted file mode 100644 index 6740a7c8..00000000 --- a/test/dialects/table-tests.js +++ /dev/null @@ -1,675 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var user = Harness.defineUserTable(); - -Harness.test({ - query: user.select(user.id).from(user), - pg: { - text : 'SELECT "user"."id" FROM "user"', - string: 'SELECT "user"."id" FROM "user"' - }, - sqlite: { - text : 'SELECT "user"."id" FROM "user"', - string: 'SELECT "user"."id" FROM "user"' - }, - mysql: { - text : 'SELECT `user`.`id` FROM `user`', - string: 'SELECT `user`.`id` FROM `user`' - }, - mssql: { - text : 'SELECT [user].[id] FROM [user]', - string: 'SELECT [user].[id] FROM [user]' - }, - oracle: { - text : 'SELECT "user"."id" FROM "user"', - string: 'SELECT "user"."id" FROM "user"' - }, - params: [] -}); - -Harness.test({ - query: user.select(user.id, user.name).from(user), - pg: { - text : 'SELECT "user"."id", "user"."name" FROM "user"', - string: 'SELECT "user"."id", "user"."name" FROM "user"' - }, - sqlite: { - text : 'SELECT "user"."id", "user"."name" FROM "user"', - string: 'SELECT "user"."id", "user"."name" FROM "user"' - }, - mysql: { - text : 'SELECT `user`.`id`, `user`.`name` FROM `user`', - string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' - }, - mssql: { - text : 'SELECT [user].[id], [user].[name] FROM [user]', - string: 'SELECT [user].[id], [user].[name] FROM [user]' - }, - oracle: { - text : 'SELECT "user"."id", "user"."name" FROM "user"', - string: 'SELECT "user"."id", "user"."name" FROM "user"' - }, - params: [] -}); - -Harness.test({ - query: user.select(user.star()).from(user), - pg: { - text : 'SELECT "user".* FROM "user"', - string: 'SELECT "user".* FROM "user"' - }, - sqlite: { - text : 'SELECT "user".* FROM "user"', - string: 'SELECT "user".* FROM "user"' - }, - mysql: { - text : 'SELECT `user`.* FROM `user`', - string: 'SELECT `user`.* FROM `user`' - }, - mssql: { - text : 'SELECT [user].* FROM [user]', - string: 'SELECT [user].* FROM [user]' - }, - oracle: { - text : 'SELECT "user".* FROM "user"', - string: 'SELECT "user".* FROM "user"' - }, - params: [] -}); - -Harness.test({ - query: user.select(user.id, [ user.name ]).from(user), - pg: { - text: 'SELECT "user"."id", "user"."name" FROM "user"', - string: 'SELECT "user"."id", "user"."name" FROM "user"' - }, - sqlite: { - text: 'SELECT "user"."id", "user"."name" FROM "user"', - string: 'SELECT "user"."id", "user"."name" FROM "user"' - }, - mysql: { - text: 'SELECT `user`.`id`, `user`.`name` FROM `user`', - string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' - }, - oracle: { - text: 'SELECT "user"."id", "user"."name" FROM "user"', - string: 'SELECT "user"."id", "user"."name" FROM "user"' - }, - params: [] -}); - -Harness.test({ - query: user.select([ user.id ], user.name).from(user), - pg: { - text: 'SELECT "user"."id", "user"."name" FROM "user"', - string: 'SELECT "user"."id", "user"."name" FROM "user"' - }, - sqlite: { - text: 'SELECT "user"."id", "user"."name" FROM "user"', - string: 'SELECT "user"."id", "user"."name" FROM "user"' - }, - mysql: { - text: 'SELECT `user`.`id`, `user`.`name` FROM `user`', - string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' - }, - oracle: { - text: 'SELECT "user"."id", "user"."name" FROM "user"', - string: 'SELECT "user"."id", "user"."name" FROM "user"' - }, - params: [] -}); - -Harness.test({ - query: user.select([ user.id , user.name ]).from(user), - pg: { - text: 'SELECT "user"."id", "user"."name" FROM "user"', - string: 'SELECT "user"."id", "user"."name" FROM "user"' - }, - sqlite: { - text: 'SELECT "user"."id", "user"."name" FROM "user"', - string: 'SELECT "user"."id", "user"."name" FROM "user"' - }, - mysql: { - text: 'SELECT `user`.`id`, `user`.`name` FROM `user`', - string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' - }, - oracle: { - text: 'SELECT "user"."id", "user"."name" FROM "user"', - string: 'SELECT "user"."id", "user"."name" FROM "user"' - }, - params: [] -}); - -Harness.test({ - query: user.select(user.star(), user.star({ prefix: 'foo_' }), user.star({ prefix: 'bar_' })).from(user), - pg: { - text: 'SELECT "user".*, "user"."id" AS "foo_id", "user"."name" AS "foo_name", "user"."id" AS "bar_id", "user"."name" AS "bar_name" FROM "user"', - string: 'SELECT "user".*, "user"."id" AS "foo_id", "user"."name" AS "foo_name", "user"."id" AS "bar_id", "user"."name" AS "bar_name" FROM "user"' - }, - sqlite: { - text: 'SELECT "user".*, "user"."id" AS "foo_id", "user"."name" AS "foo_name", "user"."id" AS "bar_id", "user"."name" AS "bar_name" FROM "user"', - string: 'SELECT "user".*, "user"."id" AS "foo_id", "user"."name" AS "foo_name", "user"."id" AS "bar_id", "user"."name" AS "bar_name" FROM "user"' - }, - mysql: { - text: 'SELECT `user`.*, `user`.`id` AS `foo_id`, `user`.`name` AS `foo_name`, `user`.`id` AS `bar_id`, `user`.`name` AS `bar_name` FROM `user`', - string: 'SELECT `user`.*, `user`.`id` AS `foo_id`, `user`.`name` AS `foo_name`, `user`.`id` AS `bar_id`, `user`.`name` AS `bar_name` FROM `user`' - }, - oracle: { - text: 'SELECT "user".*, "user"."id" "foo_id", "user"."name" "foo_name", "user"."id" "bar_id", "user"."name" "bar_name" FROM "user"', - string: 'SELECT "user".*, "user"."id" "foo_id", "user"."name" "foo_name", "user"."id" "bar_id", "user"."name" "bar_name" FROM "user"' - }, - params: [] -}); - -Harness.test({ - query: user.select(user.id).from(user).where(user.name.equals('foo')), - pg: { - text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', - string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'foo\')' - }, - sqlite: { - text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', - string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'foo\')' - }, - mysql: { - text : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', - string: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = \'foo\')' - }, - mssql: { - text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = @1)', - string: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = \'foo\')' - }, - oracle: { - text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = :1)', - string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'foo\')' - }, - params: ['foo'] -}); - -Harness.test({ - query: user.select(user.id).from(user).where(user.name.equals('foo').or(user.name.equals('bar'))), - pg: { - text : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))', - string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = \'foo\') OR ("user"."name" = \'bar\'))' - }, - sqlite: { - text : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))', - string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = \'foo\') OR ("user"."name" = \'bar\'))' - }, - mysql: { - text : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) OR (`user`.`name` = ?))', - string: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = \'foo\') OR (`user`.`name` = \'bar\'))' - }, - mssql: { - text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = @1) OR ([user].[name] = @2))', - string: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = \'foo\') OR ([user].[name] = \'bar\'))' - }, - oracle: { - text : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = :1) OR ("user"."name" = :2))', - string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = \'foo\') OR ("user"."name" = \'bar\'))' - }, - params: ['foo', 'bar'] -}); - -Harness.test({ - query: user.select(user.id).from(user).where(user.name.equals('foo').and(user.name.equals('bar'))), - pg: { - text : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) AND ("user"."name" = $2))', - string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = \'foo\') AND ("user"."name" = \'bar\'))' - }, - sqlite: { - text : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) AND ("user"."name" = $2))', - string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = \'foo\') AND ("user"."name" = \'bar\'))' - }, - mysql: { - text : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) AND (`user`.`name` = ?))', - string: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = \'foo\') AND (`user`.`name` = \'bar\'))' - }, - mssql: { - text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = @1) AND ([user].[name] = @2))', - string: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = \'foo\') AND ([user].[name] = \'bar\'))' - }, - oracle: { - text : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = :1) AND ("user"."name" = :2))', - string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = \'foo\') AND ("user"."name" = \'bar\'))' - }, - params: ['foo', 'bar'] -}); - -Harness.test({ - query: user.select(user.id).from(user).where(user.name.equals('foo')).or(user.name.equals('bar')), - pg: { - text : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))', - string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = \'foo\') OR ("user"."name" = \'bar\'))' - }, - sqlite: { - text : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))', - string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = \'foo\') OR ("user"."name" = \'bar\'))' - }, - mysql: { - text : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) OR (`user`.`name` = ?))', - string: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = \'foo\') OR (`user`.`name` = \'bar\'))' - }, - mssql: { - text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = @1) OR ([user].[name] = @2))', - string: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = \'foo\') OR ([user].[name] = \'bar\'))' - }, - oracle: { - text : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = :1) OR ("user"."name" = :2))', - string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = \'foo\') OR ("user"."name" = \'bar\'))' - }, - params: ['foo', 'bar'] -}); - -Harness.test({ - query: user.select(user.id).from(user).where(user.name.equals('foo')).or(user.name.equals('baz')).and(user.name.equals('bar')), - pg: { - text : 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) OR ("user"."name" = $2)) AND ("user"."name" = $3))', - string: 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = \'foo\') OR ("user"."name" = \'baz\')) AND ("user"."name" = \'bar\'))' - }, - sqlite: { - text : 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) OR ("user"."name" = $2)) AND ("user"."name" = $3))', - string: 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = \'foo\') OR ("user"."name" = \'baz\')) AND ("user"."name" = \'bar\'))' - }, - mysql: { - text : 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = ?) OR (`user`.`name` = ?)) AND (`user`.`name` = ?))', - string: 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = \'foo\') OR (`user`.`name` = \'baz\')) AND (`user`.`name` = \'bar\'))' - }, - mssql: { - text : 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = @1) OR ([user].[name] = @2)) AND ([user].[name] = @3))', - string: 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = \'foo\') OR ([user].[name] = \'baz\')) AND ([user].[name] = \'bar\'))' - }, - oracle: { - text : 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = :1) OR ("user"."name" = :2)) AND ("user"."name" = :3))', - string: 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = \'foo\') OR ("user"."name" = \'baz\')) AND ("user"."name" = \'bar\'))' - }, - params: ['foo', 'baz', 'bar'] -}); - -Harness.test({ - query: user.select(user.id).from(user).where(user.name.in(['foo', 'bar'])), - pg: { - text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN ($1, $2))', - string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN (\'foo\', \'bar\'))' - }, - sqlite: { - text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN ($1, $2))', - string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN (\'foo\', \'bar\'))' - }, - mysql: { - text : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` IN (?, ?))', - string: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` IN (\'foo\', \'bar\'))' - }, - mssql: { - text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] IN (@1, @2))', - string: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] IN (\'foo\', \'bar\'))' - }, - oracle: { - text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN (:1, :2))', - string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN (\'foo\', \'bar\'))' - }, - params: ['foo', 'bar'] -}); - -Harness.test({ - query: user.select(user.id).from(user).where(user.name.in(['foo', 'bar']).and(user.id.equals(1))), - pg: { - text : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" IN ($1, $2)) AND ("user"."id" = $3))', - string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" IN (\'foo\', \'bar\')) AND ("user"."id" = 1))' - }, - sqlite: { - text : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" IN ($1, $2)) AND ("user"."id" = $3))', - string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" IN (\'foo\', \'bar\')) AND ("user"."id" = 1))' - }, - mysql: { - text : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` IN (?, ?)) AND (`user`.`id` = ?))', - string: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` IN (\'foo\', \'bar\')) AND (`user`.`id` = 1))' - }, - mssql: { - text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] IN (@1, @2)) AND ([user].[id] = @3))', - string: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] IN (\'foo\', \'bar\')) AND ([user].[id] = 1))' - }, - oracle: { - text : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" IN (:1, :2)) AND ("user"."id" = :3))', - string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" IN (\'foo\', \'bar\')) AND ("user"."id" = 1))' - }, - params: ['foo', 'bar', 1] -}); - -Harness.test({ - query: user.select(user.columns), - pg: { - text : 'SELECT "user"."id", "user"."name" FROM "user"', - string: 'SELECT "user"."id", "user"."name" FROM "user"' - }, - sqlite: { - text : 'SELECT "user"."id", "user"."name" FROM "user"', - string: 'SELECT "user"."id", "user"."name" FROM "user"' - }, - mysql: { - text : 'SELECT `user`.`id`, `user`.`name` FROM `user`', - string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' - }, - mssql: { - text : 'SELECT [user].[id], [user].[name] FROM [user]', - string: 'SELECT [user].[id], [user].[name] FROM [user]' - }, - oracle: { - text : 'SELECT "user"."id", "user"."name" FROM "user"', - string: 'SELECT "user"."id", "user"."name" FROM "user"' - }, - params: [] -}); - - -Harness.test({ - query: user - .select(user.id) - .from(user) - .where( - user.name.equals('boom') - .and(user.id.equals(1))).or( - user.name.equals('bang').and(user.id.equals(2))), - pg: { - text : 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) AND ("user"."id" = $2)) OR (("user"."name" = $3) AND ("user"."id" = $4)))', - string: 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = \'boom\') AND ("user"."id" = 1)) OR (("user"."name" = \'bang\') AND ("user"."id" = 2)))' - }, - sqlite: { - text : 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) AND ("user"."id" = $2)) OR (("user"."name" = $3) AND ("user"."id" = $4)))', - string: 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = \'boom\') AND ("user"."id" = 1)) OR (("user"."name" = \'bang\') AND ("user"."id" = 2)))' - }, - mysql: { - text : 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = ?) AND (`user`.`id` = ?)) OR ((`user`.`name` = ?) AND (`user`.`id` = ?)))', - string: 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = \'boom\') AND (`user`.`id` = 1)) OR ((`user`.`name` = \'bang\') AND (`user`.`id` = 2)))' - }, - mssql: { - text : 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = @1) AND ([user].[id] = @2)) OR (([user].[name] = @3) AND ([user].[id] = @4)))', - string: 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = \'boom\') AND ([user].[id] = 1)) OR (([user].[name] = \'bang\') AND ([user].[id] = 2)))' - }, - oracle: { - text : 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = :1) AND ("user"."id" = :2)) OR (("user"."name" = :3) AND ("user"."id" = :4)))', - string: 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = \'boom\') AND ("user"."id" = 1)) OR (("user"."name" = \'bang\') AND ("user"."id" = 2)))' - }, - params: ['boom', 1, 'bang', 2] -}); - -Harness.test({ - query: user.select(user.name.as('user name'), user.id.as('user id')).from(user), - pg: { - text : 'SELECT "user"."name" AS "user name", "user"."id" AS "user id" FROM "user"', - string: 'SELECT "user"."name" AS "user name", "user"."id" AS "user id" FROM "user"' - }, - sqlite: { - text : 'SELECT "user"."name" AS "user name", "user"."id" AS "user id" FROM "user"', - string: 'SELECT "user"."name" AS "user name", "user"."id" AS "user id" FROM "user"' - }, - mysql: { - text : 'SELECT `user`.`name` AS `user name`, `user`.`id` AS `user id` FROM `user`', - string: 'SELECT `user`.`name` AS `user name`, `user`.`id` AS `user id` FROM `user`' - }, - mssql: { - text : 'SELECT [user].[name] AS [user name], [user].[id] AS [user id] FROM [user]', - string: 'SELECT [user].[name] AS [user name], [user].[id] AS [user id] FROM [user]' - }, - oracle: { - text : 'SELECT "user"."name" "user name", "user"."id" "user id" FROM "user"', - string: 'SELECT "user"."name" "user name", "user"."id" "user id" FROM "user"' - }, - params: [] -}); - -Harness.test({ - query: user.select(user.name.as('user name')).from(user).where(user.name.equals('brian')), - pg: { - text : 'SELECT "user"."name" AS "user name" FROM "user" WHERE ("user"."name" = $1)', - string: 'SELECT "user"."name" AS "user name" FROM "user" WHERE ("user"."name" = \'brian\')' - }, - sqlite: { - text : 'SELECT "user"."name" AS "user name" FROM "user" WHERE ("user"."name" = $1)', - string: 'SELECT "user"."name" AS "user name" FROM "user" WHERE ("user"."name" = \'brian\')' - }, - mysql: { - text : 'SELECT `user`.`name` AS `user name` FROM `user` WHERE (`user`.`name` = ?)', - string: 'SELECT `user`.`name` AS `user name` FROM `user` WHERE (`user`.`name` = \'brian\')' - }, - mssql: { - text : 'SELECT [user].[name] AS [user name] FROM [user] WHERE ([user].[name] = @1)', - string: 'SELECT [user].[name] AS [user name] FROM [user] WHERE ([user].[name] = \'brian\')' - }, - oracle: { - text : 'SELECT "user"."name" "user name" FROM "user" WHERE ("user"."name" = :1)', - string: 'SELECT "user"."name" "user name" FROM "user" WHERE ("user"."name" = \'brian\')' - }, - params: ['brian'] -}); - -Harness.test({ - query: user.select(user.name).from(user).where(user.name.equals('brian')), - pg: { - text : 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = $1)', - string: 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = \'brian\')' - }, - sqlite: { - text : 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = $1)', - string: 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = \'brian\')' - }, - mysql: { - text : 'SELECT `user`.`name` FROM `user` WHERE (`user`.`name` = ?)', - string: 'SELECT `user`.`name` FROM `user` WHERE (`user`.`name` = \'brian\')' - }, - mssql: { - text : 'SELECT [user].[name] FROM [user] WHERE ([user].[name] = @1)', - string: 'SELECT [user].[name] FROM [user] WHERE ([user].[name] = \'brian\')' - }, - oracle: { - text : 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = :1)', - string: 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = \'brian\')' - }, - params: ['brian'] -}); - -Harness.test({ - query: user.select('name').from('user').where('name <> NULL'), - pg: { - text : 'SELECT name FROM user WHERE (name <> NULL)', - string: 'SELECT name FROM user WHERE (name <> NULL)' - }, - sqlite: { - text : 'SELECT name FROM user WHERE (name <> NULL)', - string: 'SELECT name FROM user WHERE (name <> NULL)' - }, - mysql: { - text : 'SELECT name FROM user WHERE (name <> NULL)', - string: 'SELECT name FROM user WHERE (name <> NULL)' - }, - mssql: { - text : 'SELECT name FROM user WHERE (name <> NULL)', - string: 'SELECT name FROM user WHERE (name <> NULL)' - }, - oracle: { - text : 'SELECT name FROM user WHERE (name <> NULL)', - string: 'SELECT name FROM user WHERE (name <> NULL)' - }, - params: [] -}); - -Harness.test({ - query: user.select('name,id').from('user').where('name <> NULL'), - pg: { - text : 'SELECT name,id FROM user WHERE (name <> NULL)', - string: 'SELECT name,id FROM user WHERE (name <> NULL)' - }, - sqlite: { - text : 'SELECT name,id FROM user WHERE (name <> NULL)', - string: 'SELECT name,id FROM user WHERE (name <> NULL)' - }, - mysql: { - text : 'SELECT name,id FROM user WHERE (name <> NULL)', - string: 'SELECT name,id FROM user WHERE (name <> NULL)' - }, - mssql: { - text : 'SELECT name,id FROM user WHERE (name <> NULL)', - string: 'SELECT name,id FROM user WHERE (name <> NULL)' - }, - oracle: { - text : 'SELECT name,id FROM user WHERE (name <> NULL)', - string: 'SELECT name,id FROM user WHERE (name <> NULL)' - }, - params: [] -}); - -Harness.test({ - query: user.select('name', 'id').from('user').where('name <> NULL'), - pg: { - text : 'SELECT name, id FROM user WHERE (name <> NULL)', - string: 'SELECT name, id FROM user WHERE (name <> NULL)' - }, - sqlite: { - text : 'SELECT name, id FROM user WHERE (name <> NULL)', - string: 'SELECT name, id FROM user WHERE (name <> NULL)' - }, - mysql: { - text : 'SELECT name, id FROM user WHERE (name <> NULL)', - string: 'SELECT name, id FROM user WHERE (name <> NULL)' - }, - mssql: { - text : 'SELECT name, id FROM user WHERE (name <> NULL)', - string: 'SELECT name, id FROM user WHERE (name <> NULL)' - }, - oracle: { - text : 'SELECT name, id FROM user WHERE (name <> NULL)', - string: 'SELECT name, id FROM user WHERE (name <> NULL)' - }, - params: [] -}); - -Harness.test({ - query: user.select('name', 'id').from('user').where('name <> NULL').and('id <> NULL'), - pg: { - text : 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', - string: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))' - }, - sqlite: { - text : 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', - string: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))' - }, - mysql: { - text : 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', - string: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))' - }, - mssql: { - text : 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', - string: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))' - }, - oracle: { - text : 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', - string: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))' - }, - params: [] -}); - -Harness.test({ - query: user.select('name').from('user').where({ - name: 'brian' - }), - pg: { - text : 'SELECT name FROM user WHERE ("user"."name" = $1)', - string: 'SELECT name FROM user WHERE ("user"."name" = \'brian\')' - }, - sqlite: { - text : 'SELECT name FROM user WHERE ("user"."name" = $1)', - string: 'SELECT name FROM user WHERE ("user"."name" = \'brian\')' - }, - mysql: { - text : 'SELECT name FROM user WHERE (`user`.`name` = ?)', - string: 'SELECT name FROM user WHERE (`user`.`name` = \'brian\')' - }, - mssql: { - text : 'SELECT name FROM user WHERE ([user].[name] = @1)', - string: 'SELECT name FROM user WHERE ([user].[name] = \'brian\')' - }, - oracle: { - text : 'SELECT name FROM user WHERE ("user"."name" = :1)', - string: 'SELECT name FROM user WHERE ("user"."name" = \'brian\')' - }, - params: ['brian'] -}); - -Harness.test({ - query: user.select('name').from('user').where({ - name: 'brian', - id: 1 - }), - pg: { - text : 'SELECT name FROM user WHERE (("user"."name" = $1) AND ("user"."id" = $2))', - string: 'SELECT name FROM user WHERE (("user"."name" = \'brian\') AND ("user"."id" = 1))' - }, - sqlite: { - text : 'SELECT name FROM user WHERE (("user"."name" = $1) AND ("user"."id" = $2))', - string: 'SELECT name FROM user WHERE (("user"."name" = \'brian\') AND ("user"."id" = 1))' - }, - mysql: { - text : 'SELECT name FROM user WHERE ((`user`.`name` = ?) AND (`user`.`id` = ?))', - string: 'SELECT name FROM user WHERE ((`user`.`name` = \'brian\') AND (`user`.`id` = 1))' - }, - mssql: { - text : 'SELECT name FROM user WHERE (([user].[name] = @1) AND ([user].[id] = @2))', - string: 'SELECT name FROM user WHERE (([user].[name] = \'brian\') AND ([user].[id] = 1))' - }, - oracle: { - text : 'SELECT name FROM user WHERE (("user"."name" = :1) AND ("user"."id" = :2))', - string: 'SELECT name FROM user WHERE (("user"."name" = \'brian\') AND ("user"."id" = 1))' - }, - params: ['brian', 1] -}); - -Harness.test({ - query: user.select(user.name.as('quote"quote"tick`tick`')), - pg: { - text : 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"', - string: 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"' - }, - sqlite: { - text : 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"', - string: 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"' - }, - mysql: { - text : 'SELECT `user`.`name` AS `quote"quote"tick``tick``` FROM `user`', - string: 'SELECT `user`.`name` AS `quote"quote"tick``tick``` FROM `user`' - }, - mssql: { - text : 'SELECT [user].[name] AS [quote"quote"tick`tick`] FROM [user]', - string: 'SELECT [user].[name] AS [quote"quote"tick`tick`] FROM [user]' - }, - oracle: { - text : 'SELECT "user"."name" "quote""quote""tick`tick`" FROM "user"', - string: 'SELECT "user"."name" "quote""quote""tick`tick`" FROM "user"' - }, - params: [] -}); - -Harness.test({ - query: user.select(user.star()).where(user.id.in(user.subQuery().select(user.id))), - pg: { - text : 'SELECT "user".* FROM "user" WHERE ("user"."id" IN (SELECT "user"."id" FROM "user"))', - string: 'SELECT "user".* FROM "user" WHERE ("user"."id" IN (SELECT "user"."id" FROM "user"))' - }, - sqlite: { - text : 'SELECT "user".* FROM "user" WHERE ("user"."id" IN (SELECT "user"."id" FROM "user"))', - string: 'SELECT "user".* FROM "user" WHERE ("user"."id" IN (SELECT "user"."id" FROM "user"))' - }, - mysql: { - text : 'SELECT `user`.* FROM `user` WHERE (`user`.`id` IN (SELECT `user`.`id` FROM `user`))', - string: 'SELECT `user`.* FROM `user` WHERE (`user`.`id` IN (SELECT `user`.`id` FROM `user`))' - }, - mssql: { - text : 'SELECT [user].* FROM [user] WHERE ([user].[id] IN (SELECT [user].[id] FROM [user]))', - string: 'SELECT [user].* FROM [user] WHERE ([user].[id] IN (SELECT [user].[id] FROM [user]))' - }, - oracle: { - text : 'SELECT "user".* FROM "user" WHERE ("user"."id" IN (SELECT "user"."id" FROM "user"))', - string: 'SELECT "user".* FROM "user" WHERE ("user"."id" IN (SELECT "user"."id" FROM "user"))' - }, - params: [] -}); diff --git a/test/dialects/table-tests.ts b/test/dialects/table-tests.ts new file mode 100644 index 00000000..7a267a0d --- /dev/null +++ b/test/dialects/table-tests.ts @@ -0,0 +1,739 @@ +import * as Harness from './support.js'; +const user = Harness.defineUserTable(); + +Harness.test({ + query: user.select(user.id).from(user), + pg: { + text: 'SELECT "user"."id" FROM "user"', + string: 'SELECT "user"."id" FROM "user"' + }, + sqlite: { + text: 'SELECT "user"."id" FROM "user"', + string: 'SELECT "user"."id" FROM "user"' + }, + mysql: { + text: 'SELECT `user`.`id` FROM `user`', + string: 'SELECT `user`.`id` FROM `user`' + }, + mssql: { + text: 'SELECT [user].[id] FROM [user]', + string: 'SELECT [user].[id] FROM [user]' + }, + oracle: { + text: 'SELECT "user"."id" FROM "user"', + string: 'SELECT "user"."id" FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: user.select(user.id, user.name).from(user), + pg: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + sqlite: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + mysql: { + text: 'SELECT `user`.`id`, `user`.`name` FROM `user`', + string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' + }, + mssql: { + text: 'SELECT [user].[id], [user].[name] FROM [user]', + string: 'SELECT [user].[id], [user].[name] FROM [user]' + }, + oracle: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: user.select(user.star()).from(user), + pg: { + text: 'SELECT "user".* FROM "user"', + string: 'SELECT "user".* FROM "user"' + }, + sqlite: { + text: 'SELECT "user".* FROM "user"', + string: 'SELECT "user".* FROM "user"' + }, + mysql: { + text: 'SELECT `user`.* FROM `user`', + string: 'SELECT `user`.* FROM `user`' + }, + mssql: { + text: 'SELECT [user].* FROM [user]', + string: 'SELECT [user].* FROM [user]' + }, + oracle: { + text: 'SELECT "user".* FROM "user"', + string: 'SELECT "user".* FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: user.select(user.id, [user.name]).from(user), + pg: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + sqlite: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + mysql: { + text: 'SELECT `user`.`id`, `user`.`name` FROM `user`', + string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' + }, + oracle: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: user.select([user.id], user.name).from(user), + pg: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + sqlite: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + mysql: { + text: 'SELECT `user`.`id`, `user`.`name` FROM `user`', + string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' + }, + oracle: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: user.select([user.id, user.name]).from(user), + pg: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + sqlite: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + mysql: { + text: 'SELECT `user`.`id`, `user`.`name` FROM `user`', + string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' + }, + oracle: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: user.select(user.star(), user.star({ prefix: 'foo_' }), user.star({ prefix: 'bar_' })).from(user), + pg: { + text: + 'SELECT "user".*, "user"."id" AS "foo_id", "user"."name" AS "foo_name", "user"."id" AS "bar_id", "user"."name" AS "bar_name" FROM "user"', + string: + 'SELECT "user".*, "user"."id" AS "foo_id", "user"."name" AS "foo_name", "user"."id" AS "bar_id", "user"."name" AS "bar_name" FROM "user"' + }, + sqlite: { + text: + 'SELECT "user".*, "user"."id" AS "foo_id", "user"."name" AS "foo_name", "user"."id" AS "bar_id", "user"."name" AS "bar_name" FROM "user"', + string: + 'SELECT "user".*, "user"."id" AS "foo_id", "user"."name" AS "foo_name", "user"."id" AS "bar_id", "user"."name" AS "bar_name" FROM "user"' + }, + mysql: { + text: + 'SELECT `user`.*, `user`.`id` AS `foo_id`, `user`.`name` AS `foo_name`, `user`.`id` AS `bar_id`, `user`.`name` AS `bar_name` FROM `user`', + string: + 'SELECT `user`.*, `user`.`id` AS `foo_id`, `user`.`name` AS `foo_name`, `user`.`id` AS `bar_id`, `user`.`name` AS `bar_name` FROM `user`' + }, + oracle: { + text: 'SELECT "user".*, "user"."id" "foo_id", "user"."name" "foo_name", "user"."id" "bar_id", "user"."name" "bar_name" FROM "user"', + string: + 'SELECT "user".*, "user"."id" "foo_id", "user"."name" "foo_name", "user"."id" "bar_id", "user"."name" "bar_name" FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: user + .select(user.id) + .from(user) + .where(user.name.equals('foo')), + pg: { + text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'foo\')' + }, + sqlite: { + text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'foo\')' + }, + mysql: { + text: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', + string: "SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = 'foo')" + }, + mssql: { + text: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = @1)', + string: "SELECT [user].[id] FROM [user] WHERE ([user].[name] = 'foo')" + }, + oracle: { + text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = :1)', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'foo\')' + }, + params: ['foo'] +}); + +Harness.test({ + query: user + .select(user.id) + .from(user) + .where(user.name.equals('foo').or(user.name.equals('bar'))), + pg: { + text: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))', + string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = \'foo\') OR ("user"."name" = \'bar\'))' + }, + sqlite: { + text: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))', + string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = \'foo\') OR ("user"."name" = \'bar\'))' + }, + mysql: { + text: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) OR (`user`.`name` = ?))', + string: "SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = 'foo') OR (`user`.`name` = 'bar'))" + }, + mssql: { + text: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = @1) OR ([user].[name] = @2))', + string: "SELECT [user].[id] FROM [user] WHERE (([user].[name] = 'foo') OR ([user].[name] = 'bar'))" + }, + oracle: { + text: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = :1) OR ("user"."name" = :2))', + string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = \'foo\') OR ("user"."name" = \'bar\'))' + }, + params: ['foo', 'bar'] +}); + +Harness.test({ + query: user + .select(user.id) + .from(user) + .where(user.name.equals('foo').and(user.name.equals('bar'))), + pg: { + text: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) AND ("user"."name" = $2))', + string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = \'foo\') AND ("user"."name" = \'bar\'))' + }, + sqlite: { + text: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) AND ("user"."name" = $2))', + string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = \'foo\') AND ("user"."name" = \'bar\'))' + }, + mysql: { + text: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) AND (`user`.`name` = ?))', + string: "SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = 'foo') AND (`user`.`name` = 'bar'))" + }, + mssql: { + text: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = @1) AND ([user].[name] = @2))', + string: "SELECT [user].[id] FROM [user] WHERE (([user].[name] = 'foo') AND ([user].[name] = 'bar'))" + }, + oracle: { + text: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = :1) AND ("user"."name" = :2))', + string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = \'foo\') AND ("user"."name" = \'bar\'))' + }, + params: ['foo', 'bar'] +}); + +Harness.test({ + query: user + .select(user.id) + .from(user) + .where(user.name.equals('foo')) + .or(user.name.equals('bar')), + pg: { + text: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))', + string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = \'foo\') OR ("user"."name" = \'bar\'))' + }, + sqlite: { + text: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))', + string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = \'foo\') OR ("user"."name" = \'bar\'))' + }, + mysql: { + text: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) OR (`user`.`name` = ?))', + string: "SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = 'foo') OR (`user`.`name` = 'bar'))" + }, + mssql: { + text: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = @1) OR ([user].[name] = @2))', + string: "SELECT [user].[id] FROM [user] WHERE (([user].[name] = 'foo') OR ([user].[name] = 'bar'))" + }, + oracle: { + text: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = :1) OR ("user"."name" = :2))', + string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = \'foo\') OR ("user"."name" = \'bar\'))' + }, + params: ['foo', 'bar'] +}); + +Harness.test({ + query: user + .select(user.id) + .from(user) + .where(user.name.equals('foo')) + .or(user.name.equals('baz')) + .and(user.name.equals('bar')), + pg: { + text: 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) OR ("user"."name" = $2)) AND ("user"."name" = $3))', + string: + 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = \'foo\') OR ("user"."name" = \'baz\')) AND ("user"."name" = \'bar\'))' + }, + sqlite: { + text: 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) OR ("user"."name" = $2)) AND ("user"."name" = $3))', + string: + 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = \'foo\') OR ("user"."name" = \'baz\')) AND ("user"."name" = \'bar\'))' + }, + mysql: { + text: 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = ?) OR (`user`.`name` = ?)) AND (`user`.`name` = ?))', + string: "SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = 'foo') OR (`user`.`name` = 'baz')) AND (`user`.`name` = 'bar'))" + }, + mssql: { + text: 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = @1) OR ([user].[name] = @2)) AND ([user].[name] = @3))', + string: "SELECT [user].[id] FROM [user] WHERE ((([user].[name] = 'foo') OR ([user].[name] = 'baz')) AND ([user].[name] = 'bar'))" + }, + oracle: { + text: 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = :1) OR ("user"."name" = :2)) AND ("user"."name" = :3))', + string: + 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = \'foo\') OR ("user"."name" = \'baz\')) AND ("user"."name" = \'bar\'))' + }, + params: ['foo', 'baz', 'bar'] +}); + +Harness.test({ + query: user + .select(user.id) + .from(user) + .where(user.name.in(['foo', 'bar'])), + pg: { + text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN ($1, $2))', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN (\'foo\', \'bar\'))' + }, + sqlite: { + text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN ($1, $2))', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN (\'foo\', \'bar\'))' + }, + mysql: { + text: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` IN (?, ?))', + string: "SELECT `user`.`id` FROM `user` WHERE (`user`.`name` IN ('foo', 'bar'))" + }, + mssql: { + text: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] IN (@1, @2))', + string: "SELECT [user].[id] FROM [user] WHERE ([user].[name] IN ('foo', 'bar'))" + }, + oracle: { + text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN (:1, :2))', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN (\'foo\', \'bar\'))' + }, + params: ['foo', 'bar'] +}); + +Harness.test({ + query: user + .select(user.id) + .from(user) + .where(user.name.in(['foo', 'bar']).and(user.id.equals(1))), + pg: { + text: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" IN ($1, $2)) AND ("user"."id" = $3))', + string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" IN (\'foo\', \'bar\')) AND ("user"."id" = 1))' + }, + sqlite: { + text: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" IN ($1, $2)) AND ("user"."id" = $3))', + string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" IN (\'foo\', \'bar\')) AND ("user"."id" = 1))' + }, + mysql: { + text: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` IN (?, ?)) AND (`user`.`id` = ?))', + string: "SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` IN ('foo', 'bar')) AND (`user`.`id` = 1))" + }, + mssql: { + text: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] IN (@1, @2)) AND ([user].[id] = @3))', + string: "SELECT [user].[id] FROM [user] WHERE (([user].[name] IN ('foo', 'bar')) AND ([user].[id] = 1))" + }, + oracle: { + text: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" IN (:1, :2)) AND ("user"."id" = :3))', + string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" IN (\'foo\', \'bar\')) AND ("user"."id" = 1))' + }, + params: ['foo', 'bar', 1] +}); + +Harness.test({ + query: user.select(user.columns), + pg: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + sqlite: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + mysql: { + text: 'SELECT `user`.`id`, `user`.`name` FROM `user`', + string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' + }, + mssql: { + text: 'SELECT [user].[id], [user].[name] FROM [user]', + string: 'SELECT [user].[id], [user].[name] FROM [user]' + }, + oracle: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: user + .select(user.id) + .from(user) + .where(user.name.equals('boom').and(user.id.equals(1))) + .or(user.name.equals('bang').and(user.id.equals(2))), + pg: { + text: + 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) AND ("user"."id" = $2)) OR (("user"."name" = $3) AND ("user"."id" = $4)))', + string: + 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = \'boom\') AND ("user"."id" = 1)) OR (("user"."name" = \'bang\') AND ("user"."id" = 2)))' + }, + sqlite: { + text: + 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) AND ("user"."id" = $2)) OR (("user"."name" = $3) AND ("user"."id" = $4)))', + string: + 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = \'boom\') AND ("user"."id" = 1)) OR (("user"."name" = \'bang\') AND ("user"."id" = 2)))' + }, + mysql: { + text: + 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = ?) AND (`user`.`id` = ?)) OR ((`user`.`name` = ?) AND (`user`.`id` = ?)))', + string: + "SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = 'boom') AND (`user`.`id` = 1)) OR ((`user`.`name` = 'bang') AND (`user`.`id` = 2)))" + }, + mssql: { + text: + 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = @1) AND ([user].[id] = @2)) OR (([user].[name] = @3) AND ([user].[id] = @4)))', + string: + "SELECT [user].[id] FROM [user] WHERE ((([user].[name] = 'boom') AND ([user].[id] = 1)) OR (([user].[name] = 'bang') AND ([user].[id] = 2)))" + }, + oracle: { + text: + 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = :1) AND ("user"."id" = :2)) OR (("user"."name" = :3) AND ("user"."id" = :4)))', + string: + 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = \'boom\') AND ("user"."id" = 1)) OR (("user"."name" = \'bang\') AND ("user"."id" = 2)))' + }, + params: ['boom', 1, 'bang', 2] +}); + +Harness.test({ + query: user.select(user.name.as('user name'), user.id.as('user id')).from(user), + pg: { + text: 'SELECT "user"."name" AS "user name", "user"."id" AS "user id" FROM "user"', + string: 'SELECT "user"."name" AS "user name", "user"."id" AS "user id" FROM "user"' + }, + sqlite: { + text: 'SELECT "user"."name" AS "user name", "user"."id" AS "user id" FROM "user"', + string: 'SELECT "user"."name" AS "user name", "user"."id" AS "user id" FROM "user"' + }, + mysql: { + text: 'SELECT `user`.`name` AS `user name`, `user`.`id` AS `user id` FROM `user`', + string: 'SELECT `user`.`name` AS `user name`, `user`.`id` AS `user id` FROM `user`' + }, + mssql: { + text: 'SELECT [user].[name] AS [user name], [user].[id] AS [user id] FROM [user]', + string: 'SELECT [user].[name] AS [user name], [user].[id] AS [user id] FROM [user]' + }, + oracle: { + text: 'SELECT "user"."name" "user name", "user"."id" "user id" FROM "user"', + string: 'SELECT "user"."name" "user name", "user"."id" "user id" FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: user + .select(user.name.as('user name')) + .from(user) + .where(user.name.equals('brian')), + pg: { + text: 'SELECT "user"."name" AS "user name" FROM "user" WHERE ("user"."name" = $1)', + string: 'SELECT "user"."name" AS "user name" FROM "user" WHERE ("user"."name" = \'brian\')' + }, + sqlite: { + text: 'SELECT "user"."name" AS "user name" FROM "user" WHERE ("user"."name" = $1)', + string: 'SELECT "user"."name" AS "user name" FROM "user" WHERE ("user"."name" = \'brian\')' + }, + mysql: { + text: 'SELECT `user`.`name` AS `user name` FROM `user` WHERE (`user`.`name` = ?)', + string: "SELECT `user`.`name` AS `user name` FROM `user` WHERE (`user`.`name` = 'brian')" + }, + mssql: { + text: 'SELECT [user].[name] AS [user name] FROM [user] WHERE ([user].[name] = @1)', + string: "SELECT [user].[name] AS [user name] FROM [user] WHERE ([user].[name] = 'brian')" + }, + oracle: { + text: 'SELECT "user"."name" "user name" FROM "user" WHERE ("user"."name" = :1)', + string: 'SELECT "user"."name" "user name" FROM "user" WHERE ("user"."name" = \'brian\')' + }, + params: ['brian'] +}); + +Harness.test({ + query: user + .select(user.name) + .from(user) + .where(user.name.equals('brian')), + pg: { + text: 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = $1)', + string: 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = \'brian\')' + }, + sqlite: { + text: 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = $1)', + string: 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = \'brian\')' + }, + mysql: { + text: 'SELECT `user`.`name` FROM `user` WHERE (`user`.`name` = ?)', + string: "SELECT `user`.`name` FROM `user` WHERE (`user`.`name` = 'brian')" + }, + mssql: { + text: 'SELECT [user].[name] FROM [user] WHERE ([user].[name] = @1)', + string: "SELECT [user].[name] FROM [user] WHERE ([user].[name] = 'brian')" + }, + oracle: { + text: 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = :1)', + string: 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = \'brian\')' + }, + params: ['brian'] +}); + +Harness.test({ + query: user + .select('name') + .from('user') + .where('name <> NULL'), + pg: { + text: 'SELECT name FROM user WHERE (name <> NULL)', + string: 'SELECT name FROM user WHERE (name <> NULL)' + }, + sqlite: { + text: 'SELECT name FROM user WHERE (name <> NULL)', + string: 'SELECT name FROM user WHERE (name <> NULL)' + }, + mysql: { + text: 'SELECT name FROM user WHERE (name <> NULL)', + string: 'SELECT name FROM user WHERE (name <> NULL)' + }, + mssql: { + text: 'SELECT name FROM user WHERE (name <> NULL)', + string: 'SELECT name FROM user WHERE (name <> NULL)' + }, + oracle: { + text: 'SELECT name FROM user WHERE (name <> NULL)', + string: 'SELECT name FROM user WHERE (name <> NULL)' + }, + params: [] +}); + +Harness.test({ + query: user + .select('name,id') + .from('user') + .where('name <> NULL'), + pg: { + text: 'SELECT name,id FROM user WHERE (name <> NULL)', + string: 'SELECT name,id FROM user WHERE (name <> NULL)' + }, + sqlite: { + text: 'SELECT name,id FROM user WHERE (name <> NULL)', + string: 'SELECT name,id FROM user WHERE (name <> NULL)' + }, + mysql: { + text: 'SELECT name,id FROM user WHERE (name <> NULL)', + string: 'SELECT name,id FROM user WHERE (name <> NULL)' + }, + mssql: { + text: 'SELECT name,id FROM user WHERE (name <> NULL)', + string: 'SELECT name,id FROM user WHERE (name <> NULL)' + }, + oracle: { + text: 'SELECT name,id FROM user WHERE (name <> NULL)', + string: 'SELECT name,id FROM user WHERE (name <> NULL)' + }, + params: [] +}); + +Harness.test({ + query: user + .select('name', 'id') + .from('user') + .where('name <> NULL'), + pg: { + text: 'SELECT name, id FROM user WHERE (name <> NULL)', + string: 'SELECT name, id FROM user WHERE (name <> NULL)' + }, + sqlite: { + text: 'SELECT name, id FROM user WHERE (name <> NULL)', + string: 'SELECT name, id FROM user WHERE (name <> NULL)' + }, + mysql: { + text: 'SELECT name, id FROM user WHERE (name <> NULL)', + string: 'SELECT name, id FROM user WHERE (name <> NULL)' + }, + mssql: { + text: 'SELECT name, id FROM user WHERE (name <> NULL)', + string: 'SELECT name, id FROM user WHERE (name <> NULL)' + }, + oracle: { + text: 'SELECT name, id FROM user WHERE (name <> NULL)', + string: 'SELECT name, id FROM user WHERE (name <> NULL)' + }, + params: [] +}); + +Harness.test({ + query: user + .select('name', 'id') + .from('user') + .where('name <> NULL') + .and('id <> NULL'), + pg: { + text: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', + string: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))' + }, + sqlite: { + text: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', + string: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))' + }, + mysql: { + text: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', + string: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))' + }, + mssql: { + text: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', + string: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))' + }, + oracle: { + text: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', + string: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))' + }, + params: [] +}); + +Harness.test({ + query: user + .select('name') + .from('user') + .where({ + name: 'brian' + }), + pg: { + text: 'SELECT name FROM user WHERE ("user"."name" = $1)', + string: 'SELECT name FROM user WHERE ("user"."name" = \'brian\')' + }, + sqlite: { + text: 'SELECT name FROM user WHERE ("user"."name" = $1)', + string: 'SELECT name FROM user WHERE ("user"."name" = \'brian\')' + }, + mysql: { + text: 'SELECT name FROM user WHERE (`user`.`name` = ?)', + string: "SELECT name FROM user WHERE (`user`.`name` = 'brian')" + }, + mssql: { + text: 'SELECT name FROM user WHERE ([user].[name] = @1)', + string: "SELECT name FROM user WHERE ([user].[name] = 'brian')" + }, + oracle: { + text: 'SELECT name FROM user WHERE ("user"."name" = :1)', + string: 'SELECT name FROM user WHERE ("user"."name" = \'brian\')' + }, + params: ['brian'] +}); + +Harness.test({ + query: user + .select('name') + .from('user') + .where({ + name: 'brian', + id: 1 + }), + pg: { + text: 'SELECT name FROM user WHERE (("user"."name" = $1) AND ("user"."id" = $2))', + string: 'SELECT name FROM user WHERE (("user"."name" = \'brian\') AND ("user"."id" = 1))' + }, + sqlite: { + text: 'SELECT name FROM user WHERE (("user"."name" = $1) AND ("user"."id" = $2))', + string: 'SELECT name FROM user WHERE (("user"."name" = \'brian\') AND ("user"."id" = 1))' + }, + mysql: { + text: 'SELECT name FROM user WHERE ((`user`.`name` = ?) AND (`user`.`id` = ?))', + string: "SELECT name FROM user WHERE ((`user`.`name` = 'brian') AND (`user`.`id` = 1))" + }, + mssql: { + text: 'SELECT name FROM user WHERE (([user].[name] = @1) AND ([user].[id] = @2))', + string: "SELECT name FROM user WHERE (([user].[name] = 'brian') AND ([user].[id] = 1))" + }, + oracle: { + text: 'SELECT name FROM user WHERE (("user"."name" = :1) AND ("user"."id" = :2))', + string: 'SELECT name FROM user WHERE (("user"."name" = \'brian\') AND ("user"."id" = 1))' + }, + params: ['brian', 1] +}); + +Harness.test({ + query: user.select(user.name.as('quote"quote"tick`tick`')), + pg: { + text: 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"', + string: 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"' + }, + sqlite: { + text: 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"', + string: 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"' + }, + mysql: { + text: 'SELECT `user`.`name` AS `quote"quote"tick``tick``` FROM `user`', + string: 'SELECT `user`.`name` AS `quote"quote"tick``tick``` FROM `user`' + }, + mssql: { + text: 'SELECT [user].[name] AS [quote"quote"tick`tick`] FROM [user]', + string: 'SELECT [user].[name] AS [quote"quote"tick`tick`] FROM [user]' + }, + oracle: { + text: 'SELECT "user"."name" "quote""quote""tick`tick`" FROM "user"', + string: 'SELECT "user"."name" "quote""quote""tick`tick`" FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: user.select(user.star()).where(user.id.in(user.subQuery().select(user.id))), + pg: { + text: 'SELECT "user".* FROM "user" WHERE ("user"."id" IN (SELECT "user"."id" FROM "user"))', + string: 'SELECT "user".* FROM "user" WHERE ("user"."id" IN (SELECT "user"."id" FROM "user"))' + }, + sqlite: { + text: 'SELECT "user".* FROM "user" WHERE ("user"."id" IN (SELECT "user"."id" FROM "user"))', + string: 'SELECT "user".* FROM "user" WHERE ("user"."id" IN (SELECT "user"."id" FROM "user"))' + }, + mysql: { + text: 'SELECT `user`.* FROM `user` WHERE (`user`.`id` IN (SELECT `user`.`id` FROM `user`))', + string: 'SELECT `user`.* FROM `user` WHERE (`user`.`id` IN (SELECT `user`.`id` FROM `user`))' + }, + mssql: { + text: 'SELECT [user].* FROM [user] WHERE ([user].[id] IN (SELECT [user].[id] FROM [user]))', + string: 'SELECT [user].* FROM [user] WHERE ([user].[id] IN (SELECT [user].[id] FROM [user]))' + }, + oracle: { + text: 'SELECT "user".* FROM "user" WHERE ("user"."id" IN (SELECT "user"."id" FROM "user"))', + string: 'SELECT "user".* FROM "user" WHERE ("user"."id" IN (SELECT "user"."id" FROM "user"))' + }, + params: [] +}); diff --git a/test/dialects/ternary-clause-tests.js b/test/dialects/ternary-clause-tests.js deleted file mode 100644 index 04832fbc..00000000 --- a/test/dialects/ternary-clause-tests.js +++ /dev/null @@ -1,55 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var customer = Harness.defineCustomerTable(); -var post = Harness.definePostTable(); - -Harness.test({ - query: customer.select().where(customer.age.between(18, 25)), - pg: { - text : 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN $1 AND $2)', - string: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN 18 AND 25)' - }, - sqlite: { - text : 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN $1 AND $2)', - string: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN 18 AND 25)' - }, - mysql: { - text : 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` BETWEEN ? AND ?)', - string: 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` BETWEEN 18 AND 25)' - }, - mssql: { - text : 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] BETWEEN @1 AND @2)', - string: 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] BETWEEN 18 AND 25)' - }, - oracle: { - text : 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN :1 AND :2)', - string: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN 18 AND 25)' - }, - params: [18, 25] -}); - -Harness.test({ - query: post.select().where(post.userId.between(customer.subQuery().select(customer.id.min()), customer.subQuery().select(customer.id.max()))), - pg: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."userId" BETWEEN (SELECT MIN("customer"."id") AS "id_min" FROM "customer") AND (SELECT MAX("customer"."id") AS "id_max" FROM "customer"))', - string: 'SELECT "post".* FROM "post" WHERE ("post"."userId" BETWEEN (SELECT MIN("customer"."id") AS "id_min" FROM "customer") AND (SELECT MAX("customer"."id") AS "id_max" FROM "customer"))' - }, - sqlite: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."userId" BETWEEN (SELECT MIN("customer"."id") AS "id_min" FROM "customer") AND (SELECT MAX("customer"."id") AS "id_max" FROM "customer"))', - string: 'SELECT "post".* FROM "post" WHERE ("post"."userId" BETWEEN (SELECT MIN("customer"."id") AS "id_min" FROM "customer") AND (SELECT MAX("customer"."id") AS "id_max" FROM "customer"))' - }, - mysql: { - text : 'SELECT `post`.* FROM `post` WHERE (`post`.`userId` BETWEEN (SELECT MIN(`customer`.`id`) AS `id_min` FROM `customer`) AND (SELECT MAX(`customer`.`id`) AS `id_max` FROM `customer`))', - string: 'SELECT `post`.* FROM `post` WHERE (`post`.`userId` BETWEEN (SELECT MIN(`customer`.`id`) AS `id_min` FROM `customer`) AND (SELECT MAX(`customer`.`id`) AS `id_max` FROM `customer`))' - }, - mssql: { - text : 'SELECT [post].* FROM [post] WHERE ([post].[userId] BETWEEN (SELECT MIN([customer].[id]) AS [id_min] FROM [customer]) AND (SELECT MAX([customer].[id]) AS [id_max] FROM [customer]))', - string: 'SELECT [post].* FROM [post] WHERE ([post].[userId] BETWEEN (SELECT MIN([customer].[id]) AS [id_min] FROM [customer]) AND (SELECT MAX([customer].[id]) AS [id_max] FROM [customer]))' - }, - oracle: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."userId" BETWEEN (SELECT MIN("customer"."id") "id_min" FROM "customer") AND (SELECT MAX("customer"."id") "id_max" FROM "customer"))', - string: 'SELECT "post".* FROM "post" WHERE ("post"."userId" BETWEEN (SELECT MIN("customer"."id") "id_min" FROM "customer") AND (SELECT MAX("customer"."id") "id_max" FROM "customer"))' - }, - params: [] -}); diff --git a/test/dialects/ternary-clause-tests.ts b/test/dialects/ternary-clause-tests.ts new file mode 100644 index 00000000..8a79b919 --- /dev/null +++ b/test/dialects/ternary-clause-tests.ts @@ -0,0 +1,65 @@ +import * as Harness from './support.js'; +const customer = Harness.defineCustomerTable(); +const post = Harness.definePostTable(); + +Harness.test({ + query: customer.select().where(customer.age.between(18, 25)), + pg: { + text: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN $1 AND $2)', + string: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN 18 AND 25)' + }, + sqlite: { + text: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN $1 AND $2)', + string: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN 18 AND 25)' + }, + mysql: { + text: 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` BETWEEN ? AND ?)', + string: 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` BETWEEN 18 AND 25)' + }, + mssql: { + text: 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] BETWEEN @1 AND @2)', + string: 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] BETWEEN 18 AND 25)' + }, + oracle: { + text: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN :1 AND :2)', + string: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN 18 AND 25)' + }, + params: [18, 25] +}); + +Harness.test({ + query: post + .select() + .where(post.userId.between(customer.subQuery().select(customer.id.min()), customer.subQuery().select(customer.id.max()))), + pg: { + text: + 'SELECT "post".* FROM "post" WHERE ("post"."userId" BETWEEN (SELECT MIN("customer"."id") AS "id_min" FROM "customer") AND (SELECT MAX("customer"."id") AS "id_max" FROM "customer"))', + string: + 'SELECT "post".* FROM "post" WHERE ("post"."userId" BETWEEN (SELECT MIN("customer"."id") AS "id_min" FROM "customer") AND (SELECT MAX("customer"."id") AS "id_max" FROM "customer"))' + }, + sqlite: { + text: + 'SELECT "post".* FROM "post" WHERE ("post"."userId" BETWEEN (SELECT MIN("customer"."id") AS "id_min" FROM "customer") AND (SELECT MAX("customer"."id") AS "id_max" FROM "customer"))', + string: + 'SELECT "post".* FROM "post" WHERE ("post"."userId" BETWEEN (SELECT MIN("customer"."id") AS "id_min" FROM "customer") AND (SELECT MAX("customer"."id") AS "id_max" FROM "customer"))' + }, + mysql: { + text: + 'SELECT `post`.* FROM `post` WHERE (`post`.`userId` BETWEEN (SELECT MIN(`customer`.`id`) AS `id_min` FROM `customer`) AND (SELECT MAX(`customer`.`id`) AS `id_max` FROM `customer`))', + string: + 'SELECT `post`.* FROM `post` WHERE (`post`.`userId` BETWEEN (SELECT MIN(`customer`.`id`) AS `id_min` FROM `customer`) AND (SELECT MAX(`customer`.`id`) AS `id_max` FROM `customer`))' + }, + mssql: { + text: + 'SELECT [post].* FROM [post] WHERE ([post].[userId] BETWEEN (SELECT MIN([customer].[id]) AS [id_min] FROM [customer]) AND (SELECT MAX([customer].[id]) AS [id_max] FROM [customer]))', + string: + 'SELECT [post].* FROM [post] WHERE ([post].[userId] BETWEEN (SELECT MIN([customer].[id]) AS [id_min] FROM [customer]) AND (SELECT MAX([customer].[id]) AS [id_max] FROM [customer]))' + }, + oracle: { + text: + 'SELECT "post".* FROM "post" WHERE ("post"."userId" BETWEEN (SELECT MIN("customer"."id") "id_min" FROM "customer") AND (SELECT MAX("customer"."id") "id_max" FROM "customer"))', + string: + 'SELECT "post".* FROM "post" WHERE ("post"."userId" BETWEEN (SELECT MIN("customer"."id") "id_min" FROM "customer") AND (SELECT MAX("customer"."id") "id_max" FROM "customer"))' + }, + params: [] +}); diff --git a/test/dialects/tostring-tests.js b/test/dialects/tostring-tests.js deleted file mode 100644 index 53d413e8..00000000 --- a/test/dialects/tostring-tests.js +++ /dev/null @@ -1,202 +0,0 @@ -'use strict'; - -var assert = require('assert'); -var Harness = require('./support'); -var post = Harness.definePostTable(); - -// Null -Harness.test({ - query: post.content.equals(null), - pg: { - text : '("post"."content" = $1)', - string: '("post"."content" = NULL)' - }, - sqlite: { - text : '("post"."content" = $1)', - string: '("post"."content" = NULL)' - }, - mysql: { - text : '(`post`.`content` = ?)', - string: '(`post`.`content` = NULL)' - }, - mssql: { - text : '([post].[content] = @1)', - string: '([post].[content] = NULL)' - }, - oracle: { - text : '("post"."content" = :1)', - string: '("post"."content" = NULL)' - }, - params: [null] -}); - -// Number -Harness.test({ - query: post.content.equals(3.14), - pg: { - text : '("post"."content" = $1)', - string: '("post"."content" = 3.14)' - }, - sqlite: { - text : '("post"."content" = $1)', - string: '("post"."content" = 3.14)' - }, - mysql: { - text : '(`post`.`content` = ?)', - string: '(`post`.`content` = 3.14)' - }, - mssql: { - text : '([post].[content] = @1)', - string: '([post].[content] = 3.14)' - }, - oracle: { - text : '("post"."content" = :1)', - string: '("post"."content" = 3.14)' - }, - params: [3.14] -}); - -// String -Harness.test({ - query: post.content.equals('hello\''), - pg: { - text : '("post"."content" = $1)', - string: '("post"."content" = \'hello\'\'\')' - }, - sqlite: { - text : '("post"."content" = $1)', - string: '("post"."content" = \'hello\'\'\')' - }, - mysql: { - text : '(`post`.`content` = ?)', - string: '(`post`.`content` = \'hello\'\'\')' - }, - mssql: { - text : '([post].[content] = @1)', - string: '([post].[content] = \'hello\'\'\')' - }, - oracle: { - text : '("post"."content" = :1)', - string: '("post"."content" = \'hello\'\'\')' - }, - params: ['hello\''] -}); - -// Array -Harness.test({ - query: post.content.equals([1, '2', null]), - pg: { - text : '("post"."content" = ($1, $2, $3))', - string: '("post"."content" = (1, \'2\', NULL))' - }, - sqlite: { - text : '("post"."content" = ($1, $2, $3))', - string: '("post"."content" = (1, \'2\', NULL))' - }, - mysql: { - text : '(`post`.`content` = (?, ?, ?))', - string: '(`post`.`content` = (1, \'2\', NULL))' - }, - mssql: { - text : 'SQL Server does not support arrays.', - throws: true - }, - oracle: { - text : 'SQL Server does not support arrays.', - throws: true - }, - params: [1, '2', null] -}); - -// Date -Harness.test({ - query: post.content.equals(new Date('Sat, 01 Jan 2000 00:00:00 GMT')), - pg: { - text : '("post"."content" = $1)', - string: '("post"."content" = \'2000-01-01T00:00:00.000Z\')' - }, - sqlite: { - text : '("post"."content" = $1)', - string: '("post"."content" = \'2000-01-01T00:00:00.000Z\')' - }, - mysql: { - text : '(`post`.`content` = ?)', - string: '(`post`.`content` = \'2000-01-01T00:00:00.000Z\')' - }, - mssql: { - text : '([post].[content] = @1)', - string: '([post].[content] = \'2000-01-01T00:00:00.000Z\')' - }, - oracle: { - text : '("post"."content" = :1)', - string: '("post"."content" = \'2000-01-01T00:00:00.000Z\')' - }, - params: [new Date('Sat, 01 Jan 2000 00:00:00 GMT')] -}); - -// Date to milliseconds -Harness.test({ - query: post.content.equals(new Date('Sat, 01 Jan 2000 00:00:00 GMT')), - pg: { - text : '("post"."content" = $1)', - string: '("post"."content" = \'2000-01-01T00:00:00.000Z\')' - }, - sqlite: { - text : '("post"."content" = $1)', - string: '("post"."content" = 946684800000)', - config: { - dateTimeMillis: true - } - }, - mysql: { - text : '(`post`.`content` = ?)', - string: '(`post`.`content` = \'2000-01-01T00:00:00.000Z\')' - }, - mssql: { - text : '([post].[content] = @1)', - string: '([post].[content] = \'2000-01-01T00:00:00.000Z\')' - }, - oracle: { - text : '("post"."content" = :1)', - string: '("post"."content" = \'2000-01-01T00:00:00.000Z\')' - }, - params: [new Date('Sat, 01 Jan 2000 00:00:00 GMT')] -}); - -// Object -var customObject = { - toString: function() { - return 'secretMessage'; - } -}; - -Harness.test({ - query: post.content.equals(customObject), - pg: { - text : '("post"."content" = $1)', - string: '("post"."content" = \'secretMessage\')' - }, - sqlite: { - text : '("post"."content" = $1)', - string: '("post"."content" = \'secretMessage\')' - }, - mysql: { - text : '(`post`.`content` = ?)', - string: '(`post`.`content` = \'secretMessage\')' - }, - mssql: { - text : '([post].[content] = @1)', - string: '([post].[content] = \'secretMessage\')' - }, - oracle: { - text : '("post"."content" = :1)', - string: '("post"."content" = \'secretMessage\')' - }, - params: [customObject] -}); - - -// Undefined -assert.throws(function() { - post.content.equals(undefined).toString(); -}); diff --git a/test/dialects/tostring-tests.ts b/test/dialects/tostring-tests.ts new file mode 100644 index 00000000..f999c2a4 --- /dev/null +++ b/test/dialects/tostring-tests.ts @@ -0,0 +1,225 @@ +import assert from 'assert'; +import * as Harness from './support.js'; +const post = Harness.definePostTable(); + +// Null +Harness.test({ + query: post.content.equals(null), + pg: { + text: '("post"."content" = $1)', + string: '("post"."content" = NULL)' + }, + sqlite: { + text: '("post"."content" = $1)', + string: '("post"."content" = NULL)' + }, + mysql: { + text: '(`post`.`content` = ?)', + string: '(`post`.`content` = NULL)' + }, + mssql: { + text: '([post].[content] = @1)', + string: '([post].[content] = NULL)' + }, + oracle: { + text: '("post"."content" = :1)', + string: '("post"."content" = NULL)' + }, + params: [null] +}); + +// Number +Harness.test({ + query: post.content.equals(3.14), + pg: { + text: '("post"."content" = $1)', + string: '("post"."content" = 3.14)' + }, + sqlite: { + text: '("post"."content" = $1)', + string: '("post"."content" = 3.14)' + }, + mysql: { + text: '(`post`.`content` = ?)', + string: '(`post`.`content` = 3.14)' + }, + mssql: { + text: '([post].[content] = @1)', + string: '([post].[content] = 3.14)' + }, + oracle: { + text: '("post"."content" = :1)', + string: '("post"."content" = 3.14)' + }, + params: [3.14] +}); + +// String +Harness.test({ + query: post.content.equals("hello'"), + pg: { + text: '("post"."content" = $1)', + string: '("post"."content" = \'hello\'\'\')' + }, + sqlite: { + text: '("post"."content" = $1)', + string: '("post"."content" = \'hello\'\'\')' + }, + mysql: { + text: '(`post`.`content` = ?)', + string: "(`post`.`content` = 'hello''')" + }, + mssql: { + text: '([post].[content] = @1)', + string: "([post].[content] = 'hello''')" + }, + oracle: { + text: '("post"."content" = :1)', + string: '("post"."content" = \'hello\'\'\')' + }, + params: ["hello'"] +}); + +// Array +Harness.test({ + query: post.content.equals([1, '2', null]), + pg: { + text: '("post"."content" = ($1, $2, $3))', + string: '("post"."content" = (1, \'2\', NULL))' + }, + sqlite: { + text: '("post"."content" = ($1, $2, $3))', + string: '("post"."content" = (1, \'2\', NULL))' + }, + mysql: { + text: '(`post`.`content` = (?, ?, ?))', + string: "(`post`.`content` = (1, '2', NULL))" + }, + mssql: { + text: 'SQL Server does not support arrays.', + throws: true + }, + oracle: { + text: 'SQL Server does not support arrays.', + throws: true + }, + params: [1, '2', null] +}); + +// Date +Harness.test({ + query: post.content.equals(new Date('Sat, 01 Jan 2000 00:00:00 GMT')), + pg: { + text: '("post"."content" = $1)', + string: '("post"."content" = \'2000-01-01T00:00:00.000Z\')' + }, + sqlite: { + text: '("post"."content" = $1)', + string: '("post"."content" = \'2000-01-01T00:00:00.000Z\')' + }, + mysql: { + text: '(`post`.`content` = ?)', + string: "(`post`.`content` = '2000-01-01T00:00:00.000Z')" + }, + mssql: { + text: '([post].[content] = @1)', + string: "([post].[content] = '2000-01-01T00:00:00.000Z')" + }, + oracle: { + text: '("post"."content" = :1)', + string: '("post"."content" = \'2000-01-01T00:00:00.000Z\')' + }, + params: [new Date('Sat, 01 Jan 2000 00:00:00 GMT')] +}); + +// Date to milliseconds +Harness.test({ + query: post.content.equals(new Date('Sat, 01 Jan 2000 00:00:00 GMT')), + pg: { + text: '("post"."content" = $1)', + string: '("post"."content" = \'2000-01-01T00:00:00.000Z\')' + }, + sqlite: { + text: '("post"."content" = $1)', + string: '("post"."content" = 946684800000)', + config: { + dateTimeMillis: true + } + }, + mysql: { + text: '(`post`.`content` = ?)', + string: "(`post`.`content` = '2000-01-01T00:00:00.000Z')" + }, + mssql: { + text: '([post].[content] = @1)', + string: "([post].[content] = '2000-01-01T00:00:00.000Z')" + }, + oracle: { + text: '("post"."content" = :1)', + string: '("post"."content" = \'2000-01-01T00:00:00.000Z\')' + }, + params: [new Date('Sat, 01 Jan 2000 00:00:00 GMT')] +}); + +// Date Year 0 and before +Harness.test({ + query: post.content.equals(new Date('0000-01-01T00:00:00.000Z')), + pg: { + text: '("post"."content" = $1)', + string: '("post"."content" = \'0001-01-01T00:00:00.000Z BC\')' + }, + sqlite: { + text: '("post"."content" = $1)', + string: '("post"."content" = \'0000-01-01T00:00:00.000Z\')' + }, + mysql: { + text: '(`post`.`content` = ?)', + string: "(`post`.`content` = '0000-01-01T00:00:00.000Z')" + }, + mssql: { + text: '([post].[content] = @1)', + string: "([post].[content] = '0000-01-01T00:00:00.000Z')" + }, + oracle: { + text: '("post"."content" = :1)', + string: '("post"."content" = \'0000-01-01T00:00:00.000Z\')' + }, + params: [new Date('0000-01-01T00:00:00.000Z')] +}); + +// Object +const customObject = { + toString() { + return 'secretMessage'; + } +}; + +Harness.test({ + query: post.content.equals(customObject), + pg: { + text: '("post"."content" = $1)', + string: '("post"."content" = \'secretMessage\')' + }, + sqlite: { + text: '("post"."content" = $1)', + string: '("post"."content" = \'secretMessage\')' + }, + mysql: { + text: '(`post`.`content` = ?)', + string: "(`post`.`content` = 'secretMessage')" + }, + mssql: { + text: '([post].[content] = @1)', + string: "([post].[content] = 'secretMessage')" + }, + oracle: { + text: '("post"."content" = :1)', + string: '("post"."content" = \'secretMessage\')' + }, + params: [customObject] +}); + +// Undefined +assert.throws(function() { + post.content.equals(undefined).toString(); +}); diff --git a/test/dialects/truncate-table-tests.js b/test/dialects/truncate-table-tests.js deleted file mode 100644 index cfdb04da..00000000 --- a/test/dialects/truncate-table-tests.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var post = Harness.definePostTable(); - -Harness.test({ - query: post.truncate(), - pg: { - text : 'TRUNCATE TABLE "post"', - string: 'TRUNCATE TABLE "post"' - }, - sqlite: { - text : 'DELETE FROM "post"', - string: 'DELETE FROM "post"' - }, - mysql: { - text : 'TRUNCATE TABLE `post`', - string: 'TRUNCATE TABLE `post`' - }, - mssql: { - text : 'TRUNCATE TABLE [post]', - string: 'TRUNCATE TABLE [post]' - }, - oracle: { - text : 'TRUNCATE TABLE "post"', - string: 'TRUNCATE TABLE "post"' - }, - params: [] -}); diff --git a/test/dialects/truncate-table-tests.ts b/test/dialects/truncate-table-tests.ts new file mode 100644 index 00000000..343ebf27 --- /dev/null +++ b/test/dialects/truncate-table-tests.ts @@ -0,0 +1,27 @@ +import * as Harness from './support.js'; +const post = Harness.definePostTable(); + +Harness.test({ + query: post.truncate(), + pg: { + text: 'TRUNCATE TABLE "post"', + string: 'TRUNCATE TABLE "post"' + }, + sqlite: { + text: 'DELETE FROM "post"', + string: 'DELETE FROM "post"' + }, + mysql: { + text: 'TRUNCATE TABLE `post`', + string: 'TRUNCATE TABLE `post`' + }, + mssql: { + text: 'TRUNCATE TABLE [post]', + string: 'TRUNCATE TABLE [post]' + }, + oracle: { + text: 'TRUNCATE TABLE "post"', + string: 'TRUNCATE TABLE "post"' + }, + params: [] +}); diff --git a/test/dialects/unary-clause-tests.js b/test/dialects/unary-clause-tests.js deleted file mode 100644 index 875de382..00000000 --- a/test/dialects/unary-clause-tests.js +++ /dev/null @@ -1,55 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var customer = Harness.defineCustomerTable(); -var post = Harness.definePostTable(); - -Harness.test({ - query: customer.select().where(customer.age.isNotNull()), - pg: { - text : 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)', - string: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)' - }, - sqlite: { - text : 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)', - string: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)' - }, - mysql: { - text : 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` IS NOT NULL)', - string: 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` IS NOT NULL)' - }, - mssql: { - text : 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] IS NOT NULL)', - string: 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] IS NOT NULL)' - }, - oracle: { - text : 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)', - string: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)' - }, - params: [] -}); - -Harness.test({ - query: post.select().where(post.userId. in (customer.subQuery().select(customer.id).where(customer.age.isNull()))), - pg: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer" WHERE ("customer"."age" IS NULL)))', - string: 'SELECT "post".* FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer" WHERE ("customer"."age" IS NULL)))' - }, - sqlite: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer" WHERE ("customer"."age" IS NULL)))', - string: 'SELECT "post".* FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer" WHERE ("customer"."age" IS NULL)))' - }, - mysql: { - text : 'SELECT `post`.* FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer` WHERE (`customer`.`age` IS NULL)))', - string: 'SELECT `post`.* FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer` WHERE (`customer`.`age` IS NULL)))' - }, - mssql: { - text : 'SELECT [post].* FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer] WHERE ([customer].[age] IS NULL)))', - string: 'SELECT [post].* FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer] WHERE ([customer].[age] IS NULL)))' - }, - oracle: { - text : 'SELECT "post".* FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer" WHERE ("customer"."age" IS NULL)))', - string: 'SELECT "post".* FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer" WHERE ("customer"."age" IS NULL)))' - }, - params: [] -}); diff --git a/test/dialects/unary-clause-tests.ts b/test/dialects/unary-clause-tests.ts new file mode 100644 index 00000000..e8d53ea2 --- /dev/null +++ b/test/dialects/unary-clause-tests.ts @@ -0,0 +1,70 @@ +import * as Harness from './support.js'; +const customer = Harness.defineCustomerTable(); +const post = Harness.definePostTable(); + +Harness.test({ + query: customer.select().where(customer.age.isNotNull()), + pg: { + text: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)', + string: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)' + }, + sqlite: { + text: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)', + string: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)' + }, + mysql: { + text: 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` IS NOT NULL)', + string: 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` IS NOT NULL)' + }, + mssql: { + text: 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] IS NOT NULL)', + string: 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] IS NOT NULL)' + }, + oracle: { + text: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)', + string: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)' + }, + params: [] +}); + +Harness.test({ + query: post.select().where( + post.userId.in( + customer + .subQuery() + .select(customer.id) + .where(customer.age.isNull()) + ) + ), + pg: { + text: + 'SELECT "post".* FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer" WHERE ("customer"."age" IS NULL)))', + string: + 'SELECT "post".* FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer" WHERE ("customer"."age" IS NULL)))' + }, + sqlite: { + text: + 'SELECT "post".* FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer" WHERE ("customer"."age" IS NULL)))', + string: + 'SELECT "post".* FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer" WHERE ("customer"."age" IS NULL)))' + }, + mysql: { + text: + 'SELECT `post`.* FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer` WHERE (`customer`.`age` IS NULL)))', + string: + 'SELECT `post`.* FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer` WHERE (`customer`.`age` IS NULL)))' + }, + mssql: { + text: + 'SELECT [post].* FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer] WHERE ([customer].[age] IS NULL)))', + string: + 'SELECT [post].* FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer] WHERE ([customer].[age] IS NULL)))' + }, + oracle: { + text: + 'SELECT "post".* FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer" WHERE ("customer"."age" IS NULL)))', + string: + 'SELECT "post".* FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer" WHERE ("customer"."age" IS NULL)))' + }, + params: [] +}); diff --git a/test/dialects/update-tests.js b/test/dialects/update-tests.js deleted file mode 100644 index eb3d0b3e..00000000 --- a/test/dialects/update-tests.js +++ /dev/null @@ -1,246 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var post = Harness.definePostTable(); -var user = Harness.defineUserTable(); -var variable = Harness.defineVariableTable(); - -Harness.test({ - query: post.update({ - content: 'test' - }), - pg: { - text : 'UPDATE "post" SET "content" = $1', - string: 'UPDATE "post" SET "content" = \'test\'' - }, - sqlite: { - text : 'UPDATE "post" SET "content" = $1', - string: 'UPDATE "post" SET "content" = \'test\'' - }, - mysql: { - text : 'UPDATE `post` SET `content` = ?', - string: 'UPDATE `post` SET `content` = \'test\'' - }, - mssql: { - text : 'UPDATE [post] SET [content] = @1', - string: 'UPDATE [post] SET [content] = \'test\'' - }, - oracle: { - text : 'UPDATE "post" SET "content" = :1', - string: 'UPDATE "post" SET "content" = \'test\'' - }, - params: ['test'] -}); - -Harness.test({ - query: post.update({ - content: 'test', - userId: 3 - }), - pg: { - text : 'UPDATE "post" SET "content" = $1, "userId" = $2', - string: 'UPDATE "post" SET "content" = \'test\', "userId" = 3' - }, - sqlite: { - text : 'UPDATE "post" SET "content" = $1, "userId" = $2', - string: 'UPDATE "post" SET "content" = \'test\', "userId" = 3' - }, - mysql: { - text : 'UPDATE `post` SET `content` = ?, `userId` = ?', - string: 'UPDATE `post` SET `content` = \'test\', `userId` = 3' - }, - mssql: { - text : 'UPDATE [post] SET [content] = @1, [userId] = @2', - string: 'UPDATE [post] SET [content] = \'test\', [userId] = 3' - }, - oracle: { - text : 'UPDATE "post" SET "content" = :1, "userId" = :2', - string: 'UPDATE "post" SET "content" = \'test\', "userId" = 3' - }, - params: ['test', 3] -}); - -Harness.test({ - query: post.update({ - content: null, - userId: 3 - }), - pg: { - text : 'UPDATE "post" SET "content" = $1, "userId" = $2', - string: 'UPDATE "post" SET "content" = NULL, "userId" = 3' - }, - sqlite: { - text : 'UPDATE "post" SET "content" = $1, "userId" = $2', - string: 'UPDATE "post" SET "content" = NULL, "userId" = 3' - }, - mysql: { - text : 'UPDATE `post` SET `content` = ?, `userId` = ?', - string: 'UPDATE `post` SET `content` = NULL, `userId` = 3' - }, - mssql: { - text : 'UPDATE [post] SET [content] = @1, [userId] = @2', - string: 'UPDATE [post] SET [content] = NULL, [userId] = 3' - }, - oracle: { - text : 'UPDATE "post" SET "content" = :1, "userId" = :2', - string: 'UPDATE "post" SET "content" = NULL, "userId" = 3' - }, - params: [null, 3] -}); - -Harness.test({ - query: post.update({ - content: 'test', - userId: 3 - }).where(post.content.equals('no')), - pg: { - text : 'UPDATE "post" SET "content" = $1, "userId" = $2 WHERE ("post"."content" = $3)', - string: 'UPDATE "post" SET "content" = \'test\', "userId" = 3 WHERE ("post"."content" = \'no\')' - }, - sqlite: { - text : 'UPDATE "post" SET "content" = $1, "userId" = $2 WHERE ("post"."content" = $3)', - string: 'UPDATE "post" SET "content" = \'test\', "userId" = 3 WHERE ("post"."content" = \'no\')' - }, - mysql: { - text : 'UPDATE `post` SET `content` = ?, `userId` = ? WHERE (`post`.`content` = ?)', - string: 'UPDATE `post` SET `content` = \'test\', `userId` = 3 WHERE (`post`.`content` = \'no\')' - }, - mssql: { - text : 'UPDATE [post] SET [content] = @1, [userId] = @2 WHERE ([post].[content] = @3)', - string: 'UPDATE [post] SET [content] = \'test\', [userId] = 3 WHERE ([post].[content] = \'no\')' - }, - oracle: { - text : 'UPDATE "post" SET "content" = :1, "userId" = :2 WHERE ("post"."content" = :3)', - string: 'UPDATE "post" SET "content" = \'test\', "userId" = 3 WHERE ("post"."content" = \'no\')' - }, - params: ['test', 3, 'no'] -}); - -Harness.test({ - query: post.update({ - content: user.name - }).from(user).where(post.userId.equals(user.id)), - sqlite: { - text : 'UPDATE "post" SET "content" = "user"."name" FROM "user" WHERE ("post"."userId" = "user"."id")', - string: 'UPDATE "post" SET "content" = "user"."name" FROM "user" WHERE ("post"."userId" = "user"."id")' - }, - pg: { - text : 'UPDATE "post" SET "content" = "user"."name" FROM "user" WHERE ("post"."userId" = "user"."id")', - string: 'UPDATE "post" SET "content" = "user"."name" FROM "user" WHERE ("post"."userId" = "user"."id")' - }, - mysql: { - text : 'UPDATE `post` SET `content` = `user`.`name` FROM `user` WHERE (`post`.`userId` = `user`.`id`)', - string: 'UPDATE `post` SET `content` = `user`.`name` FROM `user` WHERE (`post`.`userId` = `user`.`id`)' - }, - mssql: { - text : 'UPDATE [post] SET [content] = [user].[name] FROM [user] WHERE ([post].[userId] = [user].[id])', - string: 'UPDATE [post] SET [content] = [user].[name] FROM [user] WHERE ([post].[userId] = [user].[id])' - }, - oracle: { - text : 'UPDATE "post" SET "content" = "user"."name" FROM "user" WHERE ("post"."userId" = "user"."id")', - string: 'UPDATE "post" SET "content" = "user"."name" FROM "user" WHERE ("post"."userId" = "user"."id")' - }, - params: [] -}); - -// update() needs to prefix ambiguous source columns; prefixing target columns is not allowed -Harness.test({ - query: post.update({ - userId: user.id - }).from(user).where(post.userId.equals(user.id)), - pg: { - text : 'UPDATE "post" SET "userId" = "user"."id" FROM "user" WHERE ("post"."userId" = "user"."id")', - string: 'UPDATE "post" SET "userId" = "user"."id" FROM "user" WHERE ("post"."userId" = "user"."id")' - }, - sqlite: { - text : 'UPDATE "post" SET "userId" = "user"."id" FROM "user" WHERE ("post"."userId" = "user"."id")', - string: 'UPDATE "post" SET "userId" = "user"."id" FROM "user" WHERE ("post"."userId" = "user"."id")' - }, - mysql: { - text : 'UPDATE `post` SET `userId` = `user`.`id` FROM `user` WHERE (`post`.`userId` = `user`.`id`)', - string: 'UPDATE `post` SET `userId` = `user`.`id` FROM `user` WHERE (`post`.`userId` = `user`.`id`)' - }, - mssql: { - text : 'UPDATE [post] SET [userId] = [user].[id] FROM [user] WHERE ([post].[userId] = [user].[id])', - string: 'UPDATE [post] SET [userId] = [user].[id] FROM [user] WHERE ([post].[userId] = [user].[id])' - }, - oracle: { - text : 'UPDATE "post" SET "userId" = "user"."id" FROM "user" WHERE ("post"."userId" = "user"."id")', - string: 'UPDATE "post" SET "userId" = "user"."id" FROM "user" WHERE ("post"."userId" = "user"."id")' - }, - params: [] -}); - -// Binary updates -Harness.test({ - query: post.update({ - content: new Buffer('test') - }), - pg: { - text : 'UPDATE "post" SET "content" = $1', - string: 'UPDATE "post" SET "content" = \'\\x74657374\'' - }, - sqlite: { - text : 'UPDATE "post" SET "content" = $1', - string: 'UPDATE "post" SET "content" = x\'74657374\'' - }, - mysql: { - text : 'UPDATE `post` SET `content` = ?', - string: 'UPDATE `post` SET `content` = x\'74657374\'' - }, - oracle: { - text : 'UPDATE "post" SET "content" = :1', - string: 'UPDATE "post" SET "content" = utl_raw.cast_to_varchar2(hextoraw(\'74657374\'))' - }, - params: [new Buffer('test')] -}); - -// Boolean updates -Harness.test({ - query: variable.update({ - a: true, - b: false - }), - pg: { - text : 'UPDATE "variable" SET "a" = $1, "b" = $2', - string: 'UPDATE "variable" SET "a" = TRUE, "b" = FALSE' - }, - sqlite: { - text : 'UPDATE "variable" SET "a" = $1, "b" = $2', - string: 'UPDATE "variable" SET "a" = 1, "b" = 0' - }, - mysql: { - text : 'UPDATE `variable` SET `a` = ?, `b` = ?', - string: 'UPDATE `variable` SET `a` = TRUE, `b` = FALSE' - }, - oracle: { - text : 'UPDATE "variable" SET "a" = :1, "b" = :2', - string: 'UPDATE "variable" SET "a" = TRUE, "b" = FALSE' - }, - params: [true, false] -}); - -// Object updates -Harness.test({ - query: variable.update({ - a: {"id": 1, "value": 2}, - b: [{"id": 2, "value": 3}, {"id": 3, "value": 4}] - }), - pg: { - text : 'UPDATE "variable" SET "a" = $1, "b" = $2', - string: 'UPDATE "variable" SET "a" = \'{"id":1,"value":2}\', "b" = \'[{"id":2,"value":3},{"id":3,"value":4}]\'' - }, - sqlite: { - text : 'UPDATE "variable" SET "a" = $1, "b" = $2', - string: 'UPDATE "variable" SET "a" = \'{"id":1,"value":2}\', "b" = \'[{"id":2,"value":3},{"id":3,"value":4}]\'' - }, - mysql: { - text : 'UPDATE `variable` SET `a` = ?, `b` = ?', - string: 'UPDATE `variable` SET `a` = \'{"id":1,"value":2}\', `b` = (\'{"id":2,"value":3}\', \'{"id":3,"value":4}\')' - }, - oracle: { - text : 'UPDATE "variable" SET "a" = :1, "b" = :2', - string: 'UPDATE "variable" SET "a" = \'{"id":1,"value":2}\', "b" = (\'{"id":2,"value":3}\', \'{"id":3,"value":4}\')' - }, - params: [{"id": 1, "value": 2}, [{"id": 2, "value": 3}, {"id": 3, "value": 4}]] -}); \ No newline at end of file diff --git a/test/dialects/update-tests.ts b/test/dialects/update-tests.ts new file mode 100644 index 00000000..f0141991 --- /dev/null +++ b/test/dialects/update-tests.ts @@ -0,0 +1,253 @@ +import * as Harness from './support.js'; +const post = Harness.definePostTable(); +const user = Harness.defineUserTable(); +const variable = Harness.defineVariableTable(); + +Harness.test({ + query: post.update({ + content: 'test' + }), + pg: { + text: 'UPDATE "post" SET "content" = $1', + string: 'UPDATE "post" SET "content" = \'test\'' + }, + sqlite: { + text: 'UPDATE "post" SET "content" = $1', + string: 'UPDATE "post" SET "content" = \'test\'' + }, + mysql: { + text: 'UPDATE `post` SET `content` = ?', + string: "UPDATE `post` SET `content` = 'test'" + }, + mssql: { + text: 'UPDATE [post] SET [content] = @1', + string: "UPDATE [post] SET [content] = 'test'" + }, + oracle: { + text: 'UPDATE "post" SET "content" = :1', + string: 'UPDATE "post" SET "content" = \'test\'' + }, + params: ['test'] +}); + +Harness.test({ + query: post.update({ + content: 'test', + userId: 3 + }), + pg: { + text: 'UPDATE "post" SET "content" = $1, "userId" = $2', + string: 'UPDATE "post" SET "content" = \'test\', "userId" = 3' + }, + sqlite: { + text: 'UPDATE "post" SET "content" = $1, "userId" = $2', + string: 'UPDATE "post" SET "content" = \'test\', "userId" = 3' + }, + mysql: { + text: 'UPDATE `post` SET `content` = ?, `userId` = ?', + string: "UPDATE `post` SET `content` = 'test', `userId` = 3" + }, + mssql: { + text: 'UPDATE [post] SET [content] = @1, [userId] = @2', + string: "UPDATE [post] SET [content] = 'test', [userId] = 3" + }, + oracle: { + text: 'UPDATE "post" SET "content" = :1, "userId" = :2', + string: 'UPDATE "post" SET "content" = \'test\', "userId" = 3' + }, + params: ['test', 3] +}); + +Harness.test({ + query: post.update({ + content: null, + userId: 3 + }), + pg: { + text: 'UPDATE "post" SET "content" = $1, "userId" = $2', + string: 'UPDATE "post" SET "content" = NULL, "userId" = 3' + }, + sqlite: { + text: 'UPDATE "post" SET "content" = $1, "userId" = $2', + string: 'UPDATE "post" SET "content" = NULL, "userId" = 3' + }, + mysql: { + text: 'UPDATE `post` SET `content` = ?, `userId` = ?', + string: 'UPDATE `post` SET `content` = NULL, `userId` = 3' + }, + mssql: { + text: 'UPDATE [post] SET [content] = @1, [userId] = @2', + string: 'UPDATE [post] SET [content] = NULL, [userId] = 3' + }, + oracle: { + text: 'UPDATE "post" SET "content" = :1, "userId" = :2', + string: 'UPDATE "post" SET "content" = NULL, "userId" = 3' + }, + params: [null, 3] +}); + +Harness.test({ + query: post + .update({ + content: 'test', + userId: 3 + }) + .where(post.content.equals('no')), + pg: { + text: 'UPDATE "post" SET "content" = $1, "userId" = $2 WHERE ("post"."content" = $3)', + string: 'UPDATE "post" SET "content" = \'test\', "userId" = 3 WHERE ("post"."content" = \'no\')' + }, + sqlite: { + text: 'UPDATE "post" SET "content" = $1, "userId" = $2 WHERE ("post"."content" = $3)', + string: 'UPDATE "post" SET "content" = \'test\', "userId" = 3 WHERE ("post"."content" = \'no\')' + }, + mysql: { + text: 'UPDATE `post` SET `content` = ?, `userId` = ? WHERE (`post`.`content` = ?)', + string: "UPDATE `post` SET `content` = 'test', `userId` = 3 WHERE (`post`.`content` = 'no')" + }, + mssql: { + text: 'UPDATE [post] SET [content] = @1, [userId] = @2 WHERE ([post].[content] = @3)', + string: "UPDATE [post] SET [content] = 'test', [userId] = 3 WHERE ([post].[content] = 'no')" + }, + oracle: { + text: 'UPDATE "post" SET "content" = :1, "userId" = :2 WHERE ("post"."content" = :3)', + string: 'UPDATE "post" SET "content" = \'test\', "userId" = 3 WHERE ("post"."content" = \'no\')' + }, + params: ['test', 3, 'no'] +}); + +Harness.test({ + query: post + .update({ + content: user.name + }) + .from(user) + .where(post.userId.equals(user.id)), + sqlite: { + text: 'UPDATE "post" SET "content" = "user"."name" FROM "user" WHERE ("post"."userId" = "user"."id")', + string: 'UPDATE "post" SET "content" = "user"."name" FROM "user" WHERE ("post"."userId" = "user"."id")' + }, + pg: { + text: 'UPDATE "post" SET "content" = "user"."name" FROM "user" WHERE ("post"."userId" = "user"."id")', + string: 'UPDATE "post" SET "content" = "user"."name" FROM "user" WHERE ("post"."userId" = "user"."id")' + }, + mysql: { + text: 'UPDATE `post` SET `content` = `user`.`name` FROM `user` WHERE (`post`.`userId` = `user`.`id`)', + string: 'UPDATE `post` SET `content` = `user`.`name` FROM `user` WHERE (`post`.`userId` = `user`.`id`)' + }, + mssql: { + text: 'UPDATE [post] SET [content] = [user].[name] FROM [user] WHERE ([post].[userId] = [user].[id])', + string: 'UPDATE [post] SET [content] = [user].[name] FROM [user] WHERE ([post].[userId] = [user].[id])' + }, + oracle: { + text: 'UPDATE "post" SET "content" = "user"."name" FROM "user" WHERE ("post"."userId" = "user"."id")', + string: 'UPDATE "post" SET "content" = "user"."name" FROM "user" WHERE ("post"."userId" = "user"."id")' + }, + params: [] +}); + +// update() needs to prefix ambiguous source columns; prefixing target columns is not allowed +Harness.test({ + query: post + .update({ + userId: user.id + }) + .from(user) + .where(post.userId.equals(user.id)), + pg: { + text: 'UPDATE "post" SET "userId" = "user"."id" FROM "user" WHERE ("post"."userId" = "user"."id")', + string: 'UPDATE "post" SET "userId" = "user"."id" FROM "user" WHERE ("post"."userId" = "user"."id")' + }, + sqlite: { + text: 'UPDATE "post" SET "userId" = "user"."id" FROM "user" WHERE ("post"."userId" = "user"."id")', + string: 'UPDATE "post" SET "userId" = "user"."id" FROM "user" WHERE ("post"."userId" = "user"."id")' + }, + mysql: { + text: 'UPDATE `post` SET `userId` = `user`.`id` FROM `user` WHERE (`post`.`userId` = `user`.`id`)', + string: 'UPDATE `post` SET `userId` = `user`.`id` FROM `user` WHERE (`post`.`userId` = `user`.`id`)' + }, + mssql: { + text: 'UPDATE [post] SET [userId] = [user].[id] FROM [user] WHERE ([post].[userId] = [user].[id])', + string: 'UPDATE [post] SET [userId] = [user].[id] FROM [user] WHERE ([post].[userId] = [user].[id])' + }, + oracle: { + text: 'UPDATE "post" SET "userId" = "user"."id" FROM "user" WHERE ("post"."userId" = "user"."id")', + string: 'UPDATE "post" SET "userId" = "user"."id" FROM "user" WHERE ("post"."userId" = "user"."id")' + }, + params: [] +}); + +// Binary updates +Harness.test({ + query: post.update({ + // @ts-ignore should investigate whether this should be valid for typings + content: Buffer.from('test') + }), + pg: { + text: 'UPDATE "post" SET "content" = $1', + string: 'UPDATE "post" SET "content" = \'\\x74657374\'' + }, + sqlite: { + text: 'UPDATE "post" SET "content" = $1', + string: 'UPDATE "post" SET "content" = x\'74657374\'' + }, + mysql: { + text: 'UPDATE `post` SET `content` = ?', + string: "UPDATE `post` SET `content` = x'74657374'" + }, + oracle: { + text: 'UPDATE "post" SET "content" = :1', + string: 'UPDATE "post" SET "content" = utl_raw.cast_to_varchar2(hextoraw(\'74657374\'))' + }, + params: [Buffer.from('test')] +}); + +// Boolean updates +Harness.test({ + query: variable.update({ + a: true, + b: false + }), + pg: { + text: 'UPDATE "variable" SET "a" = $1, "b" = $2', + string: 'UPDATE "variable" SET "a" = TRUE, "b" = FALSE' + }, + sqlite: { + text: 'UPDATE "variable" SET "a" = $1, "b" = $2', + string: 'UPDATE "variable" SET "a" = 1, "b" = 0' + }, + mysql: { + text: 'UPDATE `variable` SET `a` = ?, `b` = ?', + string: 'UPDATE `variable` SET `a` = TRUE, `b` = FALSE' + }, + oracle: { + text: 'UPDATE "variable" SET "a" = :1, "b" = :2', + string: 'UPDATE "variable" SET "a" = TRUE, "b" = FALSE' + }, + params: [true, false] +}); + +// Object updates +Harness.test({ + query: variable.update({ + a: { id: 1, value: 2 }, + b: [{ id: 2, value: 3 }, { id: 3, value: 4 }] + }), + pg: { + text: 'UPDATE "variable" SET "a" = $1, "b" = $2', + string: 'UPDATE "variable" SET "a" = \'{"id":1,"value":2}\', "b" = \'[{"id":2,"value":3},{"id":3,"value":4}]\'' + }, + sqlite: { + text: 'UPDATE "variable" SET "a" = $1, "b" = $2', + string: 'UPDATE "variable" SET "a" = \'{"id":1,"value":2}\', "b" = \'[{"id":2,"value":3},{"id":3,"value":4}]\'' + }, + mysql: { + text: 'UPDATE `variable` SET `a` = ?, `b` = ?', + string: 'UPDATE `variable` SET `a` = \'{"id":1,"value":2}\', `b` = (\'{"id":2,"value":3}\', \'{"id":3,"value":4}\')' + }, + oracle: { + text: 'UPDATE "variable" SET "a" = :1, "b" = :2', + string: 'UPDATE "variable" SET "a" = \'{"id":1,"value":2}\', "b" = (\'{"id":2,"value":3}\', \'{"id":3,"value":4}\')' + }, + params: [{ id: 1, value: 2 }, [{ id: 2, value: 3 }, { id: 3, value: 4 }]] +}); diff --git a/test/dialects/value-expression-tests.js b/test/dialects/value-expression-tests.js deleted file mode 100644 index 5eaae5ae..00000000 --- a/test/dialects/value-expression-tests.js +++ /dev/null @@ -1,133 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var customer = Harness.defineCustomerTable(); -var post = Harness.definePostTable(); -var v = Harness.defineVariableTable(); - -// Test composition of binary methods +, *, -, =. -Harness.test({ - query: customer.select(customer.name, customer.income.modulo(100)).where(customer.age.plus(5).multiply(customer.age.minus(2)).equals(10)), - pg: { - text : 'SELECT "customer"."name", ("customer"."income" % $1) FROM "customer" WHERE ((("customer"."age" + $2) * ("customer"."age" - $3)) = $4)', - string: 'SELECT "customer"."name", ("customer"."income" % 100) FROM "customer" WHERE ((("customer"."age" + 5) * ("customer"."age" - 2)) = 10)' - }, - sqlite: { - text : 'SELECT "customer"."name", ("customer"."income" % $1) FROM "customer" WHERE ((("customer"."age" + $2) * ("customer"."age" - $3)) = $4)', - string: 'SELECT "customer"."name", ("customer"."income" % 100) FROM "customer" WHERE ((("customer"."age" + 5) * ("customer"."age" - 2)) = 10)' - }, - mysql: { - text : 'SELECT `customer`.`name`, (`customer`.`income` % ?) FROM `customer` WHERE (((`customer`.`age` + ?) * (`customer`.`age` - ?)) = ?)', - string: 'SELECT `customer`.`name`, (`customer`.`income` % 100) FROM `customer` WHERE (((`customer`.`age` + 5) * (`customer`.`age` - 2)) = 10)' - }, - mssql: { - text : 'SELECT [customer].[name], ([customer].[income] % @1) FROM [customer] WHERE ((([customer].[age] + @2) * ([customer].[age] - @3)) = @4)', - string: 'SELECT [customer].[name], ([customer].[income] % 100) FROM [customer] WHERE ((([customer].[age] + 5) * ([customer].[age] - 2)) = 10)' - }, - oracle: { - text : 'SELECT "customer"."name", ("customer"."income" % :1) FROM "customer" WHERE ((("customer"."age" + :2) * ("customer"."age" - :3)) = :4)', - string: 'SELECT "customer"."name", ("customer"."income" % 100) FROM "customer" WHERE ((("customer"."age" + 5) * ("customer"."age" - 2)) = 10)' - }, - params: [100, 5, 2, 10] -}); - -// Test composition of binary (e.g. +) and unary (e.g. like) methods. -Harness.test({ - query: customer.select(customer.name).where(customer.name.like(customer.id.plus('hello'))), - pg: { - text : 'SELECT "customer"."name" FROM "customer" WHERE ("customer"."name" LIKE ("customer"."id" + $1))', - string: 'SELECT "customer"."name" FROM "customer" WHERE ("customer"."name" LIKE ("customer"."id" + \'hello\'))' - }, - sqlite: { - text : 'SELECT "customer"."name" FROM "customer" WHERE ("customer"."name" LIKE ("customer"."id" + $1))', - string: 'SELECT "customer"."name" FROM "customer" WHERE ("customer"."name" LIKE ("customer"."id" + \'hello\'))' - }, - mysql: { - text : 'SELECT `customer`.`name` FROM `customer` WHERE (`customer`.`name` LIKE (`customer`.`id` + ?))', - string: 'SELECT `customer`.`name` FROM `customer` WHERE (`customer`.`name` LIKE (`customer`.`id` + \'hello\'))' - }, - mssql: { - text : 'SELECT [customer].[name] FROM [customer] WHERE ([customer].[name] LIKE ([customer].[id] + @1))', - string: 'SELECT [customer].[name] FROM [customer] WHERE ([customer].[name] LIKE ([customer].[id] + \'hello\'))' - }, - oracle: { - text : 'SELECT "customer"."name" FROM "customer" WHERE ("customer"."name" LIKE ("customer"."id" + :1))', - string: 'SELECT "customer"."name" FROM "customer" WHERE ("customer"."name" LIKE ("customer"."id" + \'hello\'))' - }, - params: ['hello'] -}); - -// Test implementing simple formulas. -// Acceleration formula. (a * t^2 / 2) + (v * t) = d -Harness.test({ - query: v.select(v.a.multiply(v.a).divide(2).plus(v.v.multiply(v.t)).equals(v.d)), - pg: { - text : 'SELECT (((("variable"."a" * "variable"."a") / $1) + ("variable"."v" * "variable"."t")) = "variable"."d") FROM "variable"', - string: 'SELECT (((("variable"."a" * "variable"."a") / 2) + ("variable"."v" * "variable"."t")) = "variable"."d") FROM "variable"' - }, - sqlite: { - text : 'SELECT (((("variable"."a" * "variable"."a") / $1) + ("variable"."v" * "variable"."t")) = "variable"."d") FROM "variable"', - string: 'SELECT (((("variable"."a" * "variable"."a") / 2) + ("variable"."v" * "variable"."t")) = "variable"."d") FROM "variable"' - }, - mysql: { - text : 'SELECT ((((`variable`.`a` * `variable`.`a`) / ?) + (`variable`.`v` * `variable`.`t`)) = `variable`.`d`) FROM `variable`', - string: 'SELECT ((((`variable`.`a` * `variable`.`a`) / 2) + (`variable`.`v` * `variable`.`t`)) = `variable`.`d`) FROM `variable`' - }, - mssql: { - text : 'SELECT (((([variable].[a] * [variable].[a]) / @1) + ([variable].[v] * [variable].[t])) = [variable].[d]) FROM [variable]', - string: 'SELECT (((([variable].[a] * [variable].[a]) / 2) + ([variable].[v] * [variable].[t])) = [variable].[d]) FROM [variable]' - }, - oracle: { - text : 'SELECT (((("variable"."a" * "variable"."a") / :1) + ("variable"."v" * "variable"."t")) = "variable"."d") FROM "variable"', - string: 'SELECT (((("variable"."a" * "variable"."a") / 2) + ("variable"."v" * "variable"."t")) = "variable"."d") FROM "variable"' - }, - params: [2] -}); - -// Pythagorean theorem. a^2 + b^2 = c^2. -Harness.test({ - query: v.select(v.a.multiply(v.a).plus(v.b.multiply(v.b)).equals(v.c.multiply(v.c))), - pg: { - text : 'SELECT ((("variable"."a" * "variable"."a") + ("variable"."b" * "variable"."b")) = ("variable"."c" * "variable"."c")) FROM "variable"', - string: 'SELECT ((("variable"."a" * "variable"."a") + ("variable"."b" * "variable"."b")) = ("variable"."c" * "variable"."c")) FROM "variable"' - }, - sqlite: { - text : 'SELECT ((("variable"."a" * "variable"."a") + ("variable"."b" * "variable"."b")) = ("variable"."c" * "variable"."c")) FROM "variable"', - string: 'SELECT ((("variable"."a" * "variable"."a") + ("variable"."b" * "variable"."b")) = ("variable"."c" * "variable"."c")) FROM "variable"' - }, - mysql: { - text : 'SELECT (((`variable`.`a` * `variable`.`a`) + (`variable`.`b` * `variable`.`b`)) = (`variable`.`c` * `variable`.`c`)) FROM `variable`', - string: 'SELECT (((`variable`.`a` * `variable`.`a`) + (`variable`.`b` * `variable`.`b`)) = (`variable`.`c` * `variable`.`c`)) FROM `variable`' - }, - mssql: { - text : 'SELECT ((([variable].[a] * [variable].[a]) + ([variable].[b] * [variable].[b])) = ([variable].[c] * [variable].[c])) FROM [variable]', - string: 'SELECT ((([variable].[a] * [variable].[a]) + ([variable].[b] * [variable].[b])) = ([variable].[c] * [variable].[c])) FROM [variable]' - }, - oracle: { - text : 'SELECT ((("variable"."a" * "variable"."a") + ("variable"."b" * "variable"."b")) = ("variable"."c" * "variable"."c")) FROM "variable"', - string: 'SELECT ((("variable"."a" * "variable"."a") + ("variable"."b" * "variable"."b")) = ("variable"."c" * "variable"."c")) FROM "variable"' - }, - params: [] -}); - -Harness.test({ - query: post.select(post.id).where(post.content.equals(new Buffer('test'))), - pg: { - text : 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = $1)', - string: 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = \'\\x74657374\')', - }, - sqlite: { - text : 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = $1)', - string: 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = x\'74657374\')', - }, - mysql: { - text : 'SELECT `post`.`id` FROM `post` WHERE (`post`.`content` = ?)', - string: 'SELECT `post`.`id` FROM `post` WHERE (`post`.`content` = x\'74657374\')', - }, - oracle: { - text : 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = :1)', - string: 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = utl_raw.cast_to_varchar2(hextoraw(\'74657374\')))', - }, - params: [new Buffer('test')] -}); - diff --git a/test/dialects/value-expression-tests.ts b/test/dialects/value-expression-tests.ts new file mode 100644 index 00000000..24dff856 --- /dev/null +++ b/test/dialects/value-expression-tests.ts @@ -0,0 +1,166 @@ +import * as Harness from './support.js'; +const customer = Harness.defineCustomerTable(); +const post = Harness.definePostTable(); +const variable = Harness.defineVariableTable(); + +// Test composition of binary methods +, *, -, =. +Harness.test({ + query: customer.select(customer.name, customer.income.modulo(100)).where( + customer.age + .plus(5) + .multiply(customer.age.minus(2)) + .equals(10) + ), + pg: { + text: + 'SELECT "customer"."name", ("customer"."income" % $1) FROM "customer" WHERE ((("customer"."age" + $2) * ("customer"."age" - $3)) = $4)', + string: + 'SELECT "customer"."name", ("customer"."income" % 100) FROM "customer" WHERE ((("customer"."age" + 5) * ("customer"."age" - 2)) = 10)' + }, + sqlite: { + text: + 'SELECT "customer"."name", ("customer"."income" % $1) FROM "customer" WHERE ((("customer"."age" + $2) * ("customer"."age" - $3)) = $4)', + string: + 'SELECT "customer"."name", ("customer"."income" % 100) FROM "customer" WHERE ((("customer"."age" + 5) * ("customer"."age" - 2)) = 10)' + }, + mysql: { + text: + 'SELECT `customer`.`name`, (`customer`.`income` % ?) FROM `customer` WHERE (((`customer`.`age` + ?) * (`customer`.`age` - ?)) = ?)', + string: + 'SELECT `customer`.`name`, (`customer`.`income` % 100) FROM `customer` WHERE (((`customer`.`age` + 5) * (`customer`.`age` - 2)) = 10)' + }, + mssql: { + text: + 'SELECT [customer].[name], ([customer].[income] % @1) FROM [customer] WHERE ((([customer].[age] + @2) * ([customer].[age] - @3)) = @4)', + string: + 'SELECT [customer].[name], ([customer].[income] % 100) FROM [customer] WHERE ((([customer].[age] + 5) * ([customer].[age] - 2)) = 10)' + }, + oracle: { + text: + 'SELECT "customer"."name", ("customer"."income" % :1) FROM "customer" WHERE ((("customer"."age" + :2) * ("customer"."age" - :3)) = :4)', + string: + 'SELECT "customer"."name", ("customer"."income" % 100) FROM "customer" WHERE ((("customer"."age" + 5) * ("customer"."age" - 2)) = 10)' + }, + params: [100, 5, 2, 10] +}); + +// Test composition of binary (e.g. +) and unary (e.g. like) methods. +Harness.test({ + query: customer.select(customer.name).where(customer.name.like(customer.id.plus('hello'))), + pg: { + text: 'SELECT "customer"."name" FROM "customer" WHERE ("customer"."name" LIKE ("customer"."id" + $1))', + string: 'SELECT "customer"."name" FROM "customer" WHERE ("customer"."name" LIKE ("customer"."id" + \'hello\'))' + }, + sqlite: { + text: 'SELECT "customer"."name" FROM "customer" WHERE ("customer"."name" LIKE ("customer"."id" + $1))', + string: 'SELECT "customer"."name" FROM "customer" WHERE ("customer"."name" LIKE ("customer"."id" + \'hello\'))' + }, + mysql: { + text: 'SELECT `customer`.`name` FROM `customer` WHERE (`customer`.`name` LIKE (`customer`.`id` + ?))', + string: "SELECT `customer`.`name` FROM `customer` WHERE (`customer`.`name` LIKE (`customer`.`id` + 'hello'))" + }, + mssql: { + text: 'SELECT [customer].[name] FROM [customer] WHERE ([customer].[name] LIKE ([customer].[id] + @1))', + string: "SELECT [customer].[name] FROM [customer] WHERE ([customer].[name] LIKE ([customer].[id] + 'hello'))" + }, + oracle: { + text: 'SELECT "customer"."name" FROM "customer" WHERE ("customer"."name" LIKE ("customer"."id" + :1))', + string: 'SELECT "customer"."name" FROM "customer" WHERE ("customer"."name" LIKE ("customer"."id" + \'hello\'))' + }, + params: ['hello'] +}); + +// Test implementing simple formulas. +// Acceleration formula. (a * t^2 / 2) + (v * t) = d +Harness.test({ + query: variable.select( + variable.a + .multiply(variable.a) + .divide(2) + .plus(variable.v.multiply(variable.t)) + .equals(variable.d) + ), + pg: { + text: 'SELECT (((("variable"."a" * "variable"."a") / $1) + ("variable"."v" * "variable"."t")) = "variable"."d") FROM "variable"', + string: 'SELECT (((("variable"."a" * "variable"."a") / 2) + ("variable"."v" * "variable"."t")) = "variable"."d") FROM "variable"' + }, + sqlite: { + text: 'SELECT (((("variable"."a" * "variable"."a") / $1) + ("variable"."v" * "variable"."t")) = "variable"."d") FROM "variable"', + string: 'SELECT (((("variable"."a" * "variable"."a") / 2) + ("variable"."v" * "variable"."t")) = "variable"."d") FROM "variable"' + }, + mysql: { + text: 'SELECT ((((`variable`.`a` * `variable`.`a`) / ?) + (`variable`.`v` * `variable`.`t`)) = `variable`.`d`) FROM `variable`', + string: 'SELECT ((((`variable`.`a` * `variable`.`a`) / 2) + (`variable`.`v` * `variable`.`t`)) = `variable`.`d`) FROM `variable`' + }, + mssql: { + text: 'SELECT (((([variable].[a] * [variable].[a]) / @1) + ([variable].[v] * [variable].[t])) = [variable].[d]) FROM [variable]', + string: 'SELECT (((([variable].[a] * [variable].[a]) / 2) + ([variable].[v] * [variable].[t])) = [variable].[d]) FROM [variable]' + }, + oracle: { + text: 'SELECT (((("variable"."a" * "variable"."a") / :1) + ("variable"."v" * "variable"."t")) = "variable"."d") FROM "variable"', + string: 'SELECT (((("variable"."a" * "variable"."a") / 2) + ("variable"."v" * "variable"."t")) = "variable"."d") FROM "variable"' + }, + params: [2] +}); + +// Pythagorean theorem. a^2 + b^2 = c^2. +Harness.test({ + query: variable.select( + variable.a + .multiply(variable.a) + .plus(variable.b.multiply(variable.b)) + .equals(variable.c.multiply(variable.c)) + ), + pg: { + text: + 'SELECT ((("variable"."a" * "variable"."a") + ("variable"."b" * "variable"."b")) = ("variable"."c" * "variable"."c")) FROM "variable"', + string: + 'SELECT ((("variable"."a" * "variable"."a") + ("variable"."b" * "variable"."b")) = ("variable"."c" * "variable"."c")) FROM "variable"' + }, + sqlite: { + text: + 'SELECT ((("variable"."a" * "variable"."a") + ("variable"."b" * "variable"."b")) = ("variable"."c" * "variable"."c")) FROM "variable"', + string: + 'SELECT ((("variable"."a" * "variable"."a") + ("variable"."b" * "variable"."b")) = ("variable"."c" * "variable"."c")) FROM "variable"' + }, + mysql: { + text: + 'SELECT (((`variable`.`a` * `variable`.`a`) + (`variable`.`b` * `variable`.`b`)) = (`variable`.`c` * `variable`.`c`)) FROM `variable`', + string: + 'SELECT (((`variable`.`a` * `variable`.`a`) + (`variable`.`b` * `variable`.`b`)) = (`variable`.`c` * `variable`.`c`)) FROM `variable`' + }, + mssql: { + text: + 'SELECT ((([variable].[a] * [variable].[a]) + ([variable].[b] * [variable].[b])) = ([variable].[c] * [variable].[c])) FROM [variable]', + string: + 'SELECT ((([variable].[a] * [variable].[a]) + ([variable].[b] * [variable].[b])) = ([variable].[c] * [variable].[c])) FROM [variable]' + }, + oracle: { + text: + 'SELECT ((("variable"."a" * "variable"."a") + ("variable"."b" * "variable"."b")) = ("variable"."c" * "variable"."c")) FROM "variable"', + string: + 'SELECT ((("variable"."a" * "variable"."a") + ("variable"."b" * "variable"."b")) = ("variable"."c" * "variable"."c")) FROM "variable"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.id).where(post.content.equals(Buffer.from('test'))), + pg: { + text: 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = $1)', + string: 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = \'\\x74657374\')' + }, + sqlite: { + text: 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = $1)', + string: 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = x\'74657374\')' + }, + mysql: { + text: 'SELECT `post`.`id` FROM `post` WHERE (`post`.`content` = ?)', + string: "SELECT `post`.`id` FROM `post` WHERE (`post`.`content` = x'74657374')" + }, + oracle: { + text: 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = :1)', + string: 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = utl_raw.cast_to_varchar2(hextoraw(\'74657374\')))' + }, + params: [Buffer.from('test')] +}); diff --git a/test/dialects/where-clause-tests.js b/test/dialects/where-clause-tests.js deleted file mode 100644 index 3282b7d9..00000000 --- a/test/dialects/where-clause-tests.js +++ /dev/null @@ -1,205 +0,0 @@ -'use strict'; - -var Harness = require('./support'); -var user = Harness.defineUserTable(); - -Harness.test({ - query: user.where(user.id.isNotNull(), user.name.isNotNull()), - pg: { - text : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', - string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' - }, - mysql: { - text : 'SELECT * FROM `user` WHERE ((`user`.`id` IS NOT NULL) AND (`user`.`name` IS NOT NULL))', - string: 'SELECT * FROM `user` WHERE ((`user`.`id` IS NOT NULL) AND (`user`.`name` IS NOT NULL))' - }, - sqlite: { - text : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', - string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' - }, - mssql: { - text : 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))', - string: 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))' - }, - oracle: { - text : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', - string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' - }, - params: [] -}); - -Harness.test({ - query: user.and(user.id.isNotNull(), user.name.isNotNull()), - pg: { - text : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', - string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' - }, - mysql: { - text : 'SELECT * FROM `user` WHERE ((`user`.`id` IS NOT NULL) AND (`user`.`name` IS NOT NULL))', - string: 'SELECT * FROM `user` WHERE ((`user`.`id` IS NOT NULL) AND (`user`.`name` IS NOT NULL))' - }, - sqlite: { - text : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', - string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' - }, - mssql: { - text : 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))', - string: 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))' - }, - oracle: { - text : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', - string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' - }, - params: [] -}); - -Harness.test({ - query: user.where([user.id.isNotNull(), user.name.isNotNull()]), - pg: { - text : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', - string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' - }, - mysql: { - text : 'SELECT * FROM `user` WHERE ((`user`.`id` IS NOT NULL) AND (`user`.`name` IS NOT NULL))', - string: 'SELECT * FROM `user` WHERE ((`user`.`id` IS NOT NULL) AND (`user`.`name` IS NOT NULL))' - }, - sqlite: { - text : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', - string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' - }, - mssql: { - text : 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))', - string: 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))' - }, - oracle: { - text : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', - string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' - }, - params: [] -}); - -Harness.test({ - query: user.where([]), - pg: { - text : 'SELECT * FROM "user" WHERE (1 = 1)', - string: 'SELECT * FROM "user" WHERE (1 = 1)' - }, - mysql: { - text : 'SELECT * FROM `user` WHERE (1 = 1)', - string: 'SELECT * FROM `user` WHERE (1 = 1)' - }, - sqlite: { - text : 'SELECT * FROM "user" WHERE (1 = 1)', - string: 'SELECT * FROM "user" WHERE (1 = 1)' - }, - mssql: { - text : 'SELECT * FROM [user] WHERE (1 = 1)', - string: 'SELECT * FROM [user] WHERE (1 = 1)' - }, - oracle: { - text : 'SELECT * FROM "user" WHERE (1 = 1)', - string: 'SELECT * FROM "user" WHERE (1 = 1)' - }, - params: [] -}); - -Harness.test({ - query: user.select().where(user.id.equals(1)).and(user.name.equals('a')), - pg: { - text : 'SELECT "user".* FROM "user" WHERE (("user"."id" = $1) AND ("user"."name" = $2))', - string: 'SELECT "user".* FROM "user" WHERE (("user"."id" = 1) AND ("user"."name" = \'a\'))' - }, - mysql: { - text : 'SELECT `user`.* FROM `user` WHERE ((`user`.`id` = ?) AND (`user`.`name` = ?))', - string: 'SELECT `user`.* FROM `user` WHERE ((`user`.`id` = 1) AND (`user`.`name` = \'a\'))' - }, - sqlite: { - text : 'SELECT "user".* FROM "user" WHERE (("user"."id" = $1) AND ("user"."name" = $2))', - string: 'SELECT "user".* FROM "user" WHERE (("user"."id" = 1) AND ("user"."name" = \'a\'))' - }, - mssql: { - text : 'SELECT [user].* FROM [user] WHERE (([user].[id] = @1) AND ([user].[name] = @2))', - string: 'SELECT [user].* FROM [user] WHERE (([user].[id] = 1) AND ([user].[name] = \'a\'))' - }, - oracle: { - text : 'SELECT "user".* FROM "user" WHERE (("user"."id" = :1) AND ("user"."name" = :2))', - string: 'SELECT "user".* FROM "user" WHERE (("user"."id" = 1) AND ("user"."name" = \'a\'))' - }, - params: [1,'a'] -}); - -Harness.test({ - query: user.select().and(user.id.equals(1)), - pg: { - text : 'SELECT "user".* FROM "user" WHERE ("user"."id" = $1)', - string: 'SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' - }, - mysql: { - text : 'SELECT `user`.* FROM `user` WHERE (`user`.`id` = ?)', - string: 'SELECT `user`.* FROM `user` WHERE (`user`.`id` = 1)' - }, - sqlite: { - text : 'SELECT "user".* FROM "user" WHERE ("user"."id" = $1)', - string: 'SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' - }, - mssql: { - text : 'SELECT [user].* FROM [user] WHERE ([user].[id] = @1)', - string: 'SELECT [user].* FROM [user] WHERE ([user].[id] = 1)' - }, - oracle: { - text : 'SELECT "user".* FROM "user" WHERE ("user"."id" = :1)', - string: 'SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' - }, - params: [1] -}); - -Harness.test({ - query: user.select().or(user.id.equals(1)), - pg: { - text : 'SELECT "user".* FROM "user" WHERE ("user"."id" = $1)', - string: 'SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' - }, - mysql: { - text : 'SELECT `user`.* FROM `user` WHERE (`user`.`id` = ?)', - string: 'SELECT `user`.* FROM `user` WHERE (`user`.`id` = 1)' - }, - sqlite: { - text : 'SELECT "user".* FROM "user" WHERE ("user"."id" = $1)', - string: 'SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' - }, - mssql: { - text : 'SELECT [user].* FROM [user] WHERE ([user].[id] = @1)', - string: 'SELECT [user].* FROM [user] WHERE ([user].[id] = 1)' - }, - oracle: { - text : 'SELECT "user".* FROM "user" WHERE ("user"."id" = :1)', - string: 'SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' - }, - params: [1] -}); - -Harness.test({ - query: user.select().and(user.id.equals(1)).or(user.name.equals('a')), - pg: { - text : 'SELECT "user".* FROM "user" WHERE (("user"."id" = $1) OR ("user"."name" = $2))', - string: 'SELECT "user".* FROM "user" WHERE (("user"."id" = 1) OR ("user"."name" = \'a\'))' - }, - mysql: { - text : 'SELECT `user`.* FROM `user` WHERE ((`user`.`id` = ?) OR (`user`.`name` = ?))', - string: 'SELECT `user`.* FROM `user` WHERE ((`user`.`id` = 1) OR (`user`.`name` = \'a\'))' - }, - sqlite: { - text : 'SELECT "user".* FROM "user" WHERE (("user"."id" = $1) OR ("user"."name" = $2))', - string: 'SELECT "user".* FROM "user" WHERE (("user"."id" = 1) OR ("user"."name" = \'a\'))' - }, - mssql: { - text : 'SELECT [user].* FROM [user] WHERE (([user].[id] = @1) OR ([user].[name] = @2))', - string: 'SELECT [user].* FROM [user] WHERE (([user].[id] = 1) OR ([user].[name] = \'a\'))' - }, - oracle: { - text : 'SELECT "user".* FROM "user" WHERE (("user"."id" = :1) OR ("user"."name" = :2))', - string: 'SELECT "user".* FROM "user" WHERE (("user"."id" = 1) OR ("user"."name" = \'a\'))' - }, - params: [1,'a'] -}); - diff --git a/test/dialects/where-clause-tests.ts b/test/dialects/where-clause-tests.ts new file mode 100644 index 00000000..10a34afa --- /dev/null +++ b/test/dialects/where-clause-tests.ts @@ -0,0 +1,208 @@ +import * as Harness from './support.js'; +const user = Harness.defineUserTable(); + +Harness.test({ + query: user.where(user.id.isNotNull(), user.name.isNotNull()), + pg: { + text: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', + string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' + }, + mysql: { + text: 'SELECT * FROM `user` WHERE ((`user`.`id` IS NOT NULL) AND (`user`.`name` IS NOT NULL))', + string: 'SELECT * FROM `user` WHERE ((`user`.`id` IS NOT NULL) AND (`user`.`name` IS NOT NULL))' + }, + sqlite: { + text: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', + string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' + }, + mssql: { + text: 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))', + string: 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))' + }, + oracle: { + text: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', + string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' + }, + params: [] +}); + +Harness.test({ + query: user.and(user.id.isNotNull(), user.name.isNotNull()), + pg: { + text: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', + string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' + }, + mysql: { + text: 'SELECT * FROM `user` WHERE ((`user`.`id` IS NOT NULL) AND (`user`.`name` IS NOT NULL))', + string: 'SELECT * FROM `user` WHERE ((`user`.`id` IS NOT NULL) AND (`user`.`name` IS NOT NULL))' + }, + sqlite: { + text: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', + string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' + }, + mssql: { + text: 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))', + string: 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))' + }, + oracle: { + text: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', + string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' + }, + params: [] +}); + +Harness.test({ + query: user.where([user.id.isNotNull(), user.name.isNotNull()]), + pg: { + text: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', + string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' + }, + mysql: { + text: 'SELECT * FROM `user` WHERE ((`user`.`id` IS NOT NULL) AND (`user`.`name` IS NOT NULL))', + string: 'SELECT * FROM `user` WHERE ((`user`.`id` IS NOT NULL) AND (`user`.`name` IS NOT NULL))' + }, + sqlite: { + text: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', + string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' + }, + mssql: { + text: 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))', + string: 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))' + }, + oracle: { + text: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', + string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' + }, + params: [] +}); + +Harness.test({ + query: user.where([]), + pg: { + text: 'SELECT * FROM "user" WHERE (1 = 1)', + string: 'SELECT * FROM "user" WHERE (1 = 1)' + }, + mysql: { + text: 'SELECT * FROM `user` WHERE (1 = 1)', + string: 'SELECT * FROM `user` WHERE (1 = 1)' + }, + sqlite: { + text: 'SELECT * FROM "user" WHERE (1 = 1)', + string: 'SELECT * FROM "user" WHERE (1 = 1)' + }, + mssql: { + text: 'SELECT * FROM [user] WHERE (1 = 1)', + string: 'SELECT * FROM [user] WHERE (1 = 1)' + }, + oracle: { + text: 'SELECT * FROM "user" WHERE (1 = 1)', + string: 'SELECT * FROM "user" WHERE (1 = 1)' + }, + params: [] +}); + +Harness.test({ + query: user + .select() + .where(user.id.equals(1)) + .and(user.name.equals('a')), + pg: { + text: 'SELECT "user".* FROM "user" WHERE (("user"."id" = $1) AND ("user"."name" = $2))', + string: 'SELECT "user".* FROM "user" WHERE (("user"."id" = 1) AND ("user"."name" = \'a\'))' + }, + mysql: { + text: 'SELECT `user`.* FROM `user` WHERE ((`user`.`id` = ?) AND (`user`.`name` = ?))', + string: "SELECT `user`.* FROM `user` WHERE ((`user`.`id` = 1) AND (`user`.`name` = 'a'))" + }, + sqlite: { + text: 'SELECT "user".* FROM "user" WHERE (("user"."id" = $1) AND ("user"."name" = $2))', + string: 'SELECT "user".* FROM "user" WHERE (("user"."id" = 1) AND ("user"."name" = \'a\'))' + }, + mssql: { + text: 'SELECT [user].* FROM [user] WHERE (([user].[id] = @1) AND ([user].[name] = @2))', + string: "SELECT [user].* FROM [user] WHERE (([user].[id] = 1) AND ([user].[name] = 'a'))" + }, + oracle: { + text: 'SELECT "user".* FROM "user" WHERE (("user"."id" = :1) AND ("user"."name" = :2))', + string: 'SELECT "user".* FROM "user" WHERE (("user"."id" = 1) AND ("user"."name" = \'a\'))' + }, + params: [1, 'a'] +}); + +Harness.test({ + query: user.select().and(user.id.equals(1)), + pg: { + text: 'SELECT "user".* FROM "user" WHERE ("user"."id" = $1)', + string: 'SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' + }, + mysql: { + text: 'SELECT `user`.* FROM `user` WHERE (`user`.`id` = ?)', + string: 'SELECT `user`.* FROM `user` WHERE (`user`.`id` = 1)' + }, + sqlite: { + text: 'SELECT "user".* FROM "user" WHERE ("user"."id" = $1)', + string: 'SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' + }, + mssql: { + text: 'SELECT [user].* FROM [user] WHERE ([user].[id] = @1)', + string: 'SELECT [user].* FROM [user] WHERE ([user].[id] = 1)' + }, + oracle: { + text: 'SELECT "user".* FROM "user" WHERE ("user"."id" = :1)', + string: 'SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' + }, + params: [1] +}); + +Harness.test({ + query: user.select().or(user.id.equals(1)), + pg: { + text: 'SELECT "user".* FROM "user" WHERE ("user"."id" = $1)', + string: 'SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' + }, + mysql: { + text: 'SELECT `user`.* FROM `user` WHERE (`user`.`id` = ?)', + string: 'SELECT `user`.* FROM `user` WHERE (`user`.`id` = 1)' + }, + sqlite: { + text: 'SELECT "user".* FROM "user" WHERE ("user"."id" = $1)', + string: 'SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' + }, + mssql: { + text: 'SELECT [user].* FROM [user] WHERE ([user].[id] = @1)', + string: 'SELECT [user].* FROM [user] WHERE ([user].[id] = 1)' + }, + oracle: { + text: 'SELECT "user".* FROM "user" WHERE ("user"."id" = :1)', + string: 'SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' + }, + params: [1] +}); + +Harness.test({ + query: user + .select() + .and(user.id.equals(1)) + .or(user.name.equals('a')), + pg: { + text: 'SELECT "user".* FROM "user" WHERE (("user"."id" = $1) OR ("user"."name" = $2))', + string: 'SELECT "user".* FROM "user" WHERE (("user"."id" = 1) OR ("user"."name" = \'a\'))' + }, + mysql: { + text: 'SELECT `user`.* FROM `user` WHERE ((`user`.`id` = ?) OR (`user`.`name` = ?))', + string: "SELECT `user`.* FROM `user` WHERE ((`user`.`id` = 1) OR (`user`.`name` = 'a'))" + }, + sqlite: { + text: 'SELECT "user".* FROM "user" WHERE (("user"."id" = $1) OR ("user"."name" = $2))', + string: 'SELECT "user".* FROM "user" WHERE (("user"."id" = 1) OR ("user"."name" = \'a\'))' + }, + mssql: { + text: 'SELECT [user].* FROM [user] WHERE (([user].[id] = @1) OR ([user].[name] = @2))', + string: "SELECT [user].* FROM [user] WHERE (([user].[id] = 1) OR ([user].[name] = 'a'))" + }, + oracle: { + text: 'SELECT "user".* FROM "user" WHERE (("user"."id" = :1) OR ("user"."name" = :2))', + string: 'SELECT "user".* FROM "user" WHERE (("user"."id" = 1) OR ("user"."name" = \'a\'))' + }, + params: [1, 'a'] +}); diff --git a/test/function-tests.js b/test/function-tests.js deleted file mode 100644 index 6c53072d..00000000 --- a/test/function-tests.js +++ /dev/null @@ -1,93 +0,0 @@ -'use strict'; -var assert = require('assert'); - -var sql = require(__dirname + '/../lib').setDialect('postgres'); - -var user = sql.define({ - name: 'user', - columns: [ - {name: 'id'}, - {name:'email'}, - {name: 'name'}, - {name: 'age', property: 'howOld'} - ] -}); - -suite('function', function() { - test('alias function call', function() { - var upper = sql.functions.UPPER; - var aliasedUpper = upper(user.email).as('upperAlias').toQuery(); - - assert.equal(aliasedUpper.text, 'UPPER("user"."email") AS "upperAlias"'); - }); - - test('function call on aliased column', function() { - var round = sql.functions.ROUND; - var aliasedRound = round(user.howOld, 2).toQuery(); - - assert.equal(aliasedRound.text, 'ROUND("user"."age", $1)'); - assert.equal(aliasedRound.values[0], 2); - }); - - test('creating function call works', function() { - var upper = sql.functionCallCreator('UPPER'); - var functionCall = upper('hello', 'world').toQuery(); - - assert.equal(functionCall.text, 'UPPER($1, $2)'); - assert.equal(functionCall.values[0], 'hello'); - assert.equal(functionCall.values[1], 'world'); - }); - - test('creating function call on columns works', function() { - var upper = sql.functionCallCreator('UPPER'); - var functionCall = upper(user.id, user.email).toQuery(); - - assert.equal(functionCall.text, 'UPPER("user"."id", "user"."email")'); - assert.equal(functionCall.values.length, 0); - }); - - test('function call inside select works', function() { - var upper = sql.functionCallCreator('UPPER'); - var query = sql.select(upper(user.id, user.email)).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery(); - - assert.equal(query.text, 'SELECT UPPER("user"."id", "user"."email") FROM "user" WHERE ("user"."email" = $1)'); - assert.equal(query.values[0], 'brian.m.carlson@gmail.com'); - }); - - test('standard aggregate functions with having clause', function() { - var count = sql.functions.COUNT; - var distinct = sql.functions.DISTINCT; - var distinctEmailCount = count(distinct(user.email)); - - var query = user.select(user.id, distinctEmailCount).group(user.id).having(distinctEmailCount.gt(100)).toQuery(); - - assert.equal(query.text, 'SELECT "user"."id", COUNT(DISTINCT("user"."email")) FROM "user" GROUP BY "user"."id" HAVING (COUNT(DISTINCT("user"."email")) > $1)'); - assert.equal(query.values[0], 100); - }); - - test('custom and standard functions behave the same', function() { - var standardUpper = sql.functions.UPPER; - var customUpper = sql.functionCallCreator('UPPER'); - - var standardQuery = user.select(standardUpper(user.name)).toQuery(); - var customQuery = user.select(customUpper(user.name)).toQuery(); - - var expectedQuery = 'SELECT UPPER("user"."name") FROM "user"'; - assert.equal(standardQuery.text, expectedQuery); - assert.equal(customQuery.text, expectedQuery); - }); - - test('combine function with operations', function() { - var f = sql.functions; - var query = user.select(f.AVG(f.DISTINCT(f.COUNT(user.id).plus(f.MAX(user.id))).minus(f.MIN(user.id))).multiply(100)).toQuery(); - - assert.equal(query.text, 'SELECT (AVG((DISTINCT((COUNT("user"."id") + MAX("user"."id"))) - MIN("user"."id"))) * $1) FROM "user"'); - assert.equal(query.values[0], 100); - }); - - test('use custom function', function() { - var query = user.select(sql.function('PHRASE_TO_TSQUERY')('simple', user.name)).toQuery(); - assert.equal(query.text, 'SELECT PHRASE_TO_TSQUERY($1, "user"."name") FROM "user"'); - assert.equal(query.values[0], 'simple'); - }); -}); diff --git a/test/function-tests.ts b/test/function-tests.ts new file mode 100644 index 00000000..2257cd30 --- /dev/null +++ b/test/function-tests.ts @@ -0,0 +1,101 @@ +import { strictEqual } from 'assert'; + +import { Sql } from '../dist/lib.js'; +const instance = new Sql('postgres'); + +const user = instance.define<{ id: string; email: string; name: string; howOld: number }>({ + name: 'user', + columns: [{ name: 'id' }, { name: 'email' }, { name: 'name' }, { name: 'age', property: 'howOld' }] +}); + +suite('function', function() { + test('alias function call', function() { + const upper = instance.functions.UPPER; + const aliasedUpper = upper(user.email) + .as('upperAlias') + .toQuery(); + + strictEqual(aliasedUpper.text, 'UPPER("user"."email") AS "upperAlias"'); + }); + + test('function call on aliased column', function() { + const round = instance.functions.ROUND; + const aliasedRound = round(user.howOld, 2).toQuery(); + + strictEqual(aliasedRound.text, 'ROUND("user"."age", $1)'); + strictEqual(aliasedRound.values[0], 2); + }); + + test('creating function call works', function() { + const upper = instance.function('UPPER'); + const functionCall = upper('hello', 'world').toQuery(); + + strictEqual(functionCall.text, 'UPPER($1, $2)'); + strictEqual(functionCall.values[0], 'hello'); + strictEqual(functionCall.values[1], 'world'); + }); + + test('creating function call on columns works', function() { + const upper = instance.function('UPPER'); + const functionCall = upper(user.id, user.email).toQuery(); + + strictEqual(functionCall.text, 'UPPER("user"."id", "user"."email")'); + strictEqual(functionCall.values.length, 0); + }); + + test('function call inside select works', function() { + const upper = instance.function('UPPER'); + const query = instance + .select(upper(user.id, user.email)) + .from(user) + .where(user.email.equals('brian.m.carlson@gmail.com')) + .toQuery(); + + strictEqual(query.text, 'SELECT UPPER("user"."id", "user"."email") FROM "user" WHERE ("user"."email" = $1)'); + strictEqual(query.values[0], 'brian.m.carlson@gmail.com'); + }); + + test('standard aggregate functions with having clause', function() { + const count = instance.functions.COUNT; + const distinct = instance.functions.DISTINCT; + const distinctEmailCount = count(distinct(user.email)); + + const query = user + .select(user.id, distinctEmailCount) + .group(user.id) + .having(distinctEmailCount.gt(100)) + .toQuery(); + + strictEqual( + query.text, + 'SELECT "user"."id", COUNT(DISTINCT("user"."email")) FROM "user" GROUP BY "user"."id" HAVING (COUNT(DISTINCT("user"."email")) > $1)' + ); + strictEqual(query.values[0], 100); + }); + + test('custom and standard functions behave the same', function() { + const standardUpper = instance.functions.UPPER; + const customUpper = instance.function('UPPER'); + + const standardQuery = user.select(standardUpper(user.name)).toQuery(); + const customQuery = user.select(customUpper(user.name)).toQuery(); + + const expectedQuery = 'SELECT UPPER("user"."name") FROM "user"'; + strictEqual(standardQuery.text, expectedQuery); + strictEqual(customQuery.text, expectedQuery); + }); + + test('combine function with operations', function() { + const f = instance.functions; + const query = user.select(f.AVG(f.DISTINCT(f.COUNT(user.id).plus(f.MAX(user.id))).minus(f.MIN(user.id))).multiply(100)).toQuery(); + + strictEqual(query.text, 'SELECT (AVG((DISTINCT((COUNT("user"."id") + MAX("user"."id"))) - MIN("user"."id"))) * $1) FROM "user"'); + strictEqual(query.values[0], 100); + }); + + test('use custom function', function() { + const query = user.select(instance.function('PHRASE_TO_TSQUERY')('simple', user.name)).toQuery(); + strictEqual(query.text, 'SELECT PHRASE_TO_TSQUERY($1, "user"."name") FROM "user"'); + strictEqual(query.values[0], 'simple'); + }); +}); diff --git a/test/index-tests.js b/test/index-tests.js deleted file mode 100644 index f25839e1..00000000 --- a/test/index-tests.js +++ /dev/null @@ -1,214 +0,0 @@ -'use strict'; -var assert = require('assert'); - -var sql = require('../lib'); - -var user = sql.define({ - name: 'user', - columns: ['id', 'email'] -}); - -suite('index', function() { - test('unknown dialect throws exception', function() { - assert.throws(function() { - sql.setDialect('asdf'); - }); - }); - - test('stores the default dialect\'s name if none has been passed', function() { - assert.equal(sql.create().dialectName, 'postgres'); - }); - - test('stores the sqlite dialect', function() { - assert.equal(sql.create('sqlite').dialectName, 'sqlite'); - }); - - test('stores the mysql dialect', function() { - assert.equal(sql.create('mysql').dialectName, 'mysql'); - }); - - test('stores the mssql dialect', function() { - assert.equal(sql.create('mssql').dialectName, 'mssql'); - }); - - test('stores the oracle dialect', function() { - assert.equal(sql.create('oracle').dialectName, 'oracle'); - }); - - - test('can create a query using the default dialect', function() { - var query = sql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery(); - assert.equal(query.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); - assert.equal(query.values[0], 'brian.m.carlson@gmail.com'); - }); - - test('setting dialect to postgres works', function() { - sql.setDialect('postgres'); - var query = sql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery(); - assert.equal(query.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); - assert.equal(query.values[0], 'brian.m.carlson@gmail.com'); - }); - - test('sql.create creates an instance with a new dialect', function() { - var mysql = sql.create('mysql'); - var query = mysql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery(); - assert.equal(query.text, 'SELECT `user`.`id` FROM `user` WHERE (`user`.`email` = ?)'); - assert.equal(query.values[0], 'brian.m.carlson@gmail.com'); - }); - - test('sql.define for parallel dialects work independently', function() { - var mssql = sql.create('mssql'); - var mysql = sql.create('mysql'); - var postgres = sql.create('postgres'); - var sqlite = sql.create('sqlite'); - var oracle = sql.create('oracle'); - - var mssqlTable = mssql.define({name: 'table', columns: ['column']}); - var mysqlTable = mysql.define({name: 'table', columns: ['column']}); - var postgresTable = postgres.define({name: 'table', columns: ['column']}); - var sqliteTable = sqlite.define({name: 'table', columns: ['column']}); - var oracleTable = oracle.define({name: 'table', columns: ['column']}); - - assert.equal(mysqlTable.sql, mysql); - assert.equal(postgresTable.sql, postgres); - assert.equal(sqliteTable.sql, sqlite); - assert.equal(mssqlTable.sql, mssql); - assert.equal(oracleTable.sql, oracle); - }); - - test('using Sql as a class', function() { - var Sql = sql.Sql; - var mssql = new Sql('mssql'); - var mysql = new Sql('mysql'); - var postgres = new Sql('postgres'); - var sqlite = new Sql('sqlite'); - var oracle = new Sql('oracle'); - - assert.equal(mysql.dialect, require(__dirname + '/../lib/dialect/mysql')); - assert.equal(postgres.dialect, require(__dirname + '/../lib/dialect/postgres')); - assert.equal(sqlite.dialect, require(__dirname + '/../lib/dialect/sqlite')); - assert.equal(mssql.dialect, require(__dirname + '/../lib/dialect/mssql')); - assert.equal(oracle.dialect, require(__dirname + '/../lib/dialect/oracle')); - }); - - test('override dialect for toQuery using dialect name', function() { - var Sql = sql.Sql; - var mssql = new Sql('mssql'); - var mysql = new Sql('mysql'); - var postgres = new Sql('postgres'); - var sqlite = new Sql('sqlite'); - var oracle = new Sql('oracle'); - - var sqliteQuery = mysql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('sqlite'); - var postgresQuery = sqlite.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('postgres'); - var mysqlQuery = postgres.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('mysql'); - var mssqlQuery = mysql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('mssql'); - var oracleQuery = oracle.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('oracle'); - - var values = ['brian.m.carlson@gmail.com']; - assert.equal(sqliteQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); - assert.deepEqual(sqliteQuery.values, values); - - assert.equal(postgresQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); - assert.deepEqual(postgresQuery.values, values); - - assert.equal(mysqlQuery.text, 'SELECT `user`.`id` FROM `user` WHERE (`user`.`email` = ?)'); - assert.deepEqual(mysqlQuery.values, values); - - assert.equal(mssqlQuery.text, 'SELECT [user].[id] FROM [user] WHERE ([user].[email] = @1)'); - assert.deepEqual(mssqlQuery.values, values); - - assert.equal(oracleQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = :1)'); - assert.deepEqual(oracleQuery.values, values); - }); - - test('override dialect for toQuery using invalid dialect name', function() { - var query = sql.select(user.id).from(user); - assert.throws(function() { - query.toQuery('invalid'); - }); - }); - - test('using named queries with toNamedQuery', function() { - var query = sql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toNamedQuery('users'); - assert.equal(query.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); - assert.equal(query.values[0], 'brian.m.carlson@gmail.com'); - assert.equal(query.name, 'users'); - }); - - test('provide an empty query name for toNamedQuery', function() { - var query = sql.select(user.id).from(user); - assert.throws(function() { - query.toNamedQuery(''); - }); - }); - - test('provide an undefined query name for toNamedQuery', function() { - var query = sql.select(user.id).from(user); - assert.throws(function() { - query.toNamedQuery(); - }); - }); - - test('override dialect for toNamedQuery using dialect name', function() { - var Sql = sql.Sql; - var mysql = new Sql('mysql'); - var postgres = new Sql('postgres'); - var sqlite = new Sql('sqlite'); - var mssql = new Sql('mssql'); - var oracle = new Sql('oracle'); - - var sqliteQuery = mysql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toNamedQuery('user.select_brian','sqlite'); - var postgresQuery = sqlite.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toNamedQuery('user.select_brian','postgres'); - var mysqlQuery = postgres.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toNamedQuery('user.select_brian','mysql'); - var oracleQuery = mssql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toNamedQuery('user.select_brian','oracle'); - var mssqlQuery = oracle.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toNamedQuery('user.select_brian','mssql'); - - - var values = ['brian.m.carlson@gmail.com']; - assert.equal(sqliteQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); - assert.deepEqual(sqliteQuery.values, values); - assert.equal('user.select_brian', sqliteQuery.name); - - assert.equal(postgresQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); - assert.deepEqual(postgresQuery.values, values); - assert.equal('user.select_brian', postgresQuery.name); - - assert.equal(mysqlQuery.text, 'SELECT `user`.`id` FROM `user` WHERE (`user`.`email` = ?)'); - assert.deepEqual(mysqlQuery.values, values); - assert.equal('user.select_brian', mysqlQuery.name); - - assert.equal(mssqlQuery.text, 'SELECT [user].[id] FROM [user] WHERE ([user].[email] = @1)'); - assert.deepEqual(mssqlQuery.values, values); - assert.equal('user.select_brian', mssqlQuery.name); - - assert.equal(oracleQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = :1)'); - assert.deepEqual(oracleQuery.values, values); - assert.equal('user.select_brian', oracleQuery.name); - - }); - - test('override dialect for toNamedQuery using invalid dialect name', function() { - var query = sql.select(user.id).from(user); - assert.throws(function() { - query.toNamedQuery('name', 'invalid'); - }); - }); - - test('mssql default parameter place holder is @index', function() { - var Sql = sql.Sql; - var mssql = new Sql('mssql'); - var query = mssql.select(user.id).from(user).where(user.email.equals('x@y.com')).toQuery(); - assert.equal(query.text, 'SELECT [user].[id] FROM [user] WHERE ([user].[email] = @1)'); - assert.equal(query.values[0], 'x@y.com'); - }); - - test('mssql override default parameter placeholder with ?', function() { - var Sql = sql.Sql; - var mssql = new Sql('mssql',{questionMarkParameterPlaceholder:true}); - var query = mssql.select(user.id).from(user).where(user.email.equals('x@y.com')).toQuery(); - assert.equal(query.text, 'SELECT [user].[id] FROM [user] WHERE ([user].[email] = ?)'); - assert.equal(query.values[0], 'x@y.com'); - }); - -}); diff --git a/test/index-tests.ts b/test/index-tests.ts new file mode 100644 index 00000000..5a0f4f86 --- /dev/null +++ b/test/index-tests.ts @@ -0,0 +1,273 @@ +import { throws, strictEqual, deepStrictEqual } from 'assert'; + +import { Sql, Mysql, Mssql, Oracle, Postgres, Sqlite } from '../dist/lib.js'; + +const instance = new Sql(); +const user = instance.define<{ id: string; email: string }>({ + name: 'user', + columns: ['id', 'email'] +}); + +suite('index', function() { + test('unknown dialect throws exception', function() { + throws(function() { + // for testing purposes ignore the compile-time error + // @ts-ignore + instance.setDialect('asdf'); + }); + }); + + test("stores the default dialect's name if none has been passed", function() { + strictEqual(new Sql().dialectName, 'postgres'); + }); + + test('stores the sqlite dialect', function() { + strictEqual(new Sql('sqlite').dialectName, 'sqlite'); + }); + + test('stores the mysql dialect', function() { + strictEqual(new Sql('mysql').dialectName, 'mysql'); + }); + + test('stores the mssql dialect', function() { + strictEqual(new Sql('mssql').dialectName, 'mssql'); + }); + + test('stores the oracle dialect', function() { + strictEqual(new Sql('oracle').dialectName, 'oracle'); + }); + + test('can create a query using the default dialect', function() { + const query = instance + .select(user.id) + .from(user) + .where(user.email.equals('brian.m.carlson@gmail.com')) + .toQuery(); + strictEqual(query.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); + strictEqual(query.values[0], 'brian.m.carlson@gmail.com'); + }); + + test('setting dialect to postgres works', function() { + instance.setDialect('postgres'); + const query = instance + .select(user.id) + .from(user) + .where(user.email.equals('brian.m.carlson@gmail.com')) + .toQuery(); + strictEqual(query.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); + strictEqual(query.values[0], 'brian.m.carlson@gmail.com'); + }); + + test('sql.create creates an instance with a new dialect', function() { + const mysql = new Sql('mysql'); + const query = mysql + .select(user.id) + .from(user) + .where(user.email.equals('brian.m.carlson@gmail.com')) + .toQuery(); + strictEqual(query.text, 'SELECT `user`.`id` FROM `user` WHERE (`user`.`email` = ?)'); + strictEqual(query.values[0], 'brian.m.carlson@gmail.com'); + }); + + test('sql.define for parallel dialects work independently', function() { + const mssql = new Sql('mssql'); + const mysql = new Sql('mysql'); + const postgres = new Sql('postgres'); + const sqlite = new Sql('sqlite'); + const oracle = new Sql('oracle'); + + const mssqlTable = mssql.define({ name: 'table', columns: ['column'] }); + const mysqlTable = mysql.define({ name: 'table', columns: ['column'] }); + const postgresTable = postgres.define({ name: 'table', columns: ['column'] }); + const sqliteTable = sqlite.define({ name: 'table', columns: ['column'] }); + const oracleTable = oracle.define({ name: 'table', columns: ['column'] }); + + strictEqual(mysqlTable.sql, mysql); + strictEqual(postgresTable.sql, postgres); + strictEqual(sqliteTable.sql, sqlite); + strictEqual(mssqlTable.sql, mssql); + strictEqual(oracleTable.sql, oracle); + }); + + test('using Sql as a class', function() { + const mssql = new Sql('mssql'); + const mysql = new Sql('mysql'); + const postgres = new Sql('postgres'); + const sqlite = new Sql('sqlite'); + const oracle = new Sql('oracle'); + + strictEqual(mysql.dialect, Mysql); + strictEqual(postgres.dialect, Postgres); + strictEqual(sqlite.dialect, Sqlite); + strictEqual(mssql.dialect, Mssql); + strictEqual(oracle.dialect, Oracle); + }); + + test('override dialect for toQuery using dialect name', function() { + const mssql = new Sql('mssql'); + const mysql = new Sql('mysql'); + const postgres = new Sql('postgres'); + const sqlite = new Sql('sqlite'); + const oracle = new Sql('oracle'); + + const sqliteQuery = mysql + .select(user.id) + .from(user) + .where(user.email.equals('brian.m.carlson@gmail.com')) + .toQuery('sqlite'); + const postgresQuery = sqlite + .select(user.id) + .from(user) + .where(user.email.equals('brian.m.carlson@gmail.com')) + .toQuery('postgres'); + const mysqlQuery = postgres + .select(user.id) + .from(user) + .where(user.email.equals('brian.m.carlson@gmail.com')) + .toQuery('mysql'); + const mssqlQuery = mssql + .select(user.id) + .from(user) + .where(user.email.equals('brian.m.carlson@gmail.com')) + .toQuery('mssql'); + const oracleQuery = oracle + .select(user.id) + .from(user) + .where(user.email.equals('brian.m.carlson@gmail.com')) + .toQuery('oracle'); + + const values = ['brian.m.carlson@gmail.com']; + strictEqual(sqliteQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); + deepStrictEqual(sqliteQuery.values, values); + + strictEqual(postgresQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); + deepStrictEqual(postgresQuery.values, values); + + strictEqual(mysqlQuery.text, 'SELECT `user`.`id` FROM `user` WHERE (`user`.`email` = ?)'); + deepStrictEqual(mysqlQuery.values, values); + + strictEqual(mssqlQuery.text, 'SELECT [user].[id] FROM [user] WHERE ([user].[email] = @1)'); + deepStrictEqual(mssqlQuery.values, values); + + strictEqual(oracleQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = :1)'); + deepStrictEqual(oracleQuery.values, values); + }); + + test('override dialect for toQuery using invalid dialect name', function() { + const query = instance.select(user.id).from(user); + throws(function() { + query.toQuery('invalid'); + }); + }); + + test('using named queries with toNamedQuery', function() { + const query = instance + .select(user.id) + .from(user) + .where(user.email.equals('brian.m.carlson@gmail.com')) + .toNamedQuery('users'); + strictEqual(query.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); + strictEqual(query.values[0], 'brian.m.carlson@gmail.com'); + strictEqual(query.name, 'users'); + }); + + test('provide an empty query name for toNamedQuery', function() { + const query = instance.select(user.id).from(user); + throws(function() { + query.toNamedQuery(''); + }); + }); + + test('provide an undefined query name for toNamedQuery', function() { + const query = instance.select(user.id).from(user); + throws(function() { + // for testing purposes ignore the compile-time error + // @ts-ignore + query.toNamedQuery(); + }); + }); + + test('override dialect for toNamedQuery using dialect name', function() { + const mysql = new Sql('mysql'); + const postgres = new Sql('postgres'); + const sqlite = new Sql('sqlite'); + const mssql = new Sql('mssql'); + const oracle = new Sql('oracle'); + + const sqliteQuery = mysql + .select(user.id) + .from(user) + .where(user.email.equals('brian.m.carlson@gmail.com')) + .toNamedQuery('user.select_brian', 'sqlite'); + const postgresQuery = sqlite + .select(user.id) + .from(user) + .where(user.email.equals('brian.m.carlson@gmail.com')) + .toNamedQuery('user.select_brian', 'postgres'); + const mysqlQuery = postgres + .select(user.id) + .from(user) + .where(user.email.equals('brian.m.carlson@gmail.com')) + .toNamedQuery('user.select_brian', 'mysql'); + const oracleQuery = mssql + .select(user.id) + .from(user) + .where(user.email.equals('brian.m.carlson@gmail.com')) + .toNamedQuery('user.select_brian', 'oracle'); + const mssqlQuery = oracle + .select(user.id) + .from(user) + .where(user.email.equals('brian.m.carlson@gmail.com')) + .toNamedQuery('user.select_brian', 'mssql'); + + const values = ['brian.m.carlson@gmail.com']; + strictEqual(sqliteQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); + deepStrictEqual(sqliteQuery.values, values); + strictEqual('user.select_brian', sqliteQuery.name); + + strictEqual(postgresQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); + deepStrictEqual(postgresQuery.values, values); + strictEqual('user.select_brian', postgresQuery.name); + + strictEqual(mysqlQuery.text, 'SELECT `user`.`id` FROM `user` WHERE (`user`.`email` = ?)'); + deepStrictEqual(mysqlQuery.values, values); + strictEqual('user.select_brian', mysqlQuery.name); + + strictEqual(mssqlQuery.text, 'SELECT [user].[id] FROM [user] WHERE ([user].[email] = @1)'); + deepStrictEqual(mssqlQuery.values, values); + strictEqual('user.select_brian', mssqlQuery.name); + + strictEqual(oracleQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = :1)'); + deepStrictEqual(oracleQuery.values, values); + strictEqual('user.select_brian', oracleQuery.name); + }); + + test('override dialect for toNamedQuery using invalid dialect name', function() { + const query = instance.select(user.id).from(user); + throws(function() { + query.toNamedQuery('name', 'invalid'); + }); + }); + + test('mssql default parameter place holder is @index', function() { + const mssql = new Sql('mssql'); + const query = mssql + .select(user.id) + .from(user) + .where(user.email.equals('x@y.com')) + .toQuery(); + strictEqual(query.text, 'SELECT [user].[id] FROM [user] WHERE ([user].[email] = @1)'); + strictEqual(query.values[0], 'x@y.com'); + }); + + test('mssql override default parameter placeholder with ?', function() { + const mssql = new Sql('mssql', { questionMarkParameterPlaceholder: true }); + const query = mssql + .select(user.id) + .from(user) + .where(user.email.equals('x@y.com')) + .toQuery(); + strictEqual(query.text, 'SELECT [user].[id] FROM [user] WHERE ([user].[email] = ?)'); + strictEqual(query.values[0], 'x@y.com'); + }); +}); diff --git a/test/index.js b/test/index.js deleted file mode 100644 index eb7a60b0..00000000 --- a/test/index.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; - -var fs = require('fs'); -var path = require('path'); - -var testDir = __dirname; - -var directories = [ - testDir + '/dialects' -]; - -directories.forEach(function (d) { - var files = fs.readdirSync(d); - /*jshint boss: true */ - for(var i = 0, file; file = files[i]; i++) { - var filePath = path.join(d, file); - if (path.extname(file) === '.js') { - require(filePath); - } - } -}); diff --git a/test/mocha.opts b/test/mocha.opts deleted file mode 100644 index 850a6c2f..00000000 --- a/test/mocha.opts +++ /dev/null @@ -1,2 +0,0 @@ ---reporter dot ---ui tdd diff --git a/test/operator-tests.ts b/test/operator-tests.ts new file mode 100644 index 00000000..6374f930 --- /dev/null +++ b/test/operator-tests.ts @@ -0,0 +1,87 @@ +import { strictEqual } from 'assert'; + +import { Sql } from '../dist/lib.js'; +const instance = new Sql('postgres'); + +const user = instance.define<{ id: string; email: string; name: string; howOld: number }>({ + name: 'user', + columns: [{ name: 'id' }, { name: 'email' }, { name: 'name' }, { name: 'age', property: 'howOld' }] +}); + +suite('operator', function() { + // PREFIX UNARY + test('creating a prefix unary operator works', function() { + const not = instance.prefixUnaryOperator('NOT'); + const operator = not(user.id).toQuery(); + + strictEqual(operator.text, '(NOT "user"."id")'); + }); + + test('creating a prefix unary operator works with a parameter', function() { + const not = instance.prefixUnaryOperator('NOT'); + const operator = not('hello').toQuery(); + + strictEqual(operator.text, '(NOT $1)'); + strictEqual(operator.values[0], 'hello'); + }); + + test('creating a prefix unary operator works via the mixin', function() { + const operator = user.id.prefixUnaryOperator('NOT').toQuery(); + + strictEqual(operator.text, '(NOT "user"."id")'); + }); + + // POSTFIX UNARY + test('creating a postfix unary operator works', function() { + const isNull = instance.postfixUnaryOperator('IS NULL'); + const operator = isNull(user.id).toQuery(); + + strictEqual(operator.text, '("user"."id" IS NULL)'); + }); + + test('creating a postfix unary operator works with a parameter', function() { + const isNull = instance.postfixUnaryOperator('IS NULL'); + const operator = isNull('hello').toQuery(); + + strictEqual(operator.text, '($1 IS NULL)'); + strictEqual(operator.values[0], 'hello'); + }); + + test('creating a postfix unary operator works via the mixin', function() { + const operator = user.id.postfixUnaryOperator('IS NOT NULL').toQuery(); + + strictEqual(operator.text, '("user"."id" IS NOT NULL)'); + }); + + // BINARY + test('creating a binary operator works', function() { + const lt = instance.binaryOperator('<'); + const operator = lt(user.id, 3).toQuery(); + + strictEqual(operator.text, '("user"."id" < $1)'); + strictEqual(operator.values[0], 3); + }); + + test('creating a binary operator works via the mixin', function() { + const operator = user.id.binaryOperator('<->', 3).toQuery(); + + strictEqual(operator.text, '("user"."id" <-> $1)'); + strictEqual(operator.values[0], 3); + }); + + // TERNARY + test('creating a ternary operator works', function() { + const between = instance.ternaryOperator('BETWEEN', 'AND'); + const operator = between(user.id, 3, user.id).toQuery(); + + strictEqual(operator.text, '("user"."id" BETWEEN $1 AND "user"."id")'); + strictEqual(operator.values[0], 3); + }); + + test('creating a ternary operator works via the mixin', function() { + const operator = user.id.ternaryOperator('BETWEEN', 3, 'AND', user.id).toQuery(); + + strictEqual(operator.text, '("user"."id" BETWEEN $1 AND "user"."id")'); + strictEqual(operator.values[0], 3); + }); +}); diff --git a/test/select-tests.js b/test/select-tests.js deleted file mode 100644 index a0befc4c..00000000 --- a/test/select-tests.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -var assert = require('assert'); -var Select = require(__dirname + '/../lib/node/select'); - -var select = new Select({sql: require('../lib/index')}); - -test('has SELECT type', function() { - assert.equal(select.type, 'SELECT'); -}); - - -test('can go toQuery', function() { - assert.equal(select.toQuery().text, 'SELECT '); -}); diff --git a/test/select-tests.ts b/test/select-tests.ts new file mode 100644 index 00000000..c82755a2 --- /dev/null +++ b/test/select-tests.ts @@ -0,0 +1,8 @@ +import { strictEqual } from 'assert'; +import { SelectNode } from '../dist/lib.js'; + +const select = new SelectNode(); + +test('has SELECT type', function() { + strictEqual(select.type, 'SELECT'); +}); diff --git a/test/table-tests.js b/test/table-tests.js deleted file mode 100644 index 73d43367..00000000 --- a/test/table-tests.js +++ /dev/null @@ -1,273 +0,0 @@ -'use strict'; -var assert = require('assert'); - -var Table = require(__dirname + '/../lib/table'); -var Column = require(__dirname + '/../lib/column'); -var Sql = require('../'); - -suite('table', function() { - var table = new Table({ - name: 'bang' - }); - - test('has name', function() { - assert.equal(table.getName(), 'bang'); - }); - - test('has no columns', function() { - assert.equal(table.columns.length, 0); - }); - - test('can add column', function() { - var col = new Column({ - table: table, - name: 'boom' - }); - - assert.equal(col.name, 'boom'); - assert.equal(col.table.getName(), 'bang'); - - table.addColumn(col); - assert.equal(table.columns.length, 1); - assert.equal(table.boom, col); - }); - - test('creates query node', function() { - var sel = table.select(table.boom); - assert.equal(sel.type, 'QUERY'); - }); - - test('creates *-query if no args is provided to select()', function() { - var sel = table.select(); - assert.ok(sel.nodes[0].nodes[0].star); - }); - - test('can be defined', function() { - var user = Table.define({ - name: 'user', - columns: ['id', 'name'] - }); - assert.equal(user.getName(), 'user'); - assert.equal(user.columns.length, 2); - assert.equal(user.columns[0].name, 'id'); - assert.equal(user.columns[1].name, 'name'); - assert.equal(user.columns[0].name, user.id.name); - assert.equal(user.id.table, user); - assert.equal(user.name.table, user); - }); -}); - -test('table with user-defined column property names', function () { - var table = Table.define({ - name: 'blah', - columns: [{ - name: 'id', - property: 'theId' - }, { - name: 'email', - property: 'uniqueEmail' - }] - }); - var cols = table.columns; - assert.equal(cols.length, 2); - assert.equal(cols[0].name, 'id'); - assert(cols[0] === table.theId, 'Expected table.theId to be the first column'); - assert(table.id === undefined, 'Expected table.id to not exist'); - assert.equal(cols[1].name, 'email'); - assert(cols[1] === table.uniqueEmail, 'Expected table.uniqueEmail to be the second column'); - assert(table.email === undefined, 'Expected table.email to not exist'); -}); - -test('table with fancier column definitions', function() { - var table = Table.define({ - name: 'blah', - columns: [{ - name: 'id', - type: 'serial', - notNull: true, - primaryKey: true - }, { - name: 'email', - type: 'text', - notNull: true, - unique: true, - anythingYouWant: 'awesome' - }] - }); - var cols = table.columns; - assert.equal(cols.length, 2); - var id = cols[0]; - assert.equal(id.name, 'id'); - assert.equal(id.type, 'serial'); - assert.equal(id.notNull, true); - assert.equal(id.primaryKey, true); - var email = cols[1]; - assert.equal(email.name, 'email'); - assert.equal(email.type, 'text'); - assert.equal(email.notNull, true); - assert.equal(email.unique, true); - assert.equal(email.anythingYouWant, 'awesome'); -}); - -test('table with object structured column definitions', function() { - var table = Table.define({ - name: 'blah', - columns: { - id: { - type: 'serial', - notNull: true, - primaryKey: true - }, - email: { - type: 'text', - notNull: true, - unique: true, - anythingYouWant: 'awesome' - } - } - }); - var cols = table.columns; - assert.equal(cols.length, 2); - var id = cols[0]; - assert.equal(id.name, 'id'); - assert.equal(id.type, 'serial'); - assert.equal(id.notNull, true); - assert.equal(id.primaryKey, true); - var email = cols[1]; - assert.equal(email.name, 'email'); - assert.equal(email.type, 'text'); - assert.equal(email.notNull, true); - assert.equal(email.unique, true); - assert.equal(email.anythingYouWant, 'awesome'); -}); - -test('table with dynamic column definition', function() { - var table = Table.define({ name: 'foo', columns: [] }); - assert.equal(table.columns.length, 0); - - table.addColumn('foo'); - assert.equal(table.columns.length, 1); - - assert.throws(function() { - table.addColumn('foo'); - }); - - assert.doesNotThrow(function() { - table.addColumn('foo', { noisy: false }); - }); - - assert.equal(table.columns.length, 1); -}); - -test('hasColumn', function() { - var table = Table.define({ name: 'foo', columns: [] }); - - assert.equal(table.hasColumn('baz'), false); - table.addColumn('baz'); - assert.equal(table.hasColumn('baz'), true); -}); - -test('hasColumn with user-defined column property', function() { - var table = Table.define({ - name: 'blah', - columns: [{ - name: 'id', - property: 'theId' - }, {name: 'foo'}] - }); - - assert.equal(table.hasColumn('id'), true); - assert.equal(table.hasColumn('theId'), true); -}); - -test('the column "from" does not overwrite the from method', function() { - var table = Table.define({ name: 'foo', columns: [] }); - table.addColumn('from'); - assert.equal(typeof table.from, 'function'); -}); - -test('getColumn returns the from column', function() { - var table = Table.define({ name: 'foo', columns: [] }); - table.addColumn('from'); - assert(table.getColumn('from') instanceof Column); - assert(table.get('from') instanceof Column); -}); - -test('set and get schema', function () { - var table = Table.define({ name: 'foo', schema: 'bar', columns: [] }); - assert.equal(table.getSchema(), 'bar'); - table.setSchema('barbarz'); - assert.equal(table.getSchema(), 'barbarz'); -}); - -suite('table.clone', function() { - test('check if it is a copy, not just a reference', function() { - var table = Table.define({ name: 'foo', columns: [] }); - var copy = table.clone(); - assert.notEqual(table, copy); - }); - - test('copy columns', function() { - var table = Table.define({ name: 'foo', columns: ['bar'] }); - var copy = table.clone(); - assert(copy.get('bar') instanceof Column); - }); - - test('overwrite config while copying', function() { - var table = Table.define({ - name: 'foo', - schema: 'foobar', - columns: ['bar'], - snakeToCamel: true, - columnWhiteList: true - }); - - var copy = table.clone({ - schema: 'test', - snakeToCamel: false, - columnWhiteList: false - }); - - assert.equal(copy.getSchema(), 'test'); - assert.equal(copy.snakeToCamel, false); - assert.equal(copy.columnWhiteList, false); - }); -}); - -test('dialects', function () { - var sql = new Sql.Sql('mysql'); - var foo = sql.define({ name: 'foo', columns: [ 'id' ] }), - bar = sql.define({ name: 'bar', columns: [ 'id' ] }); - - var actual = foo.join(bar).on(bar.id.equals(1)).toString(); - assert.equal(actual, '`foo` INNER JOIN `bar` ON (`bar`.`id` = 1)'); - - sql = new Sql.Sql('postgres'); - foo = sql.define({ name: 'foo', columns: [ 'id' ] }); - bar = sql.define({ name: 'bar', columns: [ 'id' ] }); - actual = foo.join(bar).on(bar.id.equals(1)).toString(); - assert.equal(actual, '"foo" INNER JOIN "bar" ON ("bar"."id" = 1)'); -}); - -test('limit', function () { - var user = Table.define({name: 'user', columns: ['id', 'name']}); - var query = user.limit(3); - assert.equal(query.nodes.length, 1); - assert.equal(query.nodes[0].type, 'LIMIT'); - assert.equal(query.nodes[0].count, 3); -}); - -test('offset', function () { - var user = Table.define({name: 'user', columns: ['id', 'name']}); - var query = user.offset(20); - assert.equal(query.nodes.length, 1); - assert.equal(query.nodes[0].type, 'OFFSET'); - assert.equal(query.nodes[0].count, 20); -}); - -test('order', function () { - var user = Table.define({name: 'user', columns: ['id', 'name']}); - var query = user.order(user.name); - assert.equal(query.nodes.length, 1); - assert.equal(query.nodes[0].type, 'ORDER BY'); -}); diff --git a/test/table-tests.ts b/test/table-tests.ts new file mode 100644 index 00000000..a7c5af52 --- /dev/null +++ b/test/table-tests.ts @@ -0,0 +1,285 @@ +import assert, { strictEqual, ok, throws, doesNotThrow, notStrictEqual } from 'assert'; + +import { Table, Column, Sql, ColumnNode, ModifierNode, ParameterNode } from '../dist/lib.js'; + +suite('table', function() { + const table = new Table({ + name: 'bang' + } as any); + + test('has name', function() { + strictEqual(table.getName(), 'bang'); + }); + + test('has no columns', function() { + strictEqual(table.columns.length, 0); + }); + + test('can add column', function() { + const col = new Column({ + table, + name: 'boom' + }); + + strictEqual(col.name, 'boom'); + strictEqual(col.table!.getName(), 'bang'); + + table.addColumn(col); + strictEqual(table.columns.length, 1); + // @ts-ignore column added after table created + strictEqual(table.boom, col); + }); + + test('creates query node', function() { + // @ts-ignore column added after table created + const sel = table.select(table.boom); + strictEqual(sel.type, 'QUERY'); + }); + + test('creates *-query if no args is provided to select()', function() { + const sel = table.select(); + ok((sel.nodes[0].nodes[0] as ColumnNode).star); + }); + + test('can be defined', function() { + const user = Table.define<{ id: number; name: string }>({ + name: 'user', + columns: ['id', 'name'] + }); + strictEqual(user.getName(), 'user'); + strictEqual(user.columns.length, 2); + strictEqual(user.columns[0].name, 'id'); + strictEqual(user.columns[1].name, 'name'); + strictEqual(user.columns[0].name, user.id.name); + strictEqual(user.id.table, user); + strictEqual(user.name.table, user); + }); +}); + +test('table with user-defined column property names', function() { + const table = Table.define<{ theId: number; uniqueEmail: string }>({ + name: 'blah', + columns: [ + { + name: 'id', + property: 'theId' + }, + { + name: 'email', + property: 'uniqueEmail' + } + ] + }); + const cols = table.columns; + strictEqual(cols.length, 2); + strictEqual(cols[0].name, 'id'); + assert(cols[0] === table.theId, 'Expected table.theId to be the first column'); + // @ts-ignore id doesn't exist + assert(table.id === undefined, 'Expected table.id to not exist'); + strictEqual(cols[1].name, 'email'); + assert(cols[1] === table.uniqueEmail, 'Expected table.uniqueEmail to be the second column'); + // @ts-ignore email doesn't exist + assert(table.email === undefined, 'Expected table.email to not exist'); +}); + +test('table with fancier column definitions', function() { + const table = Table.define({ + name: 'blah', + columns: [ + { + name: 'id', + dataType: 'serial', + notNull: true, + primaryKey: true + }, + { + name: 'email', + dataType: 'text', + notNull: true, + unique: true + } + ] + }); + const cols = table.columns; + strictEqual(cols.length, 2); + const id = cols[0]; + strictEqual(id.name, 'id'); + strictEqual(id.dataType, 'serial'); + strictEqual(id.notNull, true); + strictEqual(id.primaryKey, true); + const email = cols[1]; + strictEqual(email.name, 'email'); + strictEqual(email.dataType, 'text'); + strictEqual(email.notNull, true); + strictEqual(email.unique, true); +}); + +test('table with object structured column definitions', function() { + const table = Table.define({ + name: 'blah', + columns: { + id: { + dataType: 'serial', + notNull: true, + primaryKey: true + }, + email: { + dataType: 'text', + notNull: true, + unique: true + } + } + }); + const cols = table.columns; + strictEqual(cols.length, 2); + const id = cols[0]; + strictEqual(id.name, 'id'); + strictEqual(id.dataType, 'serial'); + strictEqual(id.notNull, true); + strictEqual(id.primaryKey, true); + const email = cols[1]; + strictEqual(email.name, 'email'); + strictEqual(email.dataType, 'text'); + strictEqual(email.notNull, true); + strictEqual(email.unique, true); +}); + +test('table with dynamic column definition', function() { + const table = Table.define({ name: 'foo', columns: [] }); + strictEqual(table.columns.length, 0); + + table.addColumn('foo'); + strictEqual(table.columns.length, 1); + + throws(function() { + table.addColumn('foo'); + }); + + doesNotThrow(function() { + table.addColumn('foo', { noisy: false }); + }); + + strictEqual(table.columns.length, 1); +}); + +test('hasColumn', function() { + const table = Table.define({ name: 'foo', columns: [] }); + + strictEqual(table.hasColumn('baz'), false); + table.addColumn('baz'); + strictEqual(table.hasColumn('baz'), true); +}); + +test('hasColumn with user-defined column property', function() { + const table = Table.define({ + name: 'blah', + columns: [ + { + name: 'id', + property: 'theId' + }, + { name: 'foo' } + ] + }); + + strictEqual(table.hasColumn('id'), true); + strictEqual(table.hasColumn('theId'), true); +}); + +test('the column "from" does not overwrite the from method', function() { + const table = Table.define({ name: 'foo', columns: [] }); + table.addColumn('from'); + strictEqual(typeof table.from, 'function'); +}); + +test('getColumn returns the from column', function() { + const table = Table.define({ name: 'foo', columns: [] }); + table.addColumn('from'); + assert(table.getColumn('from') instanceof Column); + assert(table.get('from') instanceof Column); +}); + +test('set and get schema', function() { + const table = Table.define({ name: 'foo', schema: 'bar', columns: [] }); + strictEqual(table.getSchema(), 'bar'); + table.setSchema('barbarz'); + strictEqual(table.getSchema(), 'barbarz'); +}); + +suite('table.clone', function() { + test('check if it is a copy, not just a reference', function() { + const table = Table.define({ name: 'foo', columns: [] }); + const copy = table.clone(); + notStrictEqual(table, copy); + }); + + test('copy columns', function() { + const table = Table.define({ name: 'foo', columns: ['bar'] }); + const copy = table.clone(); + assert(copy.get('bar') instanceof Column); + }); + + test('overwrite config while copying', function() { + const table = Table.define({ + name: 'foo', + schema: 'foobar', + columns: ['bar'], + snakeToCamel: true, + columnWhiteList: true + }); + + const copy = table.clone({ + schema: 'test', + snakeToCamel: false, + columnWhiteList: false + }); + + strictEqual(copy.getSchema(), 'test'); + strictEqual(copy.snakeToCamel, false); + strictEqual(copy.columnWhiteList, false); + }); +}); + +test('dialects', function() { + const sql1 = new Sql('mysql'); + const foo1 = sql1.define<{ id: number }>({ name: 'foo', columns: ['id'] }); + const bar1 = sql1.define<{ id: number }>({ name: 'bar', columns: ['id'] }); + + const actual1 = foo1 + .join(bar1) + .on(bar1.id.equals(1)) + .toString(); + strictEqual(actual1, '`foo` INNER JOIN `bar` ON (`bar`.`id` = 1)'); + + const sql2 = new Sql('postgres'); + const foo2 = sql2.define<{ id: number }>({ name: 'foo', columns: ['id'] }); + const bar2 = sql2.define<{ id: number }>({ name: 'bar', columns: ['id'] }); + const actual2 = foo2 + .join(bar2) + .on(bar2.id.equals(1)) + .toString(); + strictEqual(actual2, '"foo" INNER JOIN "bar" ON ("bar"."id" = 1)'); +}); + +test('limit', function() { + const user = Table.define({ name: 'user', columns: ['id', 'name'] }); + const query = user.limit(3); + strictEqual(query.nodes.length, 1); + strictEqual(query.nodes[0].type, 'LIMIT'); + strictEqual(((query.nodes[0] as ModifierNode).count as ParameterNode).value(), 3); +}); + +test('offset', function() { + const user = Table.define({ name: 'user', columns: ['id', 'name'] }); + const query = user.offset(20); + strictEqual(query.nodes.length, 1); + strictEqual(query.nodes[0].type, 'OFFSET'); + strictEqual(((query.nodes[0] as ModifierNode).count as ParameterNode).value(), 20); +}); + +test('order', function() { + const user = Table.define<{ id: number; name: string }>({ name: 'user', columns: ['id', 'name'] }); + const query = user.order(user.name); + strictEqual(query.nodes.length, 1); + strictEqual(query.nodes[0].type, 'ORDER BY'); +}); diff --git a/test/ternary-clause-tests.js b/test/ternary-clause-tests.js deleted file mode 100644 index 1e7c975f..00000000 --- a/test/ternary-clause-tests.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -var assert = require('assert'); -var Table = require(__dirname + '/../lib/table'); - -var Foo = Table.define({ - name: 'foo', - columns: ['baz','bar'] -}); - -test('operators', function() { - assert.equal(Foo.bar.between(1, 2).operator, 'BETWEEN'); - assert.equal(Foo.baz.between(1, 2).separator, 'AND'); -}); diff --git a/test/ternary-clause-tests.ts b/test/ternary-clause-tests.ts new file mode 100644 index 00000000..69ca303f --- /dev/null +++ b/test/ternary-clause-tests.ts @@ -0,0 +1,12 @@ +import assert from 'assert'; +import { Table } from '../dist/lib.js'; + +const Foo = Table.define<{ baz: string; bar: string }>({ + name: 'foo', + columns: ['baz', 'bar'] +}); + +test('operators', function() { + assert.strictEqual(Foo.bar.between(1, 2).operator, 'BETWEEN'); + assert.strictEqual(Foo.baz.between(1, 2).separator, 'AND'); +}); diff --git a/test/tsconfig.json b/test/tsconfig.json new file mode 100644 index 00000000..7fb67499 --- /dev/null +++ b/test/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../spec", + "types": ["lodash", "mocha", "node", "sliced"] + }, + "include": ["./*.ts", "./**/*.ts", "./**/*.js", "./**/*.d.ts"] +} diff --git a/test/unary-clause-tests.js b/test/unary-clause-tests.js deleted file mode 100644 index f5b36a1b..00000000 --- a/test/unary-clause-tests.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -var assert = require('assert'); -var Table = require(__dirname + '/../lib/table'); - -var Foo = Table.define({ - name: 'foo', - columns: ['baz','bar'] -}); - -test('operators', function() { - assert.equal(Foo.bar.isNull().operator, 'IS NULL'); - assert.equal(Foo.baz.isNotNull().operator, 'IS NOT NULL'); -}); diff --git a/test/unary-clause-tests.ts b/test/unary-clause-tests.ts new file mode 100644 index 00000000..2accd93c --- /dev/null +++ b/test/unary-clause-tests.ts @@ -0,0 +1,12 @@ +import assert from 'assert'; +import { Table } from '../dist/lib.js'; + +const Foo = Table.define<{ baz: string; bar: string }>({ + name: 'foo', + columns: ['baz', 'bar'] +}); + +test('operators', function() { + assert.strictEqual(Foo.bar.isNull().operator, 'IS NULL'); + assert.strictEqual(Foo.baz.isNotNull().operator, 'IS NOT NULL'); +}); diff --git a/test/value-expression-tests.js b/test/value-expression-tests.js deleted file mode 100644 index ec80415a..00000000 --- a/test/value-expression-tests.js +++ /dev/null @@ -1,18 +0,0 @@ -'use strict'; - -var assert = require('assert'); -var valueExpressionMixin = require(__dirname + './../lib/node/valueExpression'); -var Node = require(__dirname + './../lib/node'); - -suite('value-expression', function() { - test("value expression mixin should not overwrite Node prototype properties", function() { - var mixin = valueExpressionMixin(); - - // make sure that the node class doesn't have any conflicting properties - for (var key in mixin) { - if (mixin.hasOwnProperty(key)) { - assert.equal(Node.prototype[key], undefined); - } - } - }); -}); diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 00000000..6e9c87e5 --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./lib", + "declarationDir": "./dist/dts" + }, + "include": ["./lib/**/*.ts"] +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..59dde7b6 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "es2022", + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "esModuleInterop": true, + "noEmitHelpers": true, + "importHelpers": true, + "pretty": true, + "sourceMap": true, + "lib": ["es2022", "esnext.asynciterable"], + "strict": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "removeComments": false, + "noImplicitReturns": true, + "declaration": true, + "typeRoots": ["./@types", "./node_modules/@types"], + "types": ["lodash", "node", "sliced"] + }, + "exclude": ["node_modules", "./dist"], + "compileOnSave": true, + "buildOnSave": true +}