Skip to content

Commit

Permalink
Improve Create Type
Browse files Browse the repository at this point in the history
  • Loading branch information
loicknuchel committed Oct 18, 2024
1 parent 68d52b3 commit 8151d82
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 31 deletions.
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/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
2 changes: 1 addition & 1 deletion libs/parser-sql/src/postgresAst.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export type CommentStatementAst = { kind: 'Comment', object: { kind: CommentObje
export type CreateExtensionStatementAst = { kind: 'CreateExtension', ifNotExists?: TokenInfo, name: IdentifierAst, with?: TokenInfo, schema?: {name: IdentifierAst} & TokenInfo, version?: {number: StringAst | IdentifierAst} & TokenInfo, cascade?: TokenInfo } & TokenInfo
export type CreateIndexStatementAst = { kind: 'CreateIndex', unique?: TokenInfo, concurrently?: TokenInfo, ifNotExists?: TokenInfo, index?: IdentifierAst, only?: TokenInfo, schema?: IdentifierAst, table: IdentifierAst, using?: {method: IdentifierAst} & TokenInfo, columns: IndexColumnAst[], include?: {columns: IdentifierAst[]} & TokenInfo, where?: {predicate: ExpressionAst} & TokenInfo } & TokenInfo
export type CreateTableStatementAst = { kind: 'CreateTable', schema?: IdentifierAst, table: IdentifierAst, columns: TableColumnAst[], constraints?: TableConstraintAst[] } & TokenInfo
export type CreateTypeStatementAst = { kind: 'CreateType', schema?: IdentifierAst, type: IdentifierAst, struct?: {attrs: TypeColumnAst[]} & TokenInfo, enum?: {values: StringAst[]} & TokenInfo } & TokenInfo
export type CreateTypeStatementAst = { kind: 'CreateType', schema?: IdentifierAst, type: IdentifierAst, struct?: {attrs: TypeColumnAst[]} & TokenInfo, enum?: {values: StringAst[]} & TokenInfo, base?: {name: IdentifierAst, value: ExpressionAst}[] } & TokenInfo
export type DropStatementAst = { kind: 'Drop', object: { kind: DropObject } & TokenInfo, entities: TableRefAst[], concurrently?: TokenInfo, ifExists?: TokenInfo, mode?: { kind: DropMode } & TokenInfo } & TokenInfo
export type InsertIntoStatementAst = { kind: 'InsertInto', schema?: IdentifierAst, table: IdentifierAst, columns?: IdentifierAst[], values: (ExpressionAst | { kind: 'Default' } & TokenInfo)[][], returning?: SelectClauseAst } & TokenInfo
export type SelectStatementAst = { kind: 'Select', select: SelectClauseAst, from?: FromClauseAst, where?: WhereClauseAst } & TokenInfo
Expand Down
13 changes: 13 additions & 0 deletions libs/parser-sql/src/postgresParser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,19 @@ describe('postgresParser', () => {
...token(0, 56)
}]}})
})
// TODO: range
test('base', () => {
expect(parsePostgresAst("CREATE TYPE box (INPUT = my_box_in_function, OUTPUT = my_box_out_function, INTERNALLENGTH = 16);")).toEqual({result: {statements: [{
kind: 'CreateType',
type: identifier('box', 12, 14),
base: [
{name: identifier('INPUT', 17, 21), value: {column: identifier('my_box_in_function', 25, 42)}}, // FIXME: expressions should be different here (identifier instead of column)
{name: identifier('OUTPUT', 45, 50), value: {column: identifier('my_box_out_function', 54, 72)}},
{name: identifier('INTERNALLENGTH', 75, 88), value: integer(16, 92, 93)},
],
...token(0, 95)
}]}})
})
})
describe('dropStatement', () => {
test('simplest', () => {
Expand Down
63 changes: 37 additions & 26 deletions libs/parser-sql/src/postgresParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,32 +366,12 @@ class PostgresParser extends EmbeddedActionsParser {
const start = $.CONSUME(Create)
$.CONSUME(Type)
const table = $.SUBRULE($.tableRefRule)
const content = $.OPTION(() => {
const as = $.CONSUME(As)
return $.OR([
{ALT: () => {
$.CONSUME(ParenLeft)
const attrs: TypeColumnAst[] = []
$.AT_LEAST_ONE_SEP({SEP: Comma, DEF: () => attrs.push(removeUndefined({
name: $.SUBRULE($.identifierRule),
type: $.SUBRULE($.columnTypeRule),
collation: $.OPTION2(() => ({...tokenInfo($.CONSUME(Collate)), name: $.SUBRULE2($.identifierRule)}))
}))})
$.CONSUME(ParenRight)
return {struct: {...tokenInfo(as), attrs: attrs.filter(isNotUndefined)}}
}},
{ALT: () => {
const token = tokenInfo2(as, $.CONSUME(Enum))
$.CONSUME2(ParenLeft)
const values: StringAst[] = []
$.AT_LEAST_ONE_SEP2({SEP: Comma, DEF: () => values.push($.SUBRULE($.stringRule))})
$.CONSUME2(ParenRight)
return {enum: {...token, values: values.filter(isNotUndefined)}}
}},
// TODO: RANGE
// TODO: function
])
})
const content = $.OPTION(() => $.OR([
{ALT: () => ({struct: {...tokenInfo($.CONSUME(As)), attrs: $.SUBRULE(createTypeStructAttrs)}})},
{ALT: () => ({enum: {...tokenInfo2($.CONSUME2(As), $.CONSUME(Enum)), values: $.SUBRULE(createTypeEnumValues)}})},
// TODO: RANGE
{ALT: () => ({base: $.SUBRULE(createTypeBase)})}
]))
const end = $.CONSUME(Semicolon)
return removeEmpty({kind: 'CreateType' as const, schema: table.schema, type: table.table, ...content, ...tokenInfo2(start, end)})
})
Expand Down Expand Up @@ -621,6 +601,37 @@ class PostgresParser extends EmbeddedActionsParser {
return removeUndefined({kind: 'ForeignKey' as const, ...tokenInfo(token), columns, ref, onUpdate, onDelete, constraint})
})

const createTypeStructAttrs = $.RULE<() => TypeColumnAst[]>('createTypeStructAttrs', () => {
$.CONSUME(ParenLeft)
const attrs: TypeColumnAst[] = []
$.AT_LEAST_ONE_SEP({SEP: Comma, DEF: () => attrs.push(removeUndefined({
name: $.SUBRULE($.identifierRule),
type: $.SUBRULE($.columnTypeRule),
collation: $.OPTION(() => ({...tokenInfo($.CONSUME(Collate)), name: $.SUBRULE2($.identifierRule)}))
}))})
$.CONSUME(ParenRight)
return attrs.filter(isNotUndefined)
})
const createTypeEnumValues = $.RULE<() => StringAst[]>('createTypeEnumValues', () => {
$.CONSUME(ParenLeft)
const values: StringAst[] = []
$.AT_LEAST_ONE_SEP({SEP: Comma, DEF: () => values.push($.SUBRULE($.stringRule))})
$.CONSUME(ParenRight)
return values
})
const createTypeBase = $.RULE<() => {name: IdentifierAst, value: ExpressionAst}[]>('createTypeBase', () => {
$.CONSUME(ParenLeft)
const params: {name: IdentifierAst, value: ExpressionAst}[] = []
$.AT_LEAST_ONE_SEP({SEP: Comma, DEF: () => {
const name = $.SUBRULE($.identifierRule)
$.CONSUME(Equal)
const value = $.SUBRULE($.expressionRule)
params.push({name, value})
}})
$.CONSUME(ParenRight)
return params
})

const constraintNameRule = $.RULE<() => ConstraintNameAst>('constraintNameRule', () => {
const token = $.CONSUME(Constraint)
const name = $.SUBRULE($.identifierRule)
Expand Down

0 comments on commit 8151d82

Please sign in to comment.