Skip to content

Commit

Permalink
Small refacto
Browse files Browse the repository at this point in the history
  • Loading branch information
loicknuchel committed Oct 29, 2024
1 parent 4b5fd3f commit 4bef4e1
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 45 deletions.
5 changes: 3 additions & 2 deletions libs/parser-sql/src/postgresBuilder.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as fs from "fs";
import {describe, expect, test} from "@jest/globals";
import {removeFieldsDeep} from "@azimutt/utils";
import {Database, Entity, parseJsonDatabase, ParserError} from "@azimutt/models";
import {SelectStatementInnerAst} from "./postgresAst";
import {parsePostgresAst} from "./postgresParser";
Expand Down Expand Up @@ -87,13 +88,13 @@ COMMENT ON TYPE bug_status IS 'bug status';
}
expect(parse(input)).toEqual({db, errors: []})
})
test.skip('full', () => {
test.skip('full', () => { // won't work, some concepts can't be handled in SQL, yet, worth checking the diff ^^
const json = parseJsonDatabase(fs.readFileSync('../aml/resources/full.json', 'utf8'))
const db: Database = json.result || {}
const sql = fs.readFileSync('./resources/full.postgres.sql', 'utf8')
const parsed = parse(sql)
expect(parsed.errors).toEqual([])
expect(parsed.db).toEqual(db)
expect(removeFieldsDeep(parsed.db, ['extra'])).toEqual(removeFieldsDeep(db, ['extra']))
})
describe('selectEntities', () => {
const users: Entity = {schema: 'public', name: 'users', attrs: [{name: 'id', type: 'int'}, {name: 'name', type: 'varchar'}]}
Expand Down
89 changes: 46 additions & 43 deletions libs/parser-sql/src/postgresBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,56 +47,15 @@ import {
PostgresAst,
SelectClauseColumnAst,
SelectStatementInnerAst,
StatementAst,
TableColumnAst
} from "./postgresAst";
import {duplicated} from "./errors";

export function buildPostgresDatabase(ast: PostgresAst, start: number, parsed: number): ParserResult<Database> {
const db: Database = {entities: [], relations: [], types: []}
const errors: ParserError[] = []
ast.statements.forEach((stmt, i) => {
const index = i + 1
if (stmt.kind === 'AlterTable') {
alterTable(index, stmt, db)
} else if (stmt.kind === 'CommentOn') {
commentOn(index, stmt, db)
} else if (stmt.kind === 'CreateIndex') {
if (!db.entities) db.entities = []
createIndex(index, stmt, db.entities)
} else if (stmt.kind === 'CreateMaterializedView') {
if (!db.entities) db.entities = []
const entity = createMaterializedView(index, stmt, db.entities)
addEntity(db.entities, errors, entity, mergePositions([stmt.schema, stmt.name].map(v => v?.token)))
} else if (stmt.kind === 'CreateTable') {
if (!db.entities) db.entities = []
const res = createTable(index, stmt)
addEntity(db.entities, errors, res.entity, mergePositions([stmt.schema, stmt.name].map(v => v?.token)))
res.relations.forEach(r => db.relations?.push(r))
} else if (stmt.kind === 'CreateType') {
if (!db.types) db.types = []
const type = createType(index, stmt)
addType(db.types, errors, type, mergePositions([stmt.schema, stmt.name].map(v => v?.token)))
} else if (stmt.kind === 'CreateView') {
if (!db.entities) db.entities = []
const entity = createView(index, stmt, db.entities)
addEntity(db.entities, errors, entity, mergePositions([stmt.schema, stmt.name].map(v => v?.token)))
} else if (stmt.kind === 'AlterSequence') { // nothing
} else if (stmt.kind === 'Begin') { // nothing
} else if (stmt.kind === 'Commit') { // nothing
} else if (stmt.kind === 'CreateExtension') { // nothing
} else if (stmt.kind === 'CreateFunction') { // nothing
} else if (stmt.kind === 'CreateSequence') { // nothing
} else if (stmt.kind === 'Delete') { // nothing
} else if (stmt.kind === 'Drop') { // nothing
} else if (stmt.kind === 'InsertInto') { // nothing
} else if (stmt.kind === 'Select') { // nothing
} else if (stmt.kind === 'Set') { // nothing
} else if (stmt.kind === 'Show') { // nothing
} else if (stmt.kind === 'Update') { // nothing
} else {
isNever(stmt)
}
})
ast.statements.forEach((stmt, i) => evolvePostgres(db, errors, i + 1, stmt))
const done = Date.now()
const extra = removeEmpty({
source: `PostgreSQL parser <${packageJson.version}>`,
Expand All @@ -109,6 +68,49 @@ export function buildPostgresDatabase(ast: PostgresAst, start: number, parsed: n
return new ParserResult(removeEmpty({...db, extra}), errors)
}

export function evolvePostgres(db: Database, errors: ParserError[], index: number, stmt: StatementAst): void {
if (stmt.kind === 'AlterTable') {
alterTable(index, stmt, db)
} else if (stmt.kind === 'CommentOn') {
commentOn(index, stmt, db)
} else if (stmt.kind === 'CreateIndex') {
if (!db.entities) db.entities = []
createIndex(index, stmt, db.entities)
} else if (stmt.kind === 'CreateMaterializedView') {
if (!db.entities) db.entities = []
const entity = createMaterializedView(index, stmt, db.entities)
addEntity(db.entities, errors, entity, mergePositions([stmt.schema, stmt.name].map(v => v?.token)))
} else if (stmt.kind === 'CreateTable') {
if (!db.entities) db.entities = []
const res = createTable(index, stmt)
addEntity(db.entities, errors, res.entity, mergePositions([stmt.schema, stmt.name].map(v => v?.token)))
res.relations.forEach(r => db.relations?.push(r))
} else if (stmt.kind === 'CreateType') {
if (!db.types) db.types = []
const type = createType(index, stmt)
addType(db.types, errors, type, mergePositions([stmt.schema, stmt.name].map(v => v?.token)))
} else if (stmt.kind === 'CreateView') {
if (!db.entities) db.entities = []
const entity = createView(index, stmt, db.entities)
addEntity(db.entities, errors, entity, mergePositions([stmt.schema, stmt.name].map(v => v?.token)))
} else if (stmt.kind === 'AlterSequence') { // nothing
} else if (stmt.kind === 'Begin') { // nothing
} else if (stmt.kind === 'Commit') { // nothing
} else if (stmt.kind === 'CreateExtension') { // nothing
} else if (stmt.kind === 'CreateFunction') { // nothing
} else if (stmt.kind === 'CreateSequence') { // nothing
} else if (stmt.kind === 'Delete') { // nothing
} else if (stmt.kind === 'Drop') { // nothing
} else if (stmt.kind === 'InsertInto') { // nothing
} else if (stmt.kind === 'Select') { // nothing
} else if (stmt.kind === 'Set') { // nothing
} else if (stmt.kind === 'Show') { // nothing
} else if (stmt.kind === 'Update') { // nothing
} else {
isNever(stmt)
}
}

function addEntity(entities: Entity[], errors: ParserError[], entity: Entity, pos: TokenPosition): void {
const ref = entityToRef(entity)
const prevIndex = entities.findIndex(e => entityRefSame(entityToRef(e), ref))
Expand Down Expand Up @@ -476,6 +478,7 @@ export type SelectSourceFrom = SelectSourceTable | SelectSourceSelect
export type SelectSourceTable = { kind: 'Table', schema?: string, table: string, columns?: { name: string, type: string }[] }
export type SelectSourceSelect = { kind: 'Select' } & SelectEntities

// TODO: also extract entities in clauses such as WHERE, HAVING... (know all use involved tables & columns, wherever they are used)
export function selectEntities(s: SelectStatementInnerAst, entities: Entity[]): SelectEntities {
const sources = s.from ? selectTables(s.from, entities) : []
const columns: SelectColumn[] = s.columns.flatMap((c, i) => selectColumn(c, i, sources))
Expand Down

0 comments on commit 4bef4e1

Please sign in to comment.