Skip to content

Commit

Permalink
Better ts parser (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
adelsz committed Jun 22, 2020
1 parent 3ae2fbc commit be9a351
Show file tree
Hide file tree
Showing 10 changed files with 755 additions and 457 deletions.
8 changes: 4 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ node_modules/*
.idea/

# Ignore build files
*.js
*.d.ts
*.js.map
packages/**/*.js
packages/**/*.d.ts
packages/**/*.js.map
*.java
*.interp
*.tokens
*.log

.vercel
.vercel
5 changes: 3 additions & 2 deletions packages/query/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ export {
ParamTransform,
IQueryParameters,
IInterpolatedQuery,
processSQLQueryAST,
processTSQueryAST,
} from './preprocessor';

export { processTSQueryAST } from './preprocessor-ts';
export { processSQLQueryAST } from './preprocessor-sql';

export { AsyncQueue } from '@pgtyped/wire';

export { default as parseTypeScriptFile, TSQueryAST } from './loader/typescript';
Expand Down
2 changes: 2 additions & 0 deletions packages/query/src/loader/typescript/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import ts from 'typescript';
import parseQuery, { Query } from "./query";
import { ParseEvent } from "../sql/logger";

export const parseTSQuery = parseQuery;

export type TSQueryAST = Query;

interface INode {
Expand Down
17 changes: 9 additions & 8 deletions packages/query/src/loader/typescript/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { CharStreams, CommonTokenStream } from 'antlr4ts';
import { ParseTreeWalker } from 'antlr4ts/tree/ParseTreeWalker';
import { QueryLexer } from './parser/QueryLexer';
import {
ParamContext,
ParamNameContext, PickKeyContext, QueryContext,
QueryParser
} from "./parser/QueryParser";
Expand Down Expand Up @@ -98,20 +99,20 @@ class ParseListener implements QueryParserListener {
}

enterParamName(ctx: ParamNameContext) {
const defLoc = {
a: ctx.start.startIndex,
b: ctx.start.stopIndex,
line: ctx.start.line,
col: ctx.start.charPositionInLine,
};
this.currentParam = {
name: ctx.text,
location: defLoc,
selection: undefined,
};
}

exitParam() {
exitParam(ctx: ParamContext) {
const defLoc = {
a: ctx.start.startIndex,
b: ctx.stop!.stopIndex,
line: ctx.start.line,
col: ctx.start.charPositionInLine,
};
this.currentParam.location = defLoc;
this.currentParam.selection = this.currentSelection as ParamSelection;
this.query.params!.push(this.currentParam as Param);
this.currentSelection = {};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,235 +1,6 @@
import {
ParamTransform,
processSQLQueryAST,
processTSQueryAST,
} from './preprocessor';
import parseSQLQuery from './loader/sql';
import parseTSQuery from './loader/typescript';

test('(TS) name parameter interpolation', () => {
const query = 'SELECT id, name from users where id = $id and age > $age';
const parsedQuery = parseTSQuery(query);
const parameters = {
id: '123',
age: 12,
};

const expectedResult = {
query: 'SELECT id, name from users where id = $1 and age > $2',
mapping: [],
bindings: ['123', 12],
};

const result = processTSQueryAST(parsedQuery.queries[0], parameters);

expect(result).toEqual(expectedResult);
});

test('(TS) scalar param used twice', () => {
const query = 'SELECT id, name from users where id = $id and parent_id = $id';
const parsedQuery = parseTSQuery(query);
const parameters = {
id: '123',
};

const expectedResult = {
query: 'SELECT id, name from users where id = $1 and parent_id = $1',
mapping: [],
bindings: ['123'],
};

const result = processTSQueryAST(parsedQuery.queries[0], parameters);

expect(result).toEqual(expectedResult);
});

test('(TS) name parameter mapping', () => {
const query = 'SELECT id, name from users where id = $id and age > $age';
const parsedQuery = parseTSQuery(query);

const expectedResult = {
query: 'SELECT id, name from users where id = $1 and age > $2',
mapping: [
{
assignedIndex: 1,
name: 'id',
type: ParamTransform.Scalar,
},
{
assignedIndex: 2,
name: 'age',
type: ParamTransform.Scalar,
},
],
bindings: [],
};

const result = processTSQueryAST(parsedQuery.queries[0]);

expect(result).toEqual(expectedResult);
});

test('(TS) single value list parameter interpolation', () => {
const query =
'INSERT INTO users (name, age) VALUES $user(name, age) RETURNING id';
const parsedQuery = parseTSQuery(query);

const parameters = {
user: {
name: 'Bob',
age: 12,
},
};

const expectedResult = {
query: 'INSERT INTO users (name, age) VALUES ($1, $2) RETURNING id',
mapping: [
{
name: 'user',
type: ParamTransform.Pick,
dict: {
name: {
assignedIndex: 1,
name: 'name',
type: ParamTransform.Scalar,
},
age: {
assignedIndex: 2,
name: 'age',
type: ParamTransform.Scalar,
},
},
},
],
bindings: [],
};

const result = processTSQueryAST(parsedQuery.queries[0]);

expect(result).toEqual(expectedResult);
});

test('(TS) multiple value list (array) parameter mapping', () => {
const query =
'SELECT FROM users where (age in $$ages) or (age in $$otherAges)';
const parsedQuery = parseTSQuery(query);

const expectedResult = {
query: 'SELECT FROM users where (age in ($1)) or (age in ($2))',
mapping: [
{
name: 'ages',
type: ParamTransform.Spread,
assignedIndex: 1,
},
{
name: 'otherAges',
type: ParamTransform.Spread,
assignedIndex: 2,
},
],
bindings: [],
};

const result = processTSQueryAST(parsedQuery.queries[0]);

expect(result).toEqual(expectedResult);
});

test('(TS) multiple value list (array) parameter interpolation', () => {
const query = 'SELECT FROM users where age in $$ages';
const parsedQuery = parseTSQuery(query);

const parameters = {
ages: [23, 27, 50],
};

const expectedResult = {
query: 'SELECT FROM users where age in ($1, $2, $3)',
bindings: [23, 27, 50],
mapping: [],
};

const result = processTSQueryAST(parsedQuery.queries[0], parameters);

expect(result).toEqual(expectedResult);
});

test('(TS) multiple value list (array) parameter used twice interpolation', () => {
const query = 'SELECT FROM users where age in $$ages or age in $$ages';
const parsedQuery = parseTSQuery(query);

const parameters = {
ages: [23, 27, 50],
};

const expectedResult = {
query: 'SELECT FROM users where age in ($1, $2, $3) or age in ($4, $5, $6)',
bindings: [23, 27, 50, 23, 27, 50],
mapping: [],
};

const result = processTSQueryAST(parsedQuery.queries[0], parameters);

expect(result).toEqual(expectedResult);
});

test('(TS) multiple value list parameter mapping', () => {
const query =
'INSERT INTO users (name, age) VALUES $$users(name, age) RETURNING id';
const parsedQuery = parseTSQuery(query);

const expectedResult = {
query: 'INSERT INTO users (name, age) VALUES ($1, $2) RETURNING id',
bindings: [],
mapping: [
{
name: 'users',
type: ParamTransform.PickSpread,
dict: {
name: {
name: 'name',
type: ParamTransform.Scalar,
assignedIndex: 1,
},
age: {
name: 'age',
type: ParamTransform.Scalar,
assignedIndex: 2,
},
},
},
],
};

const result = processTSQueryAST(parsedQuery.queries[0]);

expect(result).toEqual(expectedResult);
});

test('(TS) multiple value list parameter interpolation', () => {
const query =
'INSERT INTO users (name, age) VALUES $$users(name, age) RETURNING id';
const parsedQuery = parseTSQuery(query);

const parameters = {
users: [
{ name: 'Bob', age: 12 },
{ name: 'Tom', age: 22 },
],
};

const expectedResult = {
query:
'INSERT INTO users (name, age) VALUES ($1, $2), ($3, $4) RETURNING id',
bindings: ['Bob', 12, 'Tom', 22],
mapping: [],
};

const result = processTSQueryAST(parsedQuery.queries[0], parameters);

expect(result).toEqual(expectedResult);
});
import parseSQLQuery from "./loader/sql";
import { processSQLQueryAST } from "./preprocessor-sql";
import { ParamTransform } from "./preprocessor";

test('(SQL) no params', () => {
const query = `
Expand Down
Loading

0 comments on commit be9a351

Please sign in to comment.