123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- import { Op, cast, fn, json, sql, where } from '@sequelize/core';
- import { expectsql, sequelize } from '../../support';
- const dialect = sequelize.dialect;
- const queryGenerator = sequelize.queryGenerator;
- describe('json', () => {
- if (!dialect.supports.jsonOperations || !dialect.supports.jsonExtraction.quoted) {
- return;
- }
- it('supports WhereOptions', () => {
- const conditions = {
- metadata: {
- language: 'icelandic',
- pg_rating: { dk: 'G' },
- },
- another_json_field: { x: 1 },
- };
- expectsql(() => queryGenerator.escape(json(conditions)), {
- postgres: `("metadata"->'language' = '"icelandic"' AND "metadata"#>ARRAY['pg_rating','dk']::VARCHAR(255)[] = '"G"') AND "another_json_field"->'x' = '1'`,
- sqlite3: `(json_extract(\`metadata\`,'$.language') = '"icelandic"' AND json_extract(\`metadata\`,'$.pg_rating.dk') = '"G"') AND json_extract(\`another_json_field\`,'$.x') = '1'`,
- mariadb: `(json_compact(json_extract(\`metadata\`,'$.language')) = '"icelandic"' AND json_compact(json_extract(\`metadata\`,'$.pg_rating.dk')) = '"G"') AND json_compact(json_extract(\`another_json_field\`,'$.x')) = '1'`,
- mysql: `(json_extract(\`metadata\`,'$.language') = CAST('"icelandic"' AS JSON) AND json_extract(\`metadata\`,'$.pg_rating.dk') = CAST('"G"' AS JSON)) AND json_extract(\`another_json_field\`,'$.x') = CAST('1' AS JSON)`,
- });
- });
- it('supports the json path notation', () => {
- const path = 'metadata.pg_rating.dk';
- expectsql(() => queryGenerator.escape(json(path)), {
- postgres: `"metadata"#>ARRAY['pg_rating','dk']::VARCHAR(255)[]`,
- mariadb: `json_compact(json_extract(\`metadata\`,'$.pg_rating.dk'))`,
- 'sqlite3 mysql': `json_extract(\`metadata\`,'$.pg_rating.dk')`,
- });
- });
- it('supports numbers in the dot notation', () => {
- expectsql(() => queryGenerator.escape(json('profile.id.0.1')), {
- postgres: `"profile"#>ARRAY['id','0','1']::VARCHAR(255)[]`,
- mariadb: `json_compact(json_extract(\`profile\`,'$.id."0"."1"'))`,
- 'sqlite3 mysql': `json_extract(\`profile\`,'$.id."0"."1"')`,
- });
- });
- it('can take a value to compare against', () => {
- const path = 'metadata.pg_rating.is';
- const value = 'U';
- expectsql(() => queryGenerator.escape(json(path, value)), {
- postgres: `"metadata"#>ARRAY['pg_rating','is']::VARCHAR(255)[] = '"U"'`,
- sqlite3: `json_extract(\`metadata\`,'$.pg_rating.is') = '"U"'`,
- mariadb: `json_compact(json_extract(\`metadata\`,'$.pg_rating.is')) = '"U"'`,
- mysql: `json_extract(\`metadata\`,'$.pg_rating.is') = CAST('"U"' AS JSON)`,
- });
- });
- // TODO: add a way to let `where` know what the type of the value is in raw queries
- // it('accepts a condition object', () => {
- // expectsql(queryGenerator.escape(json({ id: 1 })), {
- // postgres: `"id" = '1'`,
- // });
- // });
- //
- // it('column named "json"', () => {
- // expectsql(queryGenerator.escape(where(json('json'), Op.eq, {})), {
- // postgres: `("json"#>>'{}') = '{}'`,
- // });
- // });
- it('accepts a nested condition object', () => {
- expectsql(() => queryGenerator.escape(json({ profile: { id: 1 } })), {
- postgres: `"profile"->'id' = '1'`,
- sqlite3: `json_extract(\`profile\`,'$.id') = '1'`,
- mariadb: `json_compact(json_extract(\`profile\`,'$.id')) = '1'`,
- mysql: `json_extract(\`profile\`,'$.id') = CAST('1' AS JSON)`,
- });
- });
- it('accepts multiple condition object', () => {
- expectsql(
- () => queryGenerator.escape(json({ property: { value: 1 }, another: { value: 'string' } })),
- {
- postgres: `"property"->'value' = '1' AND "another"->'value' = '"string"'`,
- sqlite3: `json_extract(\`property\`,'$.value') = '1' AND json_extract(\`another\`,'$.value') = '"string"'`,
- mariadb: `json_compact(json_extract(\`property\`,'$.value')) = '1' AND json_compact(json_extract(\`another\`,'$.value')) = '"string"'`,
- mysql: `json_extract(\`property\`,'$.value') = CAST('1' AS JSON) AND json_extract(\`another\`,'$.value') = CAST('"string"' AS JSON)`,
- },
- );
- });
- it('can be used inside of where', () => {
- expectsql(() => queryGenerator.escape(where(json('profile.id'), '1')), {
- postgres: `"profile"->'id' = '"1"'`,
- sqlite3: `json_extract(\`profile\`,'$.id') = '"1"'`,
- mariadb: `json_compact(json_extract(\`profile\`,'$.id')) = '"1"'`,
- mysql: `json_extract(\`profile\`,'$.id') = CAST('"1"' AS JSON)`,
- });
- });
- });
- describe('cast', () => {
- it('accepts condition object (auto casting)', () => {
- expectsql(
- () =>
- queryGenerator.escape(
- fn(
- 'SUM',
- cast(
- {
- [Op.or]: {
- foo: 'foo',
- bar: 'bar',
- },
- },
- 'int',
- ),
- ),
- ),
- {
- default: `SUM(CAST(([foo] = 'foo' OR [bar] = 'bar') AS INT))`,
- mssql: `SUM(CAST(([foo] = N'foo' OR [bar] = N'bar') AS INT))`,
- },
- );
- });
- });
- describe('fn', () => {
- // this was a band-aid over a deeper problem ('$bind' being considered to be a bind parameter when it's a string), which has been fixed
- it('should not escape $ in fn() arguments', () => {
- const out = queryGenerator.escape(fn('upper', '$user'));
- expectsql(out, {
- default: `upper('$user')`,
- mssql: `upper(N'$user')`,
- });
- });
- it('accepts all sorts of values as arguments', () => {
- const out = queryGenerator.escape(
- fn(
- 'concat',
- 'user',
- 1,
- true,
- new Date(Date.UTC(2011, 2, 27, 10, 1, 55)),
- fn('lower', 'user'),
- ),
- );
- expectsql(out, {
- postgres: `concat('user', 1, true, '2011-03-27 10:01:55.000 +00:00', lower('user'))`,
- mssql: `concat(N'user', 1, 1, N'2011-03-27 10:01:55.000 +00:00', lower(N'user'))`,
- sqlite3: `concat('user', 1, 1, '2011-03-27 10:01:55.000 +00:00', lower('user'))`,
- ibmi: `concat('user', 1, 1, '2011-03-27 10:01:55.000', lower('user'))`,
- default: `concat('user', 1, true, '2011-03-27 10:01:55.000', lower('user'))`,
- });
- });
- it('accepts arrays', () => {
- if (!dialect.supports.dataTypes.ARRAY) {
- return;
- }
- const out = queryGenerator.escape(fn('concat', ['abc']));
- expectsql(out, {
- default: `concat(ARRAY['abc'])`,
- postgres: `concat(ARRAY['abc']::VARCHAR(255)[])`,
- });
- });
- });
- describe('sql.join', () => {
- it('joins parts with a separator', () => {
- const columns = ['a', 'b', 'c'];
- // SQL expression parts, string separator
- expectsql(
- queryGenerator.escape(
- sql`SELECT ${sql.join(
- columns.map(col => sql.identifier(col)),
- ', ',
- )} FROM users`,
- ),
- {
- default: `SELECT [a], [b], [c] FROM users`,
- },
- );
- // string parts, SQL expression separator
- expectsql(
- queryGenerator.escape(
- sql`SELECT a FROM users WHERE id IN (${sql.join(['id1', 'id2', 'id3'], sql`, `)}) FROM users`,
- ),
- {
- default: `SELECT a FROM users WHERE id IN ('id1', 'id2', 'id3') FROM users`,
- mssql: `SELECT a FROM users WHERE id IN (N'id1', N'id2', N'id3') FROM users`,
- },
- );
- });
- });
- describe('sql.identifier', () => {
- it('accepts strings', () => {
- const out = queryGenerator.escape(sql.identifier('foo'));
- expectsql(out, {
- default: `[foo]`,
- });
- });
- it('accepts table structures', () => {
- const out = queryGenerator.escape(sql.identifier({ schema: 'foo', tableName: 'bar' }));
- expectsql(out, {
- default: `[foo].[bar]`,
- sqlite3: '`foo.bar`',
- });
- });
- it('accepts model classes', () => {
- const User = sequelize.define(
- 'User',
- {},
- {
- schema: 'schema',
- tableName: 'users',
- },
- );
- const out = queryGenerator.escape(sql.identifier(User));
- expectsql(out, {
- default: `[schema].[users]`,
- sqlite3: '`schema.users`',
- });
- });
- it('accepts model definitions', () => {
- const User = sequelize.define(
- 'User',
- {},
- {
- schema: 'schema',
- tableName: 'users',
- },
- );
- const out = queryGenerator.escape(sql.identifier(User.modelDefinition));
- expectsql(out, {
- default: `[schema].[users]`,
- sqlite3: '`schema.users`',
- });
- });
- it('accepts multiple parameters', () => {
- const User = sequelize.define(
- 'User',
- {},
- {
- schema: 'schema',
- tableName: 'table',
- },
- );
- const out = queryGenerator.escape(sql.identifier('database', User, 'column'));
- expectsql(out, {
- default: `[database].[schema].[table].[column]`,
- sqlite3: '`database`.`schema.table`.`column`',
- });
- });
- });
|