An in memory postgres DB instance for your unit tests

Overview

pg-mem is an experimental in-memory emulation of a postgres database.

It works both in Node or in the browser.

this repo if you like this package, it helps to motivate me :)

👉 See it in action with pg-mem playground

📐 Usage

Using Node.js

As always, it starts with an:

npm i pg-mem --save

Then, assuming you're using something like webpack, if you're targeting a browser:

import { newDb } from 'pg-mem';

const db = newDb();
db.public.many(/* put some sql here */)

Using Deno

Pretty straightforward :)

import { newDb } from 'https://deno.land/x/pg_mem/mod.ts';

const db = newDb();
db.public.many(/* put some sql here */)

Only use the SQL syntax parser

Head to the pgsql-ast-parser repo

Disclaimer

The sql syntax parser is home-made. Which means that some features are not implemented, and will be considered as invalid syntaxes.

This lib is quite new, so forgive it if some obvious pg syntax is not supported !

... And open an issue if you feel like a feature should be implemented :)

Moreover, even if I wrote hundreds of tests, keep in mind that this implementation is a best effort to replicate PG. Keep an eye on your query results if you perform complex queries. Please file issues if some results seem incoherent with what should be returned.

Finally, I invite you to read the below section to have an idea of you can or cannot do.

🔍 Features

Rollback to a previous state

pg-mem uses immutable data structures (here and here), which means that you can have restore points for free!

This is super useful if you intend to use pg-mem to mock your database for unit tests.

You could:

  1. Create your schema only once (which could be a heavy operation for a single unit test)
  2. Insert test data which will be shared by all test
  3. Create a restore point
  4. Run your tests with the same db instance, executing a backup.restore() before each test (which instantly resets db to the state it has after creating the restore point)

Usage:

const db = newDb();
db.public.none(`create table test(id text);
                insert into test values ('value');`);
// create a restore point & mess with data
const backup = db.backup();
db.public.none(`update test set id='new value';`)
// restore it !
backup.restore();
db.public.many(`select * from test`) // => {test: 'value'}

Custom functions

You can declare custom functions like this:

db.public.registerFunction({
            name: 'say_hello',
            args: [DataType.text],
            returns: DataType.text,
            implementation: x => 'hello ' + x,
        })

And then use them like in SQL select say_hello('world').

Custom functions support overloading and variadic arguments.

However, the value you return is not type checked. It MUST correspond to the datatype you provided as 'returns' (it won't fail if not, but could lead to weird bugs).

Custom types

Not all pg types are implemented in pg-mem. That said, most of the types are often equivalent to other types, with a format validation. pg-mem provides a way to register such types.

For instance, lets say you'd like to register the MACADDR type, which is basically a string, with a format constraint.

You can register it like this:

db.public.registerEquivalentType({
    name: 'macaddr',
    // which type is it equivalent to (will be able to cast it from it)
    equivalentTo: DataType.text,
    isValid(val: string) {
        // check that it will be this format
        return isValidMacAddress(val);
    }
});

Doing so, you'll be able to do things such as:

SELECT '08:00:2b:01:02:03:04:05'::macaddr; -- WORKS
SELECT 'invalid'::macaddr; -- will throw a conversion error

If you feel your implementation of a type matches the standard, and would like to include it in pg-mem for others to enjoy it, please consider filing a pull request ! (tip: see the INET type implementation as an example, and the pg_catalog index where supported types are registered)

Extensions

No native extension is implemented (pull requests are welcome), but you can define kind-of extensions like this:

db.registerExtension('my-ext', schema => {
    // install your ext in 'schema'
    // ex:  schema.registerFunction(...)
});

Statements like create extension "my-ext" will then be supported.

📃 Libraries adapters

pg-mem provides handy shortcuts to create instances of popular libraries that will be bound to pg-mem instead of a real postgres db.

  • pg-native
  • node-postgres (pg)
  • pg-promise (pgp)
  • slonik
  • typeorm
  • knex
  • mikro-orm

See the wiki for more details

💥 Inspection

Intercept queries

If you would like to hook your database, and return ad-hoc results, you can do so like this:

const db = newDb();

db.public.interceptQueries(sql => {
    if (sql === 'select * from whatever') {
        // intercept this statement, and return something custom:
        return [{something: 42}];
    }
    // proceed to actual SQL execution for other requests.
    return null;
});

Inspect a table

You can manually inspect a table content using the find() method:

for (const item of db.public.getTable<TItem>('mytable').find(itemTemplate)) {
  console.log(item);
}

Manually insert items

If you'd like to insert items manually into a table, you can do this like that:

db.public.getTable<TItem>('mytable').insert({ /* item to insert */ }))

Subscribe to events

You can subscribe to some events, like:

const db = newDb();

// called on each successful sql request
db.on('query', sql => {  });
// called on each failed sql request
db.on('query-failed', sql => { });
// called on schema changes
db.on('schema-change', () => {});
// called when a CREATE EXTENSION schema is encountered.
db.on('create-extension', ext => {});

Experimental events

pg-mem implements a basic support for indices.

These handlers are called when a request cannot be optimized using one of the created indices.

However, a real postgres instance will be much smarter to optimize its requests... so when pg-mem says "this request does not use an index", dont take my word for it.

// called when a table is iterated entirely (ex: 'select * from data where notIndex=3' triggers it)
db.on('seq-scan', () => {});

// same, but on a specific table
db.getTable('myTable').on('seq-scan', () = {});

// will be called if pg-mem did not find any way to optimize a join
// (which leads to a O(n*m) lookup with the current implementation)
db.on('catastrophic-join-optimization', () => {});

🙋‍♂️ FAQ

Detailed answers in the wiki

🐜 Development

Pull requests are welcome :)

To start hacking this lib, you'll have to:

... once done, tests should appear. HMR is on, which means that changes in your code are instantly propagated to unit tests. This allows for ultra fast development cycles (running tests takes less than 1 sec).

To debug tests: Just hit "run" (F5, or whatever)... VS Code should attach the mocha worker. Then run the test you want to debug.

Alternatively, you could just run npm run test without installing anything, but this is a bit long.

Comments
  • Type

    Type "regclass"

    This type is specific to table relations and casting to OIDs for internal relations. I believe this type is used by TypeORM for the relationship decorators.

    Is there a possibility of this being implemented in the future?

    Error for reference:
    Error: Not supported: Type "regclass"
              at Object.fromNative (/home/bobby/phorm-new/node_modules/pg-mem/src/datatypes.ts:858:19)
              at _buildValueReal (/home/bobby/phorm-new/node_modules/pg-mem/src/predicate.ts:82:26)
              at _buildValue (/home/bobby/phorm-new/node_modules/pg-mem/src/predicate.ts:33:11)
              at _buildValueReal (/home/bobby/phorm-new/node_modules/pg-mem/src/predicate.ts:81:20)
              at _buildValue (/home/bobby/phorm-new/node_modules/pg-mem/src/predicate.ts:33:11)
              at /home/bobby/phorm-new/node_modules/pg-mem/src/predicate.ts:77:44
              at Array.map (<anonymous>)
              at _buildValueReal (/home/bobby/phorm-new/node_modules/pg-mem/src/predicate.ts:77:35)
              at _buildValue (/home/bobby/phorm-new/node_modules/pg-mem/src/predicate.ts:33:11)
              at Object.buildValue (/home/bobby/phorm-new/node_modules/pg-mem/src/predicate.ts:16:12)
              at new Selection (/home/bobby/phorm-new/node_modules/pg-mem/src/transforms/selection.ts:132:28)
              at Object.buildSelection (/home/bobby/phorm-new/node_modules/pg-mem/src/transforms/selection.ts:30:12)
              at OrFilter.select (/home/bobby/phorm-new/node_modules/pg-mem/src/transforms/transform-base.ts:46:20)
              at Query.buildSelect (/home/bobby/phorm-new/node_modules/pg-mem/src/query.ts:399:23)
              at Query.queries (/home/bobby/phorm-new/node_modules/pg-mem/src/query.ts:98:47)
              at queries.next (<anonymous>)
              at Query.query (/home/bobby/phorm-new/node_modules/pg-mem/src/query.ts:42:20)
              at /home/bobby/phorm-new/node_modules/pg-mem/src/adapters.ts:81:80
              at Timeout.task [as _onTimeout] (/home/bobby/phorm-new/node_modules/jsdom/lib/jsdom/browser/Window.js:391:19)
              at listOnTimeout (internal/timers.js:554:17)
              at processTimers (internal/timers.js:497:7)
    
    enhancement 
    opened by MirrorBytes 36
  • pg-promise and exporting Schemas Automatically

    pg-promise and exporting Schemas Automatically

    Context:

    • I am not using nor do I want to use an ORM
    • I need an in-memory DB that pulls schemas exported somehow from my real DB and creates the tables

    Is there a way for me to: 1) Export my schemas from my postgres DB in a format your library will take and run with that creates the tables automatically for me?

    I looked at your examples but none of them talks about some way to do what I'm saying without using an ORM.

    Like does yours do something like sqlite has:

    https://sqlite.org/schematab.html

    opened by dschinkel 14
  • knex onConflict merge with columns

    knex onConflict merge with columns

    Describe the bug

    When using createKnex adapter, we have an issue with queries that do upsert on selected columns. merge without specifying columns is working fine.

    Column "0" not found
    

    To Reproduce

    const data = [
            { id: 1, other_id: 111, some_field: 'value', created_at: new Date(), updated_at: new Date() },
            { id: 2, other_id: 222, some_field: 'value2', created_at: new Date(), updated_at: new Date() }
        ];
        const query = knex('example').insert(data).onConflict(['id', 'other_id']).merge(['updated_at', 'some_field']);
        console.log(query.toSQL());
    

    it will produce do update set "0" = ?,"1" = ?' should be do update set "some_field" = excluded."some_field", "updated_at" = excluded."updated_at"'

    {
      method: 'insert',
      options: {},
      timeout: false,
      cancelOnTimeout: false,
      bindings: [
        2022-01-31T21:17:53.130Z,
        1,
        111,
        'value',
        2022-01-31T21:17:53.130Z,
        2022-01-31T21:17:53.130Z,
        2,
        222,
        'value2',
        2022-01-31T21:17:53.130Z,
        'updated_at',
        'some_field'
      ],
      __knexQueryUid: 'lwEt8xzcV2xKl87iZdJQl',
      sql: 'insert into "example" ("created_at", "id", "other_id", "some_field", "updated_at") values (?, ?, ?, ?, ?), (?, ?, ?, ?, ?) on conflict ("id", "other_id") do update set "0" = ?,"1" = ?',
      returning: undefined
    }
    

    pg-mem version

    2.3.0

    opened by elad-sf 13
  • Extension, and col_description errors

    Extension, and col_description errors

    So I have 2 different errors.

    One is related to CREATE EXTENSION IF when trying to use UUIDs:

    Error: Syntax error at line 1 col 18:
    
            CREATE EXTENSION IF
                             ^
          Unexpected word token: "IF". I did not expect any more input. Here is the state of my parse table:
    
              kw_index → %word ●
    
              at Parser.feed (/home/bobby/phorm-new/node_modules/nearley/lib/nearley.js:343:27)
              at _parse (/home/bobby/phorm-new/node_modules/pgsql-ast-parser/src/parser.ts:43:12)
              at Object.parse (/home/bobby/phorm-new/node_modules/pgsql-ast-parser/src/parser.ts:24:18)
              at Object.parseSql (/home/bobby/phorm-new/node_modules/pg-mem/src/parse-cache.ts:25:15)
              at Query.parse (/home/bobby/phorm-new/node_modules/pg-mem/src/query.ts:80:16)
              at Query.queries (/home/bobby/phorm-new/node_modules/pg-mem/src/query.ts:88:31)
              at queries.next (<anonymous>)
              at Query.query (/home/bobby/phorm-new/node_modules/pg-mem/src/query.ts:67:20)
              at /home/bobby/phorm-new/node_modules/pg-mem/src/adapters.ts:81:80
              at Timeout.task [as _onTimeout] (/home/bobby/phorm-new/node_modules/jsdom/lib/jsdom/browser/Window.js:391:19)
              at listOnTimeout (internal/timers.js:554:17)
              at processTimers (internal/timers.js:497:7)
    

    The other seems to be the AST parser disliking column descriptions (or at least the function):

    An insanely long AST error (I'm assuming)
    Error: Syntax error at line 4 col 43:
    
                            pg_catalog.col_description(
                                                      ^
          Unexpected lparen token: "(". Instead, I was expecting to see one of the following:
    
          A op_cast token based on:
              expr_member → expr_member$subexpression$3 ● %op_cast data_type
              expr_array_index →  ● expr_member
              expr_unary_add$macrocall$4 →  ● expr_array_index
              expr_unary_add$macrocall$1 →  ● expr_unary_add$macrocall$4
              expr_unary_add →  ● expr_unary_add$macrocall$1
              expr_exp$macrocall$4 →  ● expr_unary_add
              expr_exp$macrocall$1 →  ● expr_exp$macrocall$4
              expr_exp →  ● expr_exp$macrocall$1
              expr_mult$macrocall$4 →  ● expr_exp
              expr_mult$macrocall$1 →  ● expr_mult$macrocall$4
              expr_mult →  ● expr_mult$macrocall$1
              expr_add$macrocall$4 →  ● expr_mult
              expr_add$macrocall$1 →  ● expr_add$macrocall$4
              expr_add →  ● expr_add$macrocall$1
              expr_in$macrocall$4 →  ● expr_add
              expr_in$macrocall$1 →  ● expr_in$macrocall$4
              expr_in →  ● expr_in$macrocall$1
              expr_like$macrocall$4 →  ● expr_in
              expr_like$macrocall$1 →  ● expr_like$macrocall$4
              expr_like →  ● expr_like$macrocall$1
              expr_range$macrocall$5 →  ● expr_like
              expr_range$macrocall$1 →  ● expr_range$macrocall$5
              expr_range →  ● expr_range$macrocall$1
              expr_compare$macrocall$4 →  ● expr_range
              expr_compare$macrocall$1 →  ● expr_compare$macrocall$4
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A lbracket token based on:
              expr_array_index → expr_array_index$subexpression$1 ● %lbracket expr_nostar %rbracket
              expr_unary_add$macrocall$4 →  ● expr_array_index
              expr_unary_add$macrocall$1 →  ● expr_unary_add$macrocall$4
              expr_unary_add →  ● expr_unary_add$macrocall$1
              expr_exp$macrocall$4 →  ● expr_unary_add
              expr_exp$macrocall$1 →  ● expr_exp$macrocall$4
              expr_exp →  ● expr_exp$macrocall$1
              expr_mult$macrocall$4 →  ● expr_exp
              expr_mult$macrocall$1 →  ● expr_mult$macrocall$4
              expr_mult →  ● expr_mult$macrocall$1
              expr_add$macrocall$4 →  ● expr_mult
              expr_add$macrocall$1 →  ● expr_add$macrocall$4
              expr_add →  ● expr_add$macrocall$1
              expr_in$macrocall$4 →  ● expr_add
              expr_in$macrocall$1 →  ● expr_in$macrocall$4
              expr_in →  ● expr_in$macrocall$1
              expr_like$macrocall$4 →  ● expr_in
              expr_like$macrocall$1 →  ● expr_like$macrocall$4
              expr_like →  ● expr_like$macrocall$1
              expr_range$macrocall$5 →  ● expr_like
              expr_range$macrocall$1 →  ● expr_range$macrocall$5
              expr_range →  ● expr_range$macrocall$1
              expr_compare$macrocall$4 →  ● expr_range
              expr_compare$macrocall$1 →  ● expr_compare$macrocall$4
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A op_member token based on:
              ops_member$subexpression$1 →  ● %op_member
              ops_member →  ● ops_member$subexpression$1
              expr_member → expr_member$subexpression$1 ● ops_member expr_member$subexpression$2
              expr_array_index →  ● expr_member
              expr_unary_add$macrocall$4 →  ● expr_array_index
              expr_unary_add$macrocall$1 →  ● expr_unary_add$macrocall$4
              expr_unary_add →  ● expr_unary_add$macrocall$1
              expr_exp$macrocall$4 →  ● expr_unary_add
              expr_exp$macrocall$1 →  ● expr_exp$macrocall$4
              expr_exp →  ● expr_exp$macrocall$1
              expr_mult$macrocall$4 →  ● expr_exp
              expr_mult$macrocall$1 →  ● expr_mult$macrocall$4
              expr_mult →  ● expr_mult$macrocall$1
              expr_add$macrocall$4 →  ● expr_mult
              expr_add$macrocall$1 →  ● expr_add$macrocall$4
              expr_add →  ● expr_add$macrocall$1
              expr_in$macrocall$4 →  ● expr_add
              expr_in$macrocall$1 →  ● expr_in$macrocall$4
              expr_in →  ● expr_in$macrocall$1
              expr_like$macrocall$4 →  ● expr_in
              expr_like$macrocall$1 →  ● expr_like$macrocall$4
              expr_like →  ● expr_like$macrocall$1
              expr_range$macrocall$5 →  ● expr_like
              expr_range$macrocall$1 →  ● expr_range$macrocall$5
              expr_range →  ● expr_range$macrocall$1
              expr_compare$macrocall$4 →  ● expr_range
              expr_compare$macrocall$1 →  ● expr_compare$macrocall$4
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A op_membertext token based on:
              ops_member$subexpression$1 →  ● %op_membertext
              ops_member →  ● ops_member$subexpression$1
              expr_member → expr_member$subexpression$1 ● ops_member expr_member$subexpression$2
              expr_array_index →  ● expr_member
              expr_unary_add$macrocall$4 →  ● expr_array_index
              expr_unary_add$macrocall$1 →  ● expr_unary_add$macrocall$4
              expr_unary_add →  ● expr_unary_add$macrocall$1
              expr_exp$macrocall$4 →  ● expr_unary_add
              expr_exp$macrocall$1 →  ● expr_exp$macrocall$4
              expr_exp →  ● expr_exp$macrocall$1
              expr_mult$macrocall$4 →  ● expr_exp
              expr_mult$macrocall$1 →  ● expr_mult$macrocall$4
              expr_mult →  ● expr_mult$macrocall$1
              expr_add$macrocall$4 →  ● expr_mult
              expr_add$macrocall$1 →  ● expr_add$macrocall$4
              expr_add →  ● expr_add$macrocall$1
              expr_in$macrocall$4 →  ● expr_add
              expr_in$macrocall$1 →  ● expr_in$macrocall$4
              expr_in →  ● expr_in$macrocall$1
              expr_like$macrocall$4 →  ● expr_in
              expr_like$macrocall$1 →  ● expr_like$macrocall$4
              expr_like →  ● expr_like$macrocall$1
              expr_range$macrocall$5 →  ● expr_like
              expr_range$macrocall$1 →  ● expr_range$macrocall$5
              expr_range →  ● expr_range$macrocall$1
              expr_compare$macrocall$4 →  ● expr_range
              expr_compare$macrocall$1 →  ● expr_compare$macrocall$4
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A op_exp token based on:
              expr_exp$macrocall$2 →  ● %op_exp
              expr_exp$macrocall$1 → expr_exp$macrocall$1$subexpression$1 ● expr_exp$macrocall$2 expr_exp$macrocall$1$subexpression$2
              expr_exp →  ● expr_exp$macrocall$1
              expr_mult$macrocall$4 →  ● expr_exp
              expr_mult$macrocall$1 →  ● expr_mult$macrocall$4
              expr_mult →  ● expr_mult$macrocall$1
              expr_add$macrocall$4 →  ● expr_mult
              expr_add$macrocall$1 →  ● expr_add$macrocall$4
              expr_add →  ● expr_add$macrocall$1
              expr_in$macrocall$4 →  ● expr_add
              expr_in$macrocall$1 →  ● expr_in$macrocall$4
              expr_in →  ● expr_in$macrocall$1
              expr_like$macrocall$4 →  ● expr_in
              expr_like$macrocall$1 →  ● expr_like$macrocall$4
              expr_like →  ● expr_like$macrocall$1
              expr_range$macrocall$5 →  ● expr_like
              expr_range$macrocall$1 →  ● expr_range$macrocall$5
              expr_range →  ● expr_range$macrocall$1
              expr_compare$macrocall$4 →  ● expr_range
              expr_compare$macrocall$1 →  ● expr_compare$macrocall$4
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A star token based on:
              expr_mult$macrocall$2$subexpression$1 →  ● %star
              expr_mult$macrocall$2 →  ● expr_mult$macrocall$2$subexpression$1
              expr_mult$macrocall$1 → expr_mult$macrocall$1$subexpression$1 ● expr_mult$macrocall$2 expr_mult$macrocall$1$subexpression$2
              expr_mult →  ● expr_mult$macrocall$1
              expr_add$macrocall$4 →  ● expr_mult
              expr_add$macrocall$1 →  ● expr_add$macrocall$4
              expr_add →  ● expr_add$macrocall$1
              expr_in$macrocall$4 →  ● expr_add
              expr_in$macrocall$1 →  ● expr_in$macrocall$4
              expr_in →  ● expr_in$macrocall$1
              expr_like$macrocall$4 →  ● expr_in
              expr_like$macrocall$1 →  ● expr_like$macrocall$4
              expr_like →  ● expr_like$macrocall$1
              expr_range$macrocall$5 →  ● expr_like
              expr_range$macrocall$1 →  ● expr_range$macrocall$5
              expr_range →  ● expr_range$macrocall$1
              expr_compare$macrocall$4 →  ● expr_range
              expr_compare$macrocall$1 →  ● expr_compare$macrocall$4
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A op_div token based on:
              expr_mult$macrocall$2$subexpression$1 →  ● %op_div
              expr_mult$macrocall$2 →  ● expr_mult$macrocall$2$subexpression$1
              expr_mult$macrocall$1 → expr_mult$macrocall$1$subexpression$1 ● expr_mult$macrocall$2 expr_mult$macrocall$1$subexpression$2
              expr_mult →  ● expr_mult$macrocall$1
              expr_add$macrocall$4 →  ● expr_mult
              expr_add$macrocall$1 →  ● expr_add$macrocall$4
              expr_add →  ● expr_add$macrocall$1
              expr_in$macrocall$4 →  ● expr_add
              expr_in$macrocall$1 →  ● expr_in$macrocall$4
              expr_in →  ● expr_in$macrocall$1
              expr_like$macrocall$4 →  ● expr_in
              expr_like$macrocall$1 →  ● expr_like$macrocall$4
              expr_like →  ● expr_like$macrocall$1
              expr_range$macrocall$5 →  ● expr_like
              expr_range$macrocall$1 →  ● expr_range$macrocall$5
              expr_range →  ● expr_range$macrocall$1
              expr_compare$macrocall$4 →  ● expr_range
              expr_compare$macrocall$1 →  ● expr_compare$macrocall$4
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A op_mod token based on:
              expr_mult$macrocall$2$subexpression$1 →  ● %op_mod
              expr_mult$macrocall$2 →  ● expr_mult$macrocall$2$subexpression$1
              expr_mult$macrocall$1 → expr_mult$macrocall$1$subexpression$1 ● expr_mult$macrocall$2 expr_mult$macrocall$1$subexpression$2
              expr_mult →  ● expr_mult$macrocall$1
              expr_add$macrocall$4 →  ● expr_mult
              expr_add$macrocall$1 →  ● expr_add$macrocall$4
              expr_add →  ● expr_add$macrocall$1
              expr_in$macrocall$4 →  ● expr_add
              expr_in$macrocall$1 →  ● expr_in$macrocall$4
              expr_in →  ● expr_in$macrocall$1
              expr_like$macrocall$4 →  ● expr_in
              expr_like$macrocall$1 →  ● expr_like$macrocall$4
              expr_like →  ● expr_like$macrocall$1
              expr_range$macrocall$5 →  ● expr_like
              expr_range$macrocall$1 →  ● expr_range$macrocall$5
              expr_range →  ● expr_range$macrocall$1
              expr_compare$macrocall$4 →  ● expr_range
              expr_compare$macrocall$1 →  ● expr_compare$macrocall$4
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A op_plus token based on:
              expr_add$macrocall$2$subexpression$1 →  ● %op_plus
              expr_add$macrocall$2 →  ● expr_add$macrocall$2$subexpression$1
              expr_add$macrocall$1 → expr_add$macrocall$1$subexpression$1 ● expr_add$macrocall$2 expr_add$macrocall$1$subexpression$2
              expr_add →  ● expr_add$macrocall$1
              expr_in$macrocall$4 →  ● expr_add
              expr_in$macrocall$1 →  ● expr_in$macrocall$4
              expr_in →  ● expr_in$macrocall$1
              expr_like$macrocall$4 →  ● expr_in
              expr_like$macrocall$1 →  ● expr_like$macrocall$4
              expr_like →  ● expr_like$macrocall$1
              expr_range$macrocall$5 →  ● expr_like
              expr_range$macrocall$1 →  ● expr_range$macrocall$5
              expr_range →  ● expr_range$macrocall$1
              expr_compare$macrocall$4 →  ● expr_range
              expr_compare$macrocall$1 →  ● expr_compare$macrocall$4
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A op_minus token based on:
              expr_add$macrocall$2$subexpression$1 →  ● %op_minus
              expr_add$macrocall$2 →  ● expr_add$macrocall$2$subexpression$1
              expr_add$macrocall$1 → expr_add$macrocall$1$subexpression$1 ● expr_add$macrocall$2 expr_add$macrocall$1$subexpression$2
              expr_add →  ● expr_add$macrocall$1
              expr_in$macrocall$4 →  ● expr_add
              expr_in$macrocall$1 →  ● expr_in$macrocall$4
              expr_in →  ● expr_in$macrocall$1
              expr_like$macrocall$4 →  ● expr_in
              expr_like$macrocall$1 →  ● expr_like$macrocall$4
              expr_like →  ● expr_like$macrocall$1
              expr_range$macrocall$5 →  ● expr_like
              expr_range$macrocall$1 →  ● expr_range$macrocall$5
              expr_range →  ● expr_range$macrocall$1
              expr_compare$macrocall$4 →  ● expr_range
              expr_compare$macrocall$1 →  ● expr_compare$macrocall$4
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A op_additive token based on:
              expr_add$macrocall$2$subexpression$1 →  ● %op_additive
              expr_add$macrocall$2 →  ● expr_add$macrocall$2$subexpression$1
              expr_add$macrocall$1 → expr_add$macrocall$1$subexpression$1 ● expr_add$macrocall$2 expr_add$macrocall$1$subexpression$2
              expr_add →  ● expr_add$macrocall$1
              expr_in$macrocall$4 →  ● expr_add
              expr_in$macrocall$1 →  ● expr_in$macrocall$4
              expr_in →  ● expr_in$macrocall$1
              expr_like$macrocall$4 →  ● expr_in
              expr_like$macrocall$1 →  ● expr_like$macrocall$4
              expr_like →  ● expr_like$macrocall$1
              expr_range$macrocall$5 →  ● expr_like
              expr_range$macrocall$1 →  ● expr_range$macrocall$5
              expr_range →  ● expr_range$macrocall$1
              expr_compare$macrocall$4 →  ● expr_range
              expr_compare$macrocall$1 →  ● expr_compare$macrocall$4
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A kw_not token based on:
              ops_in$ebnf$1 →  ● %kw_not
              ops_in →  ● ops_in$ebnf$1 %kw_in
              expr_in$macrocall$2 →  ● ops_in
              expr_in$macrocall$1 → expr_in$macrocall$1$subexpression$1 ● expr_in$macrocall$2 expr_in$macrocall$1$subexpression$2
              expr_in →  ● expr_in$macrocall$1
              expr_like$macrocall$4 →  ● expr_in
              expr_like$macrocall$1 →  ● expr_like$macrocall$4
              expr_like →  ● expr_like$macrocall$1
              expr_range$macrocall$5 →  ● expr_like
              expr_range$macrocall$1 →  ● expr_range$macrocall$5
              expr_range →  ● expr_range$macrocall$1
              expr_compare$macrocall$4 →  ● expr_range
              expr_compare$macrocall$1 →  ● expr_compare$macrocall$4
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A kw_in token based on:
              ops_in → ops_in$ebnf$1 ● %kw_in
              expr_in$macrocall$2 →  ● ops_in
              expr_in$macrocall$1 → expr_in$macrocall$1$subexpression$1 ● expr_in$macrocall$2 expr_in$macrocall$1$subexpression$2
              expr_in →  ● expr_in$macrocall$1
              expr_like$macrocall$4 →  ● expr_in
              expr_like$macrocall$1 →  ● expr_like$macrocall$4
              expr_like →  ● expr_like$macrocall$1
              expr_range$macrocall$5 →  ● expr_like
              expr_range$macrocall$1 →  ● expr_range$macrocall$5
              expr_range →  ● expr_range$macrocall$1
              expr_compare$macrocall$4 →  ● expr_range
              expr_compare$macrocall$1 →  ● expr_compare$macrocall$4
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A kw_not token based on:
              ops_like_keywors$ebnf$1 →  ● %kw_not
              ops_like_keywors →  ● ops_like_keywors$ebnf$1 ops_like_keywors$subexpression$1
              ops_like →  ● ops_like_keywors
              expr_like$macrocall$2 →  ● ops_like
              expr_like$macrocall$1 → expr_like$macrocall$1$subexpression$1 ● expr_like$macrocall$2 expr_like$macrocall$1$subexpression$2
              expr_like →  ● expr_like$macrocall$1
              expr_range$macrocall$5 →  ● expr_like
              expr_range$macrocall$1 →  ● expr_range$macrocall$5
              expr_range →  ● expr_range$macrocall$1
              expr_compare$macrocall$4 →  ● expr_range
              expr_compare$macrocall$1 →  ● expr_compare$macrocall$4
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A op_like token based on:
              ops_like_operators$subexpression$1 →  ● %op_like
              ops_like_operators →  ● ops_like_operators$subexpression$1
              ops_like →  ● ops_like_operators
              expr_like$macrocall$2 →  ● ops_like
              expr_like$macrocall$1 → expr_like$macrocall$1$subexpression$1 ● expr_like$macrocall$2 expr_like$macrocall$1$subexpression$2
              expr_like →  ● expr_like$macrocall$1
              expr_range$macrocall$5 →  ● expr_like
              expr_range$macrocall$1 →  ● expr_range$macrocall$5
              expr_range →  ● expr_range$macrocall$1
              expr_compare$macrocall$4 →  ● expr_range
              expr_compare$macrocall$1 →  ● expr_compare$macrocall$4
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A op_ilike token based on:
              ops_like_operators$subexpression$2 →  ● %op_ilike
              ops_like_operators →  ● ops_like_operators$subexpression$2
              ops_like →  ● ops_like_operators
              expr_like$macrocall$2 →  ● ops_like
              expr_like$macrocall$1 → expr_like$macrocall$1$subexpression$1 ● expr_like$macrocall$2 expr_like$macrocall$1$subexpression$2
              expr_like →  ● expr_like$macrocall$1
              expr_range$macrocall$5 →  ● expr_like
              expr_range$macrocall$1 →  ● expr_range$macrocall$5
              expr_range →  ● expr_range$macrocall$1
              expr_compare$macrocall$4 →  ● expr_range
              expr_compare$macrocall$1 →  ● expr_compare$macrocall$4
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A op_not_like token based on:
              ops_like_operators$subexpression$3 →  ● %op_not_like
              ops_like_operators →  ● ops_like_operators$subexpression$3
              ops_like →  ● ops_like_operators
              expr_like$macrocall$2 →  ● ops_like
              expr_like$macrocall$1 → expr_like$macrocall$1$subexpression$1 ● expr_like$macrocall$2 expr_like$macrocall$1$subexpression$2
              expr_like →  ● expr_like$macrocall$1
              expr_range$macrocall$5 →  ● expr_like
              expr_range$macrocall$1 →  ● expr_range$macrocall$5
              expr_range →  ● expr_range$macrocall$1
              expr_compare$macrocall$4 →  ● expr_range
              expr_compare$macrocall$1 →  ● expr_compare$macrocall$4
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A op_not_ilike token based on:
              ops_like_operators$subexpression$4 →  ● %op_not_ilike
              ops_like_operators →  ● ops_like_operators$subexpression$4
              ops_like →  ● ops_like_operators
              expr_like$macrocall$2 →  ● ops_like
              expr_like$macrocall$1 → expr_like$macrocall$1$subexpression$1 ● expr_like$macrocall$2 expr_like$macrocall$1$subexpression$2
              expr_like →  ● expr_like$macrocall$1
              expr_range$macrocall$5 →  ● expr_like
              expr_range$macrocall$1 →  ● expr_range$macrocall$5
              expr_range →  ● expr_range$macrocall$1
              expr_compare$macrocall$4 →  ● expr_range
              expr_compare$macrocall$1 →  ● expr_compare$macrocall$4
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A kw_like token based on:
              ops_like_keywors$subexpression$1 →  ● %kw_like
              ops_like_keywors → ops_like_keywors$ebnf$1 ● ops_like_keywors$subexpression$1
              ops_like →  ● ops_like_keywors
              expr_like$macrocall$2 →  ● ops_like
              expr_like$macrocall$1 → expr_like$macrocall$1$subexpression$1 ● expr_like$macrocall$2 expr_like$macrocall$1$subexpression$2
              expr_like →  ● expr_like$macrocall$1
              expr_range$macrocall$5 →  ● expr_like
              expr_range$macrocall$1 →  ● expr_range$macrocall$5
              expr_range →  ● expr_range$macrocall$1
              expr_compare$macrocall$4 →  ● expr_range
              expr_compare$macrocall$1 →  ● expr_compare$macrocall$4
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A kw_ilike token based on:
              ops_like_keywors$subexpression$1 →  ● %kw_ilike
              ops_like_keywors → ops_like_keywors$ebnf$1 ● ops_like_keywors$subexpression$1
              ops_like →  ● ops_like_keywors
              expr_like$macrocall$2 →  ● ops_like
              expr_like$macrocall$1 → expr_like$macrocall$1$subexpression$1 ● expr_like$macrocall$2 expr_like$macrocall$1$subexpression$2
              expr_like →  ● expr_like$macrocall$1
              expr_range$macrocall$5 →  ● expr_like
              expr_range$macrocall$1 →  ● expr_range$macrocall$5
              expr_range →  ● expr_range$macrocall$1
              expr_compare$macrocall$4 →  ● expr_range
              expr_compare$macrocall$1 →  ● expr_compare$macrocall$4
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A kw_not token based on:
              ops_between$ebnf$1 →  ● %kw_not
              ops_between →  ● ops_between$ebnf$1 kw_between
              expr_range$macrocall$2 →  ● ops_between
              expr_range$macrocall$1 → expr_range$macrocall$1$subexpression$1 ● expr_range$macrocall$2 expr_range$macrocall$1$subexpression$2 expr_range$macrocall$3 expr_range$macrocall$1$subexpression$3
              expr_range →  ● expr_range$macrocall$1
              expr_compare$macrocall$4 →  ● expr_range
              expr_compare$macrocall$1 →  ● expr_compare$macrocall$4
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A kw_is token based on:
              expr_is → expr_is$subexpression$5 ● %kw_is expr_is$ebnf$1 expr_is$subexpression$6
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A op_compare token based on:
              expr_compare$macrocall$2 →  ● %op_compare
              expr_compare$macrocall$1 → expr_compare$macrocall$1$subexpression$1 ● expr_compare$macrocall$2 expr_compare$macrocall$1$subexpression$2
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A kw_notnull token based on:
              expr_is$subexpression$4 →  ● %kw_notnull
              expr_is → expr_is$subexpression$3 ● expr_is$subexpression$4
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A kw_is token based on:
              expr_is$subexpression$4 →  ● %kw_is kw_not_null
              expr_is → expr_is$subexpression$3 ● expr_is$subexpression$4
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A kw_isnull token based on:
              expr_is$subexpression$2 →  ● %kw_isnull
              expr_is → expr_is$subexpression$1 ● expr_is$subexpression$2
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A kw_is token based on:
              expr_is$subexpression$2 →  ● %kw_is %kw_null
              expr_is → expr_is$subexpression$1 ● expr_is$subexpression$2
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A word token based on:
              kw_between →  ● %word
              ops_between → ops_between$ebnf$1 ● kw_between
              expr_range$macrocall$2 →  ● ops_between
              expr_range$macrocall$1 → expr_range$macrocall$1$subexpression$1 ● expr_range$macrocall$2 expr_range$macrocall$1$subexpression$2 expr_range$macrocall$3 expr_range$macrocall$1$subexpression$3
              expr_range →  ● expr_range$macrocall$1
              expr_compare$macrocall$4 →  ● expr_range
              expr_compare$macrocall$1 →  ● expr_compare$macrocall$4
              expr_compare →  ● expr_compare$macrocall$1
              expr_is →  ● expr_compare
              expr_eq$macrocall$4 →  ● expr_is
              expr_eq$macrocall$1 →  ● expr_eq$macrocall$4
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A op_eq token based on:
              expr_eq$macrocall$2$subexpression$1 →  ● %op_eq
              expr_eq$macrocall$2 →  ● expr_eq$macrocall$2$subexpression$1
              expr_eq$macrocall$1 → expr_eq$macrocall$1$subexpression$1 ● expr_eq$macrocall$2 expr_eq$macrocall$1$subexpression$2
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A op_neq token based on:
              expr_eq$macrocall$2$subexpression$1 →  ● %op_neq
              expr_eq$macrocall$2 →  ● expr_eq$macrocall$2$subexpression$1
              expr_eq$macrocall$1 → expr_eq$macrocall$1$subexpression$1 ● expr_eq$macrocall$2 expr_eq$macrocall$1$subexpression$2
              expr_eq →  ● expr_eq$macrocall$1
              expr_not$macrocall$4 →  ● expr_eq
              expr_not$macrocall$1 →  ● expr_not$macrocall$4
              expr_not →  ● expr_not$macrocall$1
              expr_and$macrocall$4 →  ● expr_not
              expr_and$macrocall$1 →  ● expr_and$macrocall$4
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A kw_and token based on:
              expr_and$macrocall$2 →  ● %kw_and
              expr_and$macrocall$1 → expr_and$macrocall$1$subexpression$1 ● expr_and$macrocall$2 expr_and$macrocall$1$subexpression$2
              expr_and →  ● expr_and$macrocall$1
              expr_or$macrocall$4 →  ● expr_and
              expr_or$macrocall$1 →  ● expr_or$macrocall$4
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A kw_or token based on:
              expr_or$macrocall$2 →  ● %kw_or
              expr_or$macrocall$1 → expr_or$macrocall$1$subexpression$1 ● expr_or$macrocall$2 expr_or$macrocall$1$subexpression$2
              expr_or →  ● expr_or$macrocall$1
              expr_nostar →  ● expr_or
              expr →  ● expr_nostar
              select_expr_list_item →  ● expr select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A kw_as token based on:
              ident_aliased$subexpression$1 →  ● %kw_as ident
              ident_aliased →  ● ident_aliased$subexpression$1
              select_expr_list_item$ebnf$1 →  ● ident_aliased
              select_expr_list_item → expr ● select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A word token based on:
              word →  ● %word
              ident →  ● word
              ident_aliased →  ● ident
              select_expr_list_item$ebnf$1 →  ● ident_aliased
              select_expr_list_item → expr ● select_expr_list_item$ebnf$1
              select_expr_list_aliased$ebnf$1$subexpression$1 → comma ● select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A comma token based on:
              comma →  ● %comma
              select_expr_list_aliased$ebnf$1$subexpression$1 →  ● comma select_expr_list_item
              select_expr_list_aliased$ebnf$1 → select_expr_list_aliased$ebnf$1 ● select_expr_list_aliased$ebnf$1$subexpression$1
              select_expr_list_aliased → select_expr_list_item ● select_expr_list_aliased$ebnf$1
              select_what → %kw_select ● select_expr_list_aliased
              select_statement →  ● select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A kw_from token based on:
              select_from →  ● %kw_from select_subject
              select_statement$ebnf$1 →  ● select_from
              select_statement → select_what ● select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A kw_where token based on:
              select_where →  ● %kw_where expr
              select_statement$ebnf$2 →  ● select_where
              select_statement → select_what select_statement$ebnf$1 ● select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A kw_group token based on:
              select_groupby →  ● %kw_group kw_by expr_list_raw
              select_statement$ebnf$3 →  ● select_groupby
              select_statement → select_what select_statement$ebnf$1 select_statement$ebnf$2 ● select_statement$ebnf$3 select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A kw_order token based on:
              select_order_by$subexpression$1 →  ● %kw_order kw_by
              select_order_by →  ● select_order_by$subexpression$1 select_order_by_expr select_order_by$ebnf$1
              select_statement$ebnf$4 →  ● select_order_by
              select_statement → select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 ● select_statement$ebnf$4 select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A kw_limit token based on:
              select_limit$ebnf$1$subexpression$1 →  ● %kw_limit int
              select_limit$ebnf$1 →  ● select_limit$ebnf$1$subexpression$1
              select_limit →  ● select_limit$ebnf$1 select_limit$ebnf$2 select_limit$ebnf$3
              select_statement → select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 ● select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A kw_offset token based on:
              select_limit$ebnf$2$subexpression$1 →  ● %kw_offset int select_limit$ebnf$2$subexpression$1$ebnf$1
              select_limit$ebnf$2 →  ● select_limit$ebnf$2$subexpression$1
              select_limit → select_limit$ebnf$1 ● select_limit$ebnf$2 select_limit$ebnf$3
              select_statement → select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 ● select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A kw_fetch token based on:
              select_limit$ebnf$3$subexpression$1 →  ● %kw_fetch select_limit$ebnf$3$subexpression$1$ebnf$1 int select_limit$ebnf$3$subexpression$1$ebnf$2
              select_limit$ebnf$3 →  ● select_limit$ebnf$3$subexpression$1
              select_limit → select_limit$ebnf$1 select_limit$ebnf$2 ● select_limit$ebnf$3
              select_statement → select_what select_statement$ebnf$1 select_statement$ebnf$2 select_statement$ebnf$3 select_statement$ebnf$4 ● select_limit
              statement →  ● select_statement
              main → main$ebnf$1 ● statement main$ebnf$2 main$ebnf$3
          A semicolon token based on:
              statement_separator →  ● %semicolon
              main$ebnf$3 → main$ebnf$3 ● statement_separator
              main → main$ebnf$1 statement main$ebnf$2 ● main$ebnf$3
    
              at Parser.feed (/home/bobby/phorm-new/node_modules/nearley/lib/nearley.js:343:27)
              at _parse (/home/bobby/phorm-new/node_modules/pgsql-ast-parser/src/parser.ts:43:12)
              at Object.parse (/home/bobby/phorm-new/node_modules/pgsql-ast-parser/src/parser.ts:24:18)
              at Object.parseSql (/home/bobby/phorm-new/node_modules/pg-mem/src/parse-cache.ts:25:15)
              at Query.parse (/home/bobby/phorm-new/node_modules/pg-mem/src/query.ts:80:16)
              at Query.queries (/home/bobby/phorm-new/node_modules/pg-mem/src/query.ts:88:31)
              at queries.next (<anonymous>)
              at Query.query (/home/bobby/phorm-new/node_modules/pg-mem/src/query.ts:67:20)
              at /home/bobby/phorm-new/node_modules/pg-mem/src/adapters.ts:81:80
              at Timeout.task [as _onTimeout] (/home/bobby/phorm-new/node_modules/jsdom/lib/jsdom/browser/Window.js:391:19)
              at listOnTimeout (internal/timers.js:554:17)
              at processTimers (internal/timers.js:497:7)
    

    I know this library does not have advanced function yet, but being able to roll extensions and column descriptions might be helpful; even if it completely ignores the type and uses string, and for descriptions it just ignores them.

    opened by MirrorBytes 11
  • Unexpected word token:

    Unexpected word token: "cascade"

    Describe the bug

    It seems that CASCADE is not implemented.

    Because of this, I'm unable to use the library with [email protected].

    💔 Your query failed to parse.
    
    This is most likely due to a SQL syntax error. However, you might also have hit a bug, or an unimplemented feature of pg-mem.
    If this is the case, please file an issue at https://github.com/oguimbal/pg-mem along with a query that reproduces this syntax error.
    
    👉 Failed query:
    
    CREATE TABLE "user" ("id" SERIAL NOT NULL, "name" text NOT NULL, PRIMARY KEY ("id"));
    DROP TABLE IF EXISTS "user" CASCADE;
    ;
    
    💀 Syntax error at line 2 col 29:
    
      DROP TABLE IF EXISTS "user" CASCADE
                                  ^
    Unexpected word token: "cascade". Instead, I was expecting to see one of the following:
    
        - A "dot" token
        - A "semicolon" token
    

    To Reproduce

    CREATE TABLE "user" ("id" SERIAL NOT NULL, "name" text NOT NULL, PRIMARY KEY ("id"));
    DROP TABLE IF EXISTS "user" CASCADE;
    

    check error on https://oguimbal.github.io/pg-mem-playground

    pg-mem version

    v2.3.3

    Additional notes

    • sequelize.sync options: { alter: { drop: false }, force: true }
    • the sequelize module is being used in my project via @nestjs/[email protected]
    opened by unicornware 10
  • Insert Statement Fails with no Useful Error

    Insert Statement Fails with no Useful Error

    I'm having a hard time troubleshooting this.

    While I can log any failed sql statements that pg-mem via inMemoryDb.on('query-failed', it doesn't tell me what the problem is exactly.

    This query was successfully migrated to my production database using flyway. This same kind of statement also ran ok in my 001 migration but just not my 003 for this community table insert which is really odd.

    Here's a screencast on this: https://youtu.be/yaWBzsUtJbE

    (note: I've replaced the real strings with x's for privacy for this post)

    INSERT INTO public.community (name,image_url,twitter_url,coordinates,meetup_url,main_site_url,slack_url,facebook_url,github_url,eventbrite_url,linkedin_url) VALUES ('xxxxxxxxxx','xxxxxxxxxxx',NULL,'(33.7676338,-84.6176515)','xxxxxxxxxx',NULL,NULL,NULL,NULL,NULL,NULL);
    

    Also tried

    INSERT INTO community VALUES ('Software Crafters - Atlanta','https://storage.googleapis.com/wedotdd-client-assets/assets/communities/assets_communities_software-crafters-atlanta.png',NULL,point(33.7676338,-84.6176515),'https://www.meetup.com/Software-Craftsmanship-Atlanta',NULL,NULL,NULL,NULL,NULL,NULL);
    

    Now the initial migration that creates the schema looks like this for my pg-mem 001 migration for the community table:

    CREATE TABLE community (
        community_id integer NOT NULL,
        name character varying NOT NULL,
        image_url character varying,
        twitter_url character varying,
        coordinates point,
        meetup_url character varying,
        main_site_url character varying,
        slack_url character varying,
        facebook_url character varying,
        github_url character varying,
        eventbrite_url character varying,
        linkedin_url character varying
    );
    
    ALTER TABLE community ALTER COLUMN community_id ADD GENERATED ALWAYS AS IDENTITY (
        SEQUENCE NAME community_community_id_seq
        START WITH 0
        INCREMENT BY 1
        MINVALUE 0
        NO MAXVALUE
        CACHE 1
    );
    

    The only thing to note in addition is that in my 001 migration related to community at the end of that script is:

    ALTER TABLE ONLY community_location ADD CONSTRAINT community_country_pkey PRIMARY KEY (community_id, location_id);
    ALTER TABLE ONLY community ADD CONSTRAINT community_pkey PRIMARY KEY (community_id);
    ALTER TABLE ONLY location ADD CONSTRAINT location_pkey PRIMARY KEY (location_id);
    ALTER TABLE ONLY skill_type ADD CONSTRAINT skill_type_pkey PRIMARY KEY (skill_type_id);
    ALTER TABLE ONLY skills ADD CONSTRAINT skills_pkey PRIMARY KEY (skill_id);
    ALTER TABLE ONLY location ADD CONSTRAINT city_id_fk FOREIGN KEY (city_id) REFERENCES city(city_id) MATCH FULL;
    ALTER TABLE ONLY community_location ADD CONSTRAINT community_id_fk FOREIGN KEY (community_id) REFERENCES community(community_id) MATCH FULL;
    ALTER TABLE ONLY location ADD CONSTRAINT country_id_fk FOREIGN KEY (country_id) REFERENCES country(country_id) MATCH FULL;
    ALTER TABLE ONLY community_location ADD CONSTRAINT location_id_fk FOREIGN KEY (location_id) REFERENCES location(location_id) MATCH FULL;
    ALTER TABLE ONLY location ADD CONSTRAINT state_id_fk FOREIGN KEY (state_id) REFERENCES state(state_id) MATCH FULL;
    

    If I disable those ALTER statements at then end then change the script to include the community_id, then this works (noice the ID 31):

    INSERT INTO community VALUES (31, 'xxxxx', 'xxxxx', NULL, '(-77.03059944399082,-12.045945732454783)', 'xxxxx', NULL, NULL, NULL, NULL, NULL, NULL);
    

    But..I should not have to disable those alter statements AND I shouldn't have to specify a community_id in my insert because I've turned on ADD GENERATED ALWAYS AS IDENTITY which will create the ID for me automatically.

    opened by dschinkel 10
  • "insert into select" support (todo: array-mode iteration error)

    This is code express-session appears to use. Support for this would certainly be nice :+1: although it seems a bit complicated. I'm not sure what the point of an inner SELECT query is here since it is not actually looking up values from elsewhere but just providing them directly, but somebody better versed in SQL might know why this is clever.

    Error: todo: array-mode iteration

    *️⃣ Failed SQL statement: INSERT INTO "express_server_sessions" (sess, expire, sid) SELECT '{"cookie":{"originalMaxAge":1296000000,"expires":"2021-01-29T15:49:27.925Z","secure":true,"httpOnly":true,"path":"/"},"passport":{"user":653646}}', to_timestamp(1611935368), 'jCUSxo0EnzcIeCQYUgt6g3FQCoIO6Q3S' ON CONFLICT (sid) DO UPDATE SET sess='{"cookie":{"originalMaxAge":1296000000,"expires":"2021-01-29T15:49:27.925Z","secure":true,"httpOnly":true,"path":"/"},"passport":{"user":653646}}', expire=to_timestamp(1611935368) RETURNING sid;
    

    PS: to run this code in the first place I had to work around the lack of to_timestamp:

    const pgMem = require('pg-mem');
    const mockDb = pgMem.newDb();
    
    
    mockDb.public.registerFunction({
      name: 'to_timestamp',
      args: [pgMem.DataType.integer],
      returns: pgMem.DataType.timestampz,
      implementation: input => {
        return new Date(input * 1000).toISOString();
      },
    });
    
    
    enhancement 
    opened by hallvors 8
  • `pg` adapter leaks symbols in rows

    `pg` adapter leaks symbols in rows

    Hello again, We noticed that rows being return from pg adapter queries include Symbol(_id). This is mostly aesthetic, but can be confusing. I'll be happy try a PR, do you have any pointers ? Best,

    // pg-mem/src/tests/pg.spec.ts
    
    it('does not leak symbol properties in rows', async () => {
        simpleDb();
        const { Client } = db.adapters.createPg();
        const client = new Client();
        await client.connect();
    
        many(`create table mytable (msg varchar);
            insert into mytable values ('hello'), ('hi');`);
    
        const got = await client.query('select * from mytable;');
    
        // fails
        expect(Object.getOwnPropertySymbols(got.rows[0]).length).to.be.equal(0);
    
        await client.end();
    });
    
    opened by gabssnake 7
  • fix: constrain sequelize < 6.20.0

    fix: constrain sequelize < 6.20.0

    Sequelize 6.20.0 breaks a test in pg-mem, so tighten the version constraint to require sequelize < 6.20.0.

    The test breakage is:

      727 passing (4s)
      25 pending
      1 failing
    
      1) Sequelize
           can perform sample with force sync:
         relation "table_constraints" does not exist
    
    🐜 This seems to be an execution error, which means that your request syntax seems okay,
        but the resulting statement cannot be executed → Probably not a pg-mem error.
    
    *️⃣ Failed SQL statement: SELECT DISTINCT tc.constraint_name as constraint_name, tc.constraint_schema as constraint_schema, tc.constraint_catalog as constraint_catalog, tc.table_name as table_name,tc.table_schema as table_schema,tc.table_catalog as table_catalog,tc.initially_deferred as initially_deferred,tc.is_deferrable as is_deferrable,kcu.column_name as column_name,ccu.table_schema  AS referenced_table_schema,ccu.table_catalog  AS referenced_table_catalog,ccu.table_name  AS referenced_table_name,ccu.column_name AS referenced_column_name FROM information_schema.table_constraints AS tc JOIN information_schema.key_column_usage AS kcu ON tc.constraint_name = kcu.constraint_name JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name WHERE constraint_type = 'FOREIGN KEY' AND tc.table_name = 'Users';
    
    👉 You can file an issue at https://github.com/oguimbal/pg-mem along with a way to reproduce this error (if you can), and  the stacktrace:
    
      Error:
          at Query.run (node_modules/sequelize/src/dialects/postgres/query.js:76:25)
          at /Users/gthb/git/pg-mem/node_modules/sequelize/src/sequelize.js:641:28
          at PostgresQueryInterface.getForeignKeyReferencesForTable (node_modules/sequelize/src/dialects/postgres/query-interface.js:161:20)
          at Sequelize.drop (node_modules/sequelize/src/sequelize.js:936:27)
          at Sequelize.sync (node_modules/sequelize/src/sequelize.js:798:7)
          at Object.sequelizeSample (samples/sequelize/sequelize.ts:32:5)
          at Context.<anonymous> (src/tests/sequelize-real.spec.ts:10:9)
    
    opened by gthb 6
  • Partial Indexes not working with unique index where column value is null

    Partial Indexes not working with unique index where column value is null

    I saw in this issue that support for Partial Indexes was added: https://github.com/oguimbal/pg-mem/issues/89

    However, if you insert null as a value for a column with a unique index, in actual postgres it works since null values are not considered in unique value validation, but pg-mem does appear to include them when validating uniques and prevents the 2nd row from inserting with a value of null.

    Example SQL for postgres (works as expected against an actual postgres engine)

    create table "test_table" (
      "id" character varying(36) NOT NULL, 
      "unique_data" character varying(36), 
      "deleted_at" timestamp without time zone,
      CONSTRAINT "PK_test_table_id"
      PRIMARY KEY ("id")  
    );
    
    CREATE UNIQUE INDEX "UXtest_table_unique_data" ON "public"."test_table" ("unique_data") WHERE deleted_at IS NULL;
    
    insert into test_table ("id", "unique_data", "deleted_at") VALUES('1', default, default );
    insert into test_table ("id", "unique_data", "deleted_at") VALUES('2', default, default );
    

    Example jest / nestjs / typeorm / pg-mem test (NOT WORKING but I'd expect it to)

    // "@nestjs/testing": "^8.0.0",
    import { Test, TestingModule } from '@nestjs/testing';
    // "@nestjs/typeorm": "^8.0.2",
    import { getRepositoryToken } from '@nestjs/typeorm';
    // "typeorm": "^0.2.37",
    import { Repository, Connection, Entity,
      Column,
      PrimaryColumn,
      Index,
      DeleteDateColumn, 
    } from 'typeorm';
    // "pg-mem": "^2.0.2",
    import { newDb } from 'pg-mem';
    
    @Index('UXtest_table_unique_data', ['uniqueData'], {
      unique: true,
      where: 'deleted_at IS NULL'
    })
    @Entity()
    export class TestEntity {
      @PrimaryColumn({ length: 36 })
      id: string;
    
      @Column({ length: 36, name: 'unique_data', nullable: true })
      uniqueData?: string;
    
      @DeleteDateColumn({
        name: 'deleted_at',
        type: 'timestamp without time zone',
        nullable: true,
      })
      deletedAt: Date;
    }
    
    describe('ExamplePartialUniqueProblemWithPgMem', () => {
      let testRepo: Repository<TestEntity>, connection: Connection;
    
      beforeEach(async () => {
        // create a postgres memory db
        const db = newDb({});
    
        // define current_database
        // work around typeorm calling 'current_database' function
        db.public.registerFunction({
          implementation: () => 'test',
          name: 'current_database',
        });
    
        // create a Typeorm connection
        connection = await db.adapters.createTypeormConnection({
          type: 'postgres',
          entities: [TestEntity],
        });
    
        // create tables
        await connection.synchronize();
        testRepo = connection.getRepository(TestEntity);
      });
    
      afterEach(async () => {
        await connection.close();
      });
    
      it('create 2 test entries will null for a unique column', async () => {
    
        await testRepo.save({
          id: '1',
        });
    
        await testRepo.save({
          id: '2',
        });
    
        // get id 2
        const record2 = await testRepo.findOne('2');
    
        expect(record2.id).toEqual('2');
      });
    });
    
    

    Running this test produces this output for me

    npm run test -- test.spec
    
    > [email protected] test
    > jest --testResultsProcessor=jest-junit "test.spec"
    
     FAIL  src/talent/test.spec.ts (8.483 s)
      ExamplePartialUniqueProblemWithPgMem
        ✕ create 2 test entries will null for a unique column (241 ms)
    
      ● ExamplePartialUniqueProblemWithPgMem › create 2 test entries will null for a unique column
    
        QueryFailedError: ERROR: insert into "test_entity" (id, unique_data, deleted_at) values ($1, $2, $3) returning "unique_data" - duplicate key value violates unique constraint "test_entity_pkey"
        DETAIL: Key (unique_data)=() already exists.
    
        🐜 This seems to be an execution error, which means that your request syntax seems okay,
        but the resulting statement cannot be executed → Probably not a pg-mem error.
    
        *️⃣ Failed SQL statement: INSERT INTO "test_entity"("id", "unique_data", "deleted_at") VALUES ('2', DEFAULT, DEFAULT) RETURNING "deleted_at";
    
        👉 You can file an issue at https://github.com/oguimbal/pg-mem along with a way to reproduce this error (if you can), and  the stacktrace:
    
          at QueryFailedError.TypeORMError [as constructor] (error/TypeORMError.ts:7:9)
          at new QueryFailedError (error/QueryFailedError.ts:9:9)
          at PostgresQueryRunner.<anonymous> (driver/postgres/PostgresQueryRunner.ts:258:19)
          at step (../node_modules/tslib/tslib.js:143:27)
          at Object.throw (../node_modules/tslib/tslib.js:124:57)
          at rejected (../node_modules/tslib/tslib.js:115:69)
    
    Test Suites: 1 failed, 1 total
    Tests:       1 failed, 1 total
    Snapshots:   0 total
    Time:        8.542 s, estimated 9 s
    Ran all test suites matching /test.spec/i.
    npm ERR! code ELIFECYCLE
    npm ERR! errno 1
    
    opened by jshanman 6
  • Column doesn't exist when creating table

    Column doesn't exist when creating table

    Basic info

    pg-mem version: 1.9.9 jest version: 27.0.4 typeorm version: 0.2.35

    Reproduction link: https://gist.github.com/Sven65/5b462e2d2d4ded3d8f89d4792bf4fd6b

    Issue

    When trying to create a table using pg-mem and typeorm entities, it fails as the column doesn't exist, with the following error message:

    QueryFailedError: column "userid" does not exist
    
        🐜 This seems to be an execution error, which means that your request syntax seems okay,
        but the resulting statement cannot be executed → Probably not a pg-mem error.
    
        *️⃣ Failed SQL statement: CREATE TABLE "userStats" ("userID" character varying(255) NOT NULL, CONSTRAINT "UQ_abb77da609fd701b7052a8b4531" UNIQUE ("userID"), CONSTRAINT "PK_abb77da609fd701b7052a8b4531" PRIMARY KEY ("userID"));
    

    Stacktrace

     at QueryFailedError.TypeORMError [as constructor] (src/error/TypeORMError.ts:7:9)
          at new QueryFailedError (src/error/QueryFailedError.ts:9:9)
          at PostgresQueryRunner.call (src/driver/postgres/PostgresQueryRunner.ts:258:19)
          at step (node_modules/typeorm/node_modules/tslib/tslib.js:143:27)
          at Object.throw (node_modules/typeorm/node_modules/tslib/tslib.js:124:57)
          at rejected (node_modules/typeorm/node_modules/tslib/tslib.js:115:51)
    
    opened by Sven65 6
  • Error: column

    Error: column "table.column" does not exist

    I had an error when try join table:

    `public async findByGtin(gtin: string): Promise<Option | null> {
           return this.repoInstance.findOne({
               include: [
                   {
                       model: Gtin,
                       // perform inner join instead of left outer join
                       required: true,
                       where: {
                           gtin: gtin,
                       },
                   },
               ],
           });
       }`
    
     data: { error: 'column "Option.id" does not exist', code: undefined },
            code: undefined,
            location: { start: 0, end: 0 },
            sql: `SELECT "Option".*, "gtins"."id" AS "gtins.id", "gtins"."createdAt" AS "gtins.createdAt", "gtins"."updatedAt" AS "gtins.updatedAt", "gtins"."gtin" AS "gtins.gtin", "gtins"."optionId" AS "gtins.optionId", "gtins"."priorityTier" AS "gtins.priorityTier", "gtins"."deadlineContentCreation" AS "gtins.deadlineContentCreation" FROM (SELECT "Option"."id", "Option"."createdAt", "Option"."updatedAt", "Option"."title", "Option"."rootGtin", "Option"."singleGtin", "Option"."manufacturerColor", "Option"."classification", "Option"."brand" FROM "Options" AS "Option" WHERE ( SELECT "optionId" FROM "Gtins" AS "gtins" WHERE ("gtins"."gtin" = '4009209123394' AND "gtins"."optionId" = "Option"."id") LIMIT 1 ) IS NOT NULL LIMIT 1) AS "Option" INNER JOIN "Gtins" AS "gtins" ON "Option"."id" = "gtins"."optionId" AND "gtins"."gtin" = '4009209123394';`,
            parameters: undefined,
            [Symbol(errorDetailsIncluded)]: true
          },
          original: ColumnNotFound [Error]: column "Option.id" does not exist
         
          🐜 This seems to be an execution error, which means that your request syntax seems okay,
              but the resulting statement cannot be executed → Probably not a pg-mem error.
         
          *️⃣ Failed SQL statement: SELECT "Option".*, "gtins"."id" AS "gtins.id", "gtins"."createdAt" AS "gtins.createdAt", "gtins"."updatedAt" AS "gtins.updatedAt", "gtins"."gtin" AS "gtins.gtin", "gtins"."optionId" AS "gtins.optionId", "gtins"."priorityTier" AS "gtins.priorityTier", "gtins"."deadlineContentCreation" AS "gtins.deadlineContentCreation" FROM (SELECT "Option"."id", "Option"."createdAt", "Option"."updatedAt", "Option"."title", "Option"."rootGtin", "Option"."singleGtin", "Option"."manufacturerColor", "Option"."classification", "Option"."brand" FROM "Options" AS "Option" WHERE ( SELECT "optionId" FROM "Gtins" AS "gtins" WHERE ("gtins"."gtin" = '4009209123394' AND "gtins"."optionId" = "Option"."id") LIMIT 1 ) IS NOT NULL LIMIT 1) AS "Option" INNER JOIN "Gtins" AS "gtins" ON "Option"."id" = "gtins"."optionId" AND "gtins"."gtin" = '4009209123394';;
         
          👉 You can file an issue at https://github.com/oguimbal/pg-mem along with a way to reproduce this error (if you can), and  the stacktrace:
    

    version

    pg-mem: 2.6.4 sequelize : 6.21.2 node : 16.17.0

    cat ./node_modules/pg-mem/package.json | grep version" => 2.6.4

    opened by maymayman 0
  • Bump decode-uri-component from 0.2.0 to 0.2.2

    Bump decode-uri-component from 0.2.0 to 0.2.2

    Bumps decode-uri-component from 0.2.0 to 0.2.2.

    Release notes

    Sourced from decode-uri-component's releases.

    v0.2.2

    • Prevent overwriting previously decoded tokens 980e0bf

    https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.1...v0.2.2

    v0.2.1

    • Switch to GitHub workflows 76abc93
    • Fix issue where decode throws - fixes #6 746ca5d
    • Update license (#1) 486d7e2
    • Tidelift tasks a650457
    • Meta tweaks 66e1c28

    https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.1

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • `Cannot read property '0' of undefined` for empty result with TypeORM `getOne`

    `Cannot read property '0' of undefined` for empty result with TypeORM `getOne`

    Describe the bug

    Ran into an error of QueryFailedError: TypeError: Cannot read property '0' of undefined when using TypeORM's getOne() with a query.

    It seems to me that the issue is that when there is no result from pg-mem for a query, undefined is returned, but it's still trying to access the first element, thus causing the error.

    My TypeORM version is 0.2.45, there's no issue when connecting to a postgres instance, so most likely it's a pg-mem issue.

    QueryFailedError: TypeError: Cannot read property '0' of undefined
    
        💥 This is a nasty error, which was unexpected by pg-mem. Also known "a bug" 😁 Please file an issue !
    
     👉 You can file an issue at https://github.com/oguimbal/pg-mem along with a way to reproduce this error (if you can), and  the stacktrace:
    
          at QueryFailedError.TypeORMError [as constructor] (src/error/TypeORMError.ts:7:9)
          at new QueryFailedError (src/error/QueryFailedError.ts:9:9)
          at PostgresQueryRunner.<anonymous> (src/driver/postgres/PostgresQueryRunner.ts:263:19)
          at step (node_modules/typeorm/node_modules/tslib/tslib.js:144:27)
          at Object.throw (node_modules/typeorm/node_modules/tslib/tslib.js:125:57)
          at rejected (node_modules/typeorm/node_modules/tslib/tslib.js:116:69)
    
    

    To Reproduce

    I guess this is related to how pg-mem interprets TypeORM's getOne(). Hopefully it's an easy and quick fix! If someone could point me to related code, I'm also happy to look into a fix.

    An example query would be something like

    return await getConnection()
                .getRepository(TestTable)
                .createQueryBuilder()
                .where('id IN (:...ids)', { ids })
                .orderBy('created_at', 'DESC')
                .getOne()
    

    pg-mem version

    2.6.3

    opened by jiayang26 0
  • Rollback doesn't works

    Rollback doesn't works

    Describe the bug

    I think if multiple insert queries is in transaction and transaction fail, all of it should't be in DB, but successful queries committed in DB. It looks like rollback doesn't work.

    To Reproduce

      private lectureInsertQuery = `INSERT INTO lectures
          (name, description, category, price, teacher_id, status, created_at, updated_at)
        VALUES
          ($1, $2, $3, $4, $5, $6, $7, $8)
        RETURNING *`;
    
      public async saveBulk(lectures: Lecture[]): Promise<Lecture[]> {
        const client = await this.pool.connect();
        let results: Lecture[];
    
        const insertLecture = async (lecture: Lecture) => {
          const { rows } = await client.query(
            this.lectureInsertQuery,
            lecture.toDB(),
          );
          return Lecture.fromDB(rows[0]);
        };
    
        try {
          await client.query('BEGIN');
          const insertResults = await lectures.reduce<Promise<Lecture[]>>(
            async (prev, lecture) => {
              let prevResult = await prev;
              const savedLecture = await insertLecture(lecture);
              return Promise.resolve([...prevResult, savedLecture]);
            },
            Promise.resolve([]),
          );
          await client.query('COMMIT');
          results = insertResults;
        } catch (e) {
          await client.query('ROLLBACK');
          throw e;
        } finally {
          client.release();
        }
    
        return results;
      }
    
      // test
         it('should rollback with duplicated lecture name', async () => {
            // given
            expect(await repository.findAll()).toHaveLength(3);
    
            const lecture1 = createLecture({
              name: 'test1',
              description: 'this lecture should rollback after save', // this successfully saved
            });
            const lecture2 = createLecture({
              name: 'test1',
              description: 'this lecture name is duplicate',
            });
            const lecture3 = createLecture({
              name: 'test3',
              description: 'this lecture should not be saved',
            });
    
            // when
            const actual = async () => {
              await repository.saveBulk([lecture1, lecture2, lecture3]);
            };
    
            // then
            await expect(actual).rejects.toThrow();
            await expect(repository.findAll()).resolves.toHaveLength(3); // it return 4
          });
    

    pg-mem version

    2.6.4

    opened by GrassHopper42 0
  • Typeorm synchronize error where table is named

    Typeorm synchronize error where table is named "record"

    Describe the bug

    I've run into an error when one of my table is named "record" and i have joins on it. I'm using [email protected], [email protected] and node v16.18.1

    query: 'ALTER TABLE "record" ADD CONSTRAINT "FK_8675cd3761984947c2506f39a25" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION',
    parameters: undefined,
    driverError: QueryError: "record" is not a table
    

    To Reproduce

    import { newDb } from "pg-mem";
    import { Entity, PrimaryGeneratedColumn, Connection, BaseEntity, OneToMany, ManyToOne } from "typeorm";
    
    @Entity()
    export class User extends BaseEntity {
      @PrimaryGeneratedColumn({ type: 'integer' })
      id!: number;
    
      @OneToMany(type => Record, record => record.user)
      records!: Record[];
    }
    
    
    @Entity()
    export class Record extends BaseEntity {
      @PrimaryGeneratedColumn({ type: 'integer' })
      id!: number;
    
      @ManyToOne(type => User, user => user.records)
      user!: User;
    }
    
    export async function typeormJoinsSample() {
    
      //==== create a memory db
      const db = newDb({
        // 👉 Recommended when using Typeorm .synchronize(), which creates foreign keys but not indices !
        autoCreateForeignKeyIndices: true,
      });
    
      db.public.registerFunction({ name: 'current_database', implementation: () => 'test'})
      db.public.registerFunction({ name: 'version', implementation: () => '1'})
    
    
      //==== create a Typeorm connection
      const got: Connection = await db.adapters.createTypeormConnection({
        type: 'postgres',
        entities: [User, Record]
      });
    
      try {
        await got.synchronize();
      } finally {
        // do not forget to close the connection once done...
        // ... typeorm stores connections in a static object,
        // and does not like opening 'default connections.
        await got.close();
      }
    }
    
    typeormJoinsSample()
    

    I've managed to bypass this error by renaming my "record" table

    @Entity({ name: 'Record' })
    export class Record extends BaseEntity {
    ...
    

    But i would like to keep it named "record"

    Edit: The following interceptor seems to handle properly the table named "record"

    db.public.interceptQueries((sql) => {
        if (sql.includes(`"record"`)) {
          // intercept this statement, and return something custom:
          return db.public.query(sql.replace(`"record"`, `public.record`)).rows;
        }
        // proceed to actual SQL execution for other requests.
        return null;
      });
    
    opened by KylianCadet 1
Owner
Olivier Guimbal
CTO @ https://justice.cool [email protected]
Olivier Guimbal
TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, MariaDB, PostgreSQL and SQLite databases.

TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, MariaDB, PostgreSQL and SQLite datab

MikroORM 5.4k Dec 31, 2022
An adapter-based ORM for Node.js with support for mysql, mongo, postgres, mssql (SQL Server), and more

Waterline is a next-generation storage and retrieval engine, and the default ORM used in the Sails framework. It provides a uniform API for accessing

Balderdash 5.4k Jan 4, 2023
Postgres SQL RCE.js

Postgres-SQLi-RCE.js PostgreSQL Large Objects and UDF (User Defined Functions) RCE exploit re-written in javascript, for easy chaining with XSS Methdo

Amit 1 Jan 20, 2022
Dead Simple Postgres Data Viewer and Query Runner

Dead Simple Postgres Data Viewer and Query Runner Environment Variables GITHUB_CLIENT_ID Github Client ID of the Oauth Application for protecting your

Mahesh C. Regmi 7 Aug 22, 2022
Simple CRUD application with Nestjs, Prisma and Docker with Postgres

A progressive Node.js framework for building efficient and scalable server-side applications. Description Nest framework TypeScript starter repository

Torr7s 5 Nov 6, 2022
A transparent, in-memory, streaming write-on-update JavaScript database for Small Web applications that persists to a JavaScript transaction log.

JavaScript Database (JSDB) A zero-dependency, transparent, in-memory, streaming write-on-update JavaScript database for the Small Web that persists to

Small Technology Foundation 237 Nov 13, 2022
Bluzelle is a smart, in-memory data store. It can be used as a cache or as a database.

SwarmDB ABOUT SWARMDB Bluzelle brings together the sharing economy and token economy. Bluzelle enables people to rent out their computer storage space

Bluzelle 225 Dec 31, 2022
In-memory Object Database

limeDB What is LimeDB LimeDB is object-oriented NoSQL database (OOD) system that can work with complex data objects that is, objects that mirror those

Luks 2 Aug 18, 2022
StashQL is a light-weight, open-source npm package that improves the speed of your GraphQL queries in your application.

Table of Contents What is StashQL? Install Getting Started Queries Mutations refillCache clearRelatedFields Logging The Team What is StashQL? StashQL

OSLabs Beta 67 Sep 30, 2022
Explore, create and deploy your SQLite databases right from your browser. Quick and easy, no installation required.

SQLighter (under development, alpha code) SQLighter is a database explorer born for SQLite that helps you design and deploy your application database

sqlighter 11 Sep 20, 2022
Execute one command (or mount one Node.js middleware) and get an instant high-performance GraphQL API for your PostgreSQL database!

PostGraphile Instant lightning-fast GraphQL API backed primarily by your PostgreSQL database. Highly customisable and extensible thanks to incredibly

Graphile 11.7k Jan 4, 2023
The ultimate solution for populating your MongoDB database.

Mongo Seeding The ultimate solution for populating your MongoDB database ?? Define MongoDB documents in JSON, JavaScript or even TypeScript files. Use

Paweł Kosiec 494 Dec 29, 2022
Create flexible REST endpoints and controllers from Sequelize models in your Express app

Finale Create flexible REST endpoints and controllers from Sequelize models in your Express or Restify app. This project aims to be a Sequelize 4.x an

Tom Juszczyk 181 Oct 18, 2022
Add hic et nunc data into your websites and Node.js scripts

hic et nunc API Guide Build websites and Node.js scripts with hic et nunc data hic et nunc is a decentralized NFT marketplace built on the Tezos block

Ian Petrarca 34 May 3, 2022
Small module that makes sure your catch, caught an actual error and not a programming mistake or assertion

safety-catch Small module that makes sure your catch, caught an actual error and not a programming mistake or assertion. npm install safety-catch Tri

Mathias Buus 31 May 4, 2022
A Gmail Clone which built with ReactJS and Redux. You can sign in with your Google Account, compose a new e-mail and send realtime emails to the project.

Gmail Clone with ReactJS A Gmail Clone that you can sign in with your Google Account, compose a new e-mail and send realtime emails to the project. Cl

Özge Coşkun Gürsucu 49 Nov 14, 2022
A way to Dockerize your Hardhat solidity contracts

How To Dockerize Your Hardhat Solidity Contract This is the final code from the article "How To Dockerize Your Hardhat Solidity Contract On Localhost"

manny 21 Dec 3, 2022
The Wholesome App. A project that allows you to upload images directly to MongoDB Atlas into your collection, a faster cloud database.

The Wholesome App. A project that allows you to upload images directly to MongoDB Atlas into your collection, a faster cloud database. To upload your cute and wholesome images.

Gourav Singh Rawat 2 Jul 17, 2022