Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
adelsz committed Jun 9, 2020
1 parent b7ee3ca commit 3ae2fbc
Show file tree
Hide file tree
Showing 19 changed files with 1,944 additions and 296 deletions.
6 changes: 3 additions & 3 deletions packages/cli/src/generator.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as queryModule from '@pgtyped/query';
import { parseSQLFile } from '@pgtyped/query';
import { parseSQLFile, parseTypeScriptFile } from "@pgtyped/query";
import { IQueryTypes } from '@pgtyped/query/lib/actions';
import { generateInterface, queryToTypeDeclarations } from './generator';
import { ProcessingMode } from './index';
Expand All @@ -13,8 +13,8 @@ function parsedQuery(
queryString: string,
): Parameters<typeof queryToTypeDeclarations>[0] {
return mode === ProcessingMode.SQL
? { mode, ast: parseSQLFile(queryString).parseTree.queries[0] }
: { mode, name, body: queryString };
? { mode, ast: parseSQLFile(queryString).queries[0] }
: { mode, ast: parseTypeScriptFile(queryString).queries[0] }
}

describe('query-to-interface translation', () => {
Expand Down
104 changes: 56 additions & 48 deletions packages/cli/src/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import {
parseSQLFile,
parseTypeScriptFile,
prettyPrintEvents,
processQueryAST,
processQueryString,
QueryAST,
} from '@pgtyped/query';
processTSQueryAST, processSQLQueryAST,
SQLQueryAST,
TSQueryAST,
} from "@pgtyped/query";
import { camelCase } from 'camel-case';
import { pascalCase } from 'pascal-case';
import { ProcessingMode } from './index';
Expand Down Expand Up @@ -35,12 +35,11 @@ export const generateTypeAlias = (typeName: string, alias: string) =>

type ParsedQuery =
| {
name: string;
body: string;
mode: ProcessingMode.TS;
ast: TSQueryAST;
mode: ProcessingMode.TS;
}
| {
ast: QueryAST;
ast: SQLQueryAST;
mode: ProcessingMode.SQL;
};

Expand All @@ -52,11 +51,11 @@ export async function queryToTypeDeclarations(
let queryData;
let queryName;
if (parsedQuery.mode === ProcessingMode.TS) {
queryName = parsedQuery.name;
queryData = processQueryString(parsedQuery.body);
queryName = parsedQuery.ast.name;
queryData = processTSQueryAST(parsedQuery.ast);
} else {
queryName = parsedQuery.ast.name;
queryData = processQueryAST(parsedQuery.ast);
queryData = processSQLQueryAST(parsedQuery.ast);
}

const typeData = await getTypes(queryData, queryName, connection);
Expand Down Expand Up @@ -158,11 +157,20 @@ export async function queryToTypeDeclarations(
);
}

interface ITypedQuery {
type ITypedQuery = {
mode: 'ts';
fileName: string;
query: {
name: string;
ast: TSQueryAST;
};
typeDeclaration: string;
} | {
mode: 'sql';
fileName: string;
query?: {
query: {
name: string;
ast: QueryAST;
ast: SQLQueryAST;
paramTypeAlias: string;
returnTypeAlias: string;
};
Expand All @@ -177,55 +185,55 @@ async function generateTypedecsFromFile(
types: TypeAllocator = new TypeAllocator(DefaultTypeMapping),
): Promise<ITypedQuery[]> {
const results: ITypedQuery[] = [];
if (mode === 'ts') {
const queries = parseTypeScriptFile(contents, fileName);
for (const query of queries) {

const { queries, events } = mode === 'ts' ? parseTypeScriptFile(contents, fileName) : parseSQLFile(contents, fileName);
if (events.length > 0) {
prettyPrintEvents(contents, events);
if (events.find((e) => 'critical' in e)) {
return results;
}
}
for (const queryAST of queries) {
let typedQuery: ITypedQuery;
if (mode === 'sql') {
const sqlQueryAST = queryAST as SQLQueryAST;
const result = await queryToTypeDeclarations(
{
body: query.tagContent,
name: query.queryName,
mode: ProcessingMode.TS,
},
{ ast: sqlQueryAST, mode: ProcessingMode.SQL },
connection,
types,
);
const typedQuery = {
typedQuery = {
mode: 'sql' as const,
query: {
name: camelCase(sqlQueryAST.name),
ast: sqlQueryAST,
paramTypeAlias: `I${pascalCase(sqlQueryAST.name)}Params`,
returnTypeAlias: `I${pascalCase(sqlQueryAST.name)}Result`,
},
fileName,
queryName: query.queryName,
typeDeclaration: result,
};
results.push(typedQuery);
}
} else {
const {
parseTree: { queries },
events,
} = parseSQLFile(contents, fileName);
if (events.length > 0) {
prettyPrintEvents(contents, events);
if (events.find((e) => 'critical' in e)) {
return results;
}
}
for (const query of queries) {
} else {
const tsQueryAST = queryAST as TSQueryAST;
const result = await queryToTypeDeclarations(
{ ast: query, mode: ProcessingMode.SQL },
{
ast: tsQueryAST,
mode: ProcessingMode.TS,
},
connection,
types,
);
const typedQuery = {
typedQuery = {
mode: 'ts' as const,
fileName,
query: {
name: camelCase(query.name),
ast: query,
paramTypeAlias: `I${pascalCase(query.name)}Params`,
returnTypeAlias: `I${pascalCase(query.name)}Result`,
name: tsQueryAST.name,
ast: tsQueryAST,
},
fileName,
queryName: query.name,
typeDeclaration: result,
};
results.push(typedQuery);
}
results.push(typedQuery);
}
return results;
}
Expand Down Expand Up @@ -253,7 +261,7 @@ export async function generateDeclarationFile(
declarationFileContents += '\n';
for (const typeDec of typeDecs) {
declarationFileContents += typeDec.typeDeclaration;
if (!typeDec.query) {
if (typeDec.mode === 'ts') {
continue;
}
const queryPP = typeDec.query.ast.statement.body
Expand Down
3 changes: 2 additions & 1 deletion packages/query/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"build": "tsc --declaration",
"check": "tsc --noEmit",
"watch": "tsc --declaration --watch --preserveWatchOutput",
"parsegen": "antlr4ts -visitor -Xexact-output-dir -o src/loader/sql/parser src/loader/sql/grammar/*.g4"
"parsegen-sql": "antlr4ts -visitor -Xexact-output-dir -o src/loader/sql/parser src/loader/sql/grammar/*.g4",
"parsegen-ts": "antlr4ts -visitor -Xexact-output-dir -o src/loader/typescript/parser src/loader/typescript/grammar/*.g4"
},
"jest": {
"roots": [
Expand Down
8 changes: 4 additions & 4 deletions packages/query/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ export {
ParamTransform,
IQueryParameters,
IInterpolatedQuery,
processQueryAST,
processQueryString,
processSQLQueryAST,
processTSQueryAST,
} from './preprocessor';

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

export { default as parseTypeScriptFile } from './loader/typescript';
export { default as parseTypeScriptFile, TSQueryAST } from './loader/typescript';

export {
default as parseSQLFile,
Query as QueryAST,
SQLQueryAST,
prettyPrintEvents,
} from './loader/sql';

Expand Down
17 changes: 0 additions & 17 deletions packages/query/src/loader/sql/grammar/SQLParser.g4
Original file line number Diff line number Diff line change
@@ -1,20 +1,3 @@
/*
-- @name GetAllUsers
-- @param userNames -> (...)
-- @param user -> (name,age)
-- @param users -> ((name,age)...)
select * from $userNames;
select * from $books $filterById;
*/


/*
@name GetAllUsers
@param userNames -> (...)
@param user -> (name,age)
@param users -> ((name,age)...)
*/

parser grammar SQLParser;

options { tokenVocab = SQLLexer; }
Expand Down
7 changes: 5 additions & 2 deletions packages/query/src/loader/sql/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,10 +212,12 @@ class ParseListener implements SQLParserListener {
}
}

export type SQLParseResult = { queries: Query[]; events: ParseEvent[] };

function parseText(
text: string,
fileName: string = 'undefined.sql',
): { parseTree: ParseTree; events: ParseEvent[] } {
): SQLParseResult {
const logger = new Logger(text);
const inputStream = CharStreams.fromString(text);
const lexer = new SQLLexer(inputStream);
Expand All @@ -231,10 +233,11 @@ function parseText(
const listener = new ParseListener(logger);
ParseTreeWalker.DEFAULT.walk(listener as SQLParserListener, tree);
return {
parseTree: listener.parseTree,
queries: listener.parseTree.queries,
events: logger.parseEvents,
};
}

export { prettyPrintEvents } from './logger';
export type SQLQueryAST = Query;
export default parseText;
115 changes: 115 additions & 0 deletions packages/query/src/loader/typescript/__snapshots__/query.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`array param 1`] = `
Object {
"events": Array [],
"query": Object {
"params": Array [
Object {
"location": Object {
"a": 34,
"b": 36,
"col": 34,
"line": 1,
},
"name": "ids",
"selection": Object {
"type": "scalar_array",
},
},
],
"text": "select * from users where id in $$ids",
},
}
`;

exports[`array spread param 1`] = `
Object {
"events": Array [],
"query": Object {
"params": Array [
Object {
"location": Object {
"a": 72,
"b": 80,
"col": 11,
"line": 2,
},
"name": "customers",
"selection": Object {
"keys": Array [
"customerName",
"contactName",
"address",
],
"type": "object_array",
},
},
],
"text": "INSERT INTO customers (customer_name, contact_name, address)
VALUES $$customers(customerName, contactName, address)",
},
}
`;

exports[`pick param 1`] = `
Object {
"events": Array [],
"query": Object {
"params": Array [
Object {
"location": Object {
"a": 33,
"b": 43,
"col": 33,
"line": 1,
},
"name": "activeUsers",
"selection": Object {
"keys": Array [
"userOne",
"userTwo",
],
"type": "object",
},
},
],
"text": "select * from users where id in $activeUsers(userOne, userTwo)",
},
}
`;

exports[`scalar param 1`] = `
Object {
"events": Array [],
"query": Object {
"params": Array [
Object {
"location": Object {
"a": 32,
"b": 33,
"col": 32,
"line": 1,
},
"name": "id",
"selection": Object {
"type": "scalar",
},
},
Object {
"location": Object {
"a": 47,
"b": 51,
"col": 47,
"line": 1,
},
"name": "title",
"selection": Object {
"type": "scalar",
},
},
],
"text": "select * from users where id = $id and title= $title",
},
}
`;
Loading

0 comments on commit 3ae2fbc

Please sign in to comment.