Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create PostgreSQL parser #327

Merged
merged 51 commits into from
Nov 9, 2024
Merged
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
32e60f7
Create PostgreSQL parser
loicknuchel Oct 17, 2024
4334c50
tmp
loicknuchel Oct 17, 2024
9cbf10d
Merge branch 'main' into sql-parser
loicknuchel Oct 17, 2024
838cf47
Add function in expressions
loicknuchel Oct 18, 2024
7936931
Add COMMENT statement
loicknuchel Oct 18, 2024
4cbcd39
Add create extension statement
loicknuchel Oct 18, 2024
5cc6cf5
Add create type statement
loicknuchel Oct 18, 2024
cb16d1c
Improve column type parsing
loicknuchel Oct 18, 2024
1352a19
Add expression cast
loicknuchel Oct 18, 2024
b925fde
Small fixes
loicknuchel Oct 18, 2024
05c20bc
Add Alter Table
loicknuchel Oct 18, 2024
89c1240
Add Create Index
loicknuchel Oct 18, 2024
68d52b3
Add Insert Into
loicknuchel Oct 18, 2024
8151d82
Improve Create Type
loicknuchel Oct 18, 2024
af96cf8
Improve expressions
loicknuchel Oct 19, 2024
62a2600
Add operation precedence in expressions
loicknuchel Oct 19, 2024
1682f93
Add IN operator and escaped string
loicknuchel Oct 19, 2024
1ec2092
Add Create View
loicknuchel Oct 19, 2024
ca5a2ea
Improve Select Statement
loicknuchel Oct 20, 2024
b3a7ea9
Add Delete Statement
loicknuchel Oct 20, 2024
ad59690
Refactor pg ast
loicknuchel Oct 21, 2024
a78ddc8
Allow union in select
loicknuchel Oct 21, 2024
43ca175
Add unary expressions
loicknuchel Oct 21, 2024
43faa10
Add Update Statement
loicknuchel Oct 21, 2024
fc47152
Merge branch 'main' into sql-parser
loicknuchel Oct 23, 2024
62fa858
Add Begin and Commit statements
loicknuchel Oct 23, 2024
64d372f
Add on conflict on insert
loicknuchel Oct 23, 2024
0f2cae6
Some fixes
loicknuchel Oct 23, 2024
7a62430
Add Select distinct, filter and over
loicknuchel Oct 23, 2024
b51e147
Add Create Materialized View
loicknuchel Oct 27, 2024
620b3dc
Add Create/Alter Sequence
loicknuchel Oct 27, 2024
9b65da6
tmp: Add Create Funtion statement
loicknuchel Oct 28, 2024
7e7f980
Merge branch 'main' into sql-parser
loicknuchel Oct 28, 2024
8f8de08
Bootstrap PostgreSQL Ast to Database
loicknuchel Oct 28, 2024
bc253b5
Extract entities from Select
loicknuchel Oct 29, 2024
ab78db8
Build Index & Comment statements
loicknuchel Oct 29, 2024
4b5fd3f
Build Type & Alter table
loicknuchel Oct 29, 2024
4bef4e1
Small refacto
loicknuchel Oct 29, 2024
1c5af3f
Add extra in pg database
loicknuchel Oct 30, 2024
f868c8d
Add Create/Alter Schema
loicknuchel Oct 30, 2024
daf8532
Add Create Function statement
loicknuchel Oct 30, 2024
53b06c9
Add alter column
loicknuchel Oct 30, 2024
8b0bd91
code review
loicknuchel Oct 30, 2024
a339635
tmp
loicknuchel Nov 5, 2024
4fb1a5b
Merge branch 'main' into sql-parser
loicknuchel Nov 8, 2024
05927bb
Allow or replace in create function
loicknuchel Nov 8, 2024
9dc8e7e
Add ARRAY in expressions
loicknuchel Nov 8, 2024
d8e8ac0
Add CreateTrigger statement
loicknuchel Nov 9, 2024
56da7c6
Refactor SQL AST
loicknuchel Nov 9, 2024
9bb3a4a
Add change table owner
loicknuchel Nov 9, 2024
2243b86
Publish lib
loicknuchel Nov 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/lib/azimutt.ex
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ defmodule Azimutt do
%{id: "aml", name: "AML", parse: true, generate: true},
%{id: "dbml", name: "DBML", parse: false, generate: false},
%{id: "json", name: "JSON", parse: true, generate: true},
%{id: "postgres", name: "PostgreSQL", parse: false, generate: true},
%{id: "postgres", name: "PostgreSQL", parse: true, generate: true},
%{id: "mysql", name: "MySQL", parse: false, generate: false},
%{id: "oracle", name: "Oracle", parse: false, generate: false},
%{id: "sqlserver", name: "SQL Server", parse: false, generate: false},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
if (lang === 'aml') return aml.parseAml(content)
if (lang === 'amlv1') return aml.parseAml(content).mapError(errs => errs.filter(e => e.kind !== 'LegacySyntax'))
if (lang === 'json') return aml.parseJsonDatabase(content)
if (lang === 'postgres') return sql.parseSql(content, 'postgres')
loicknuchel marked this conversation as resolved.
Show resolved Hide resolved
return {errors: [{message: 'Unsupported source dialect: ' + lang, kind: 'UnsupportedDialect', level: 'error', offset: {start: 0, end: 100}, position: {start: {line: 1, column: 1}, end: {line: 10, column: 10}}}]}
} catch (e) {
return {errors: [{message: 'Failed to parse ' + lang + (e && e.message ? ': ' + e.message : ''), kind: 'DialectError', level: 'error', offset: {start: 0, end: 100}, position: {start: {line: 1, column: 1}, end: {line: 10, column: 10}}}]}
Expand Down
2 changes: 1 addition & 1 deletion libs/aml/resources/full.aml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ type slug | anonymous type
type uid int {tags: [generic]} # alias type
type cms.post_status (draft, published, archived) # enum type
type position {x int, y int} # struct type
type box `(INTERNALLENGTH = 16, INPUT = lower, OUTPUT = lower)` # custom type
type box `(INPUT = lower, OUTPUT = lower, INTERNALLENGTH = 16)` # custom type

namespace social.

Expand Down
2 changes: 1 addition & 1 deletion libs/aml/resources/full.json
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@
{"name": "uid", "alias": "int", "extra": {"line": 79, "statement": 15, "tags": ["generic"], "comment": "alias type"}},
{"schema": "cms", "name": "post_status", "values": ["draft", "published", "archived"], "extra": {"line": 80, "statement": 16, "comment": "enum type"}},
{"name": "position", "attrs": [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}], "extra": {"line": 81, "statement": 17, "comment": "struct type"}},
{"name": "box", "definition": "(INTERNALLENGTH = 16, INPUT = lower, OUTPUT = lower)", "extra": {"line": 82, "statement": 18, "comment": "custom type"}}
{"name": "box", "definition": "(INPUT = lower, OUTPUT = lower, INTERNALLENGTH = 16)", "extra": {"line": 82, "statement": 18, "comment": "custom type"}}
],
"extra": {
"comments": [{"line": 1, "comment": ""}, {"line": 2, "comment": "Full Schema AML"}, {"line": 3, "comment": ""}],
Expand Down
2 changes: 1 addition & 1 deletion libs/aml/resources/full.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ STRUCT:

### box

EXPRESSION: (INTERNALLENGTH = 16, INPUT = lower, OUTPUT = lower)
EXPRESSION: (INPUT = lower, OUTPUT = lower, INTERNALLENGTH = 16)

## Diagram

Expand Down
2 changes: 1 addition & 1 deletion libs/aml/src/amlParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ function tokenPosition(token: IToken): TokenPosition {
}

function pos(value: number | undefined): number {
return value !== undefined && !isNaN(value) ? value : defaultPos
return value !== undefined && !Number.isNaN(value) ? value : defaultPos
}

// utils functions
Expand Down
6 changes: 3 additions & 3 deletions libs/models/src/parserResult.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export const tokenPosition = (offsetStart: number, offsetEnd: number, positionSt
({offset: {start: offsetStart, end: offsetEnd}, position: {start: {line: positionStartLine, column: positionStartColumn}, end: {line: positionEndLine, column: positionEndColumn}}})

export const mergePositions = (positions: (TokenPosition | undefined)[]): TokenPosition => {
const pos: TokenPosition[] = positions.filter(isNotUndefined)
const pos: TokenPosition[] = positions.filter(isNotUndefined).filter(p => !!p.offset)
return ({
offset: {start: posStart(pos.map(p => p.offset.start)), end: posEnd(pos.map(p => p.offset.end))},
position: {
Expand All @@ -84,11 +84,11 @@ export const positionEndAdd = <T extends TokenPosition>(pos: T, value: number):
})

const posStart = (values: number[]): number => {
const valid = values.filter(n => n >= 0 && !isNaN(n) && isFinite(n))
const valid = values.filter(n => n >= 0 && !Number.isNaN(n) && Number.isFinite(n))
return valid.length > 0 ? Math.min(...valid) : 0
}

const posEnd = (values: number[]): number => {
const valid = values.filter(n => n >= 0 && !isNaN(n) && isFinite(n))
const valid = values.filter(n => n >= 0 && !Number.isNaN(n) && Number.isFinite(n))
return valid.length > 0 ? Math.max(...valid) : 0
}
28 changes: 28 additions & 0 deletions libs/parser-sql/resources/complex.postgres.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
--
-- A file with several statements more or less complex to check the parser is works fine.
-- They don't make sense for a particular db ^^
--

/*
* first query
* Author: Loïc
*/
select id /* primary key */, name
from users -- table
where role = 'admin';

DROP TABLE IF EXISTS users, public.posts CASCADE;

CREATE TABLE users (
id int PRIMARY KEY,
first_name varchar NOT NULL,
last_name varchar NOT NULL,
CONSTRAINT name_uniq UNIQUE (first_name, last_name),
email varchar UNIQUE CHECK ( email LIKE '%@%' ),
role varchar DEFAULT 'guest'
);

CREATE TABLE public.posts (
id int PRIMARY KEY,
author int CONSTRAINT posts_author_fk REFERENCES users(id)
);
2 changes: 1 addition & 1 deletion libs/parser-sql/resources/full.postgres.sql
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ COMMENT ON TYPE slug IS 'anonymous type';
-- CREATE TYPE uid AS int; -- type alias not supported on PostgreSQL
CREATE TYPE cms.post_status AS ENUM ('draft', 'published', 'archived');
CREATE TYPE position AS (x int, y int);
CREATE TYPE box (INTERNALLENGTH = 16, INPUT = lower, OUTPUT = lower);
CREATE TYPE box (INPUT = lower, OUTPUT = lower, INTERNALLENGTH = 16);

--
-- Full Schema AML
Expand Down
4 changes: 4 additions & 0 deletions libs/parser-sql/src/errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import {ParserError, ParserErrorLevel, TokenPosition} from "@azimutt/models";

export const duplicated = (name: string, definedAtLine: number | undefined, position: TokenPosition): ParserError =>
({message: `${name} already defined${definedAtLine !== undefined ? ` at line ${definedAtLine}` : ''}`, kind: 'Duplicated', level: ParserErrorLevel.enum.warning, offset: position.offset, position: position.position})
loicknuchel marked this conversation as resolved.
Show resolved Hide resolved
Loading
Loading