Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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 elm.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"elm/html": "1.0.0",
"elm/http": "2.0.0",
"elm/json": "1.1.3",
"elm/parser": "1.1.0",
"elm/random": "1.0.0",
"elm/regex": "1.0.0",
"elm/svg": "1.0.1",
Expand All @@ -33,7 +34,6 @@
"dillonkearns/elm-markdown": "6.0.1",
"elm/bytes": "1.0.8",
"elm/file": "1.0.5",
"elm/parser": "1.1.0",
"elm/virtual-dom": "1.0.2",
"pablohirafuji/elm-syntax-highlight": "3.4.1",
"rtfeldman/elm-hex": "1.0.0"
Expand Down
67 changes: 67 additions & 0 deletions src/DataSources/NewSqlParser/Dsl.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
module DataSources.NewSqlParser.Dsl exposing (CheckInner, ColumnConstraint(..), ForeignKeyInner, ForeignKeyRef, IndexInner, ParseError, ParsedColumn, ParsedConstraint(..), ParsedTable, PrimaryKeyInner, SqlStatement, UniqueInner)

import Libs.Nel exposing (Nel)


type alias SqlStatement =
String


type alias ParsedTable =
{ schema : Maybe String
, table : String
, columns : List ParsedColumn
, constraints : List ParsedConstraint
}


type alias ParsedColumn =
{ name : String
, kind : String
, nullable : Bool
, default : Maybe String
, primaryKey : Maybe String
, foreignKey : Maybe ( String, ForeignKeyRef )
, check : Maybe String
}


type alias ForeignKeyRef =
{ schema : Maybe String, table : String, column : Maybe String }


type ColumnConstraint
= ColumnPrimaryKey
| ColumnForeignKey ForeignKeyRef


type ParsedConstraint
= PrimaryKey PrimaryKeyInner
| ForeignKey ForeignKeyInner
| Unique UniqueInner
| Index IndexInner
| Check CheckInner


type alias PrimaryKeyInner =
{ name : Maybe String, columns : Nel String }


type alias ForeignKeyInner =
{ name : Maybe String, src : String, ref : ForeignKeyRef }


type alias UniqueInner =
{ name : String, columns : Nel String }


type alias IndexInner =
{ name : String, columns : Nel String, definition : String }


type alias CheckInner =
{ name : String, columns : List String, predicate : String }


type alias ParseError =
String
6 changes: 6 additions & 0 deletions src/DataSources/NewSqlParser/FileParser.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module DataSources.NewSqlParser.FileParser exposing (parse)


parse : String -> String
parse file =
file
166 changes: 166 additions & 0 deletions src/DataSources/NewSqlParser/Parsers/Basic.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
module DataSources.NewSqlParser.Parsers.Basic exposing (checkParser, columnNameParser, columnTypeParser, constraintParser, defaultValueParser, foreignKeyParser, foreignKeyRefParser, notNullParser, primaryKeyParser, schemaNameParser, tableNameParser, tableRefParser)

import DataSources.NewSqlParser.Dsl exposing (ColumnConstraint(..), ForeignKeyRef)
import Libs.Parser exposing (exists, identifierOrQuoted, maybe, symbolInsensitive)
import Parser exposing ((|.), (|=), Nestable(..), Parser, Trailing(..), backtrackable, getChompedString, int, multiComment, oneOf, sequence, spaces, succeed, symbol)



-- reusable (small) building blocks for bigger parsers


tableRefParser : Parser ( Maybe String, String )
tableRefParser =
succeed
(\schemaName tableName ->
case ( schemaName, tableName ) of
( part1, Nothing ) ->
( Nothing, part1 )

( part1, Just part2 ) ->
( Just part1, part2 )
)
|= identifierOrQuoted
|= maybe
(succeed identity
|. symbol "."
|= identifierOrQuoted
)


schemaNameParser : Parser String
schemaNameParser =
identifierOrQuoted


tableNameParser : Parser String
tableNameParser =
identifierOrQuoted


columnNameParser : Parser String
columnNameParser =
identifierOrQuoted


columnTypeParser : Parser String
columnTypeParser =
-- cf https://www.postgresql.org/docs/current/datatype.html
oneOf
[ customColumnTypeParser "BIT VARYING" (maybe numbers |> Parser.map (Maybe.withDefault ""))
, customColumnTypeParser "CHARACTER VARYING" (maybe numbers |> Parser.map (Maybe.withDefault ""))
, customColumnTypeParser "DOUBLE PRECISION" nothing
, customColumnTypeParser "INT IDENTITY" (maybe numbers |> Parser.map (Maybe.withDefault ""))
, succeed (\name nums -> name ++ nums)
|= identifierOrQuoted
|. spaces
|= (maybe numbers |> Parser.map (Maybe.withDefault ""))
]


customColumnTypeParser : String -> Parser String -> Parser String
customColumnTypeParser name parser =
succeed (\kind value -> kind ++ value)
|= symbolInsensitive name
|. spaces
|= parser


numbers : Parser String
numbers =
Parser.map (\nums -> "(" ++ (nums |> List.map String.fromInt |> String.join ",") ++ ")")
(sequence
{ start = "("
, separator = ","
, end = ")"
, spaces = spaces
, item = int
, trailing = Forbidden
}
)


nothing : Parser String
nothing =
succeed ""


notNullParser : Parser Bool
notNullParser =
exists (symbolInsensitive "NOT NULL") |> Parser.map not


defaultValueParser : Parser (Maybe String)
defaultValueParser =
oneOf
[ succeed (\value kind -> Just (value ++ (kind |> Maybe.withDefault "")))
|. symbolInsensitive "DEFAULT"
|. spaces
|= (identifierOrQuoted |> getChompedString)
|= oneOf
[ succeed (\t -> Just ("::" ++ t))
|. symbol "::"
|= columnTypeParser
, succeed
Nothing
]
, succeed Nothing
]


primaryKeyParser : Parser (Maybe String)
primaryKeyParser =
maybe (succeed "" |. symbolInsensitive "PRIMARY KEY")


checkParser : Parser (Maybe String)
checkParser =
oneOf
[ succeed (\str -> str |> String.dropLeft 1 |> String.dropRight 1 |> Just)
|. symbolInsensitive "CHECK"
|. spaces
|= (multiComment "(" ")" Nestable |> getChompedString)
, succeed Nothing
]


constraintParser : Parser (Maybe ( String, ColumnConstraint ))
constraintParser =
maybe
(succeed (\name constraint -> ( name, constraint ))
|. symbolInsensitive "CONSTRAINT"
|. spaces
|= identifierOrQuoted
|. spaces
|= oneOf
[ succeed ColumnPrimaryKey |. symbolInsensitive "PRIMARY KEY"
, foreignKeyParser |> Parser.map ColumnForeignKey
]
)


foreignKeyParser : Parser ForeignKeyRef
foreignKeyParser =
succeed identity
|. symbolInsensitive "REFERENCES"
|. spaces
|= foreignKeyRefParser


foreignKeyRefParser : Parser ForeignKeyRef
foreignKeyRefParser =
oneOf
[ backtrackable <|
succeed (\schema table column -> ForeignKeyRef (Just schema) table (Just column))
|= identifierOrQuoted
|. symbol "."
|= identifierOrQuoted
|. symbol "."
|= identifierOrQuoted
, backtrackable <|
succeed (\table column -> ForeignKeyRef Nothing table (Just column))
|= identifierOrQuoted
|. symbol "."
|= identifierOrQuoted
, succeed (\table -> ForeignKeyRef Nothing table Nothing) |= identifierOrQuoted
]
75 changes: 75 additions & 0 deletions src/DataSources/NewSqlParser/Parsers/CreateTable.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
module DataSources.NewSqlParser.Parsers.CreateTable exposing (columnParser, columnsParser, createTableParser)

import DataSources.NewSqlParser.Dsl exposing (ColumnConstraint(..), ParsedColumn, ParsedTable)
import DataSources.NewSqlParser.Parsers.Basic exposing (checkParser, columnNameParser, columnTypeParser, constraintParser, defaultValueParser, notNullParser, primaryKeyParser, tableRefParser)
import Libs.Maybe as M
import Libs.Parser exposing (symbolInsensitive)
import Parser exposing ((|.), (|=), Parser, Trailing(..), oneOf, sequence, spaces, succeed)



-- https://www.postgresql.org/docs/current/sql-createtable.html
-- https://dev.mysql.com/doc/refman/8.0/en/create-table.html
-- https://docs.microsoft.com/fr-fr/sql/t-sql/statements/create-table-transact-sql
-- https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-TABLE.html
-- https://www.sqlite.org/lang_createtable.html


createTableParser : Parser ParsedTable
createTableParser =
succeed (\( schemaName, tableName ) columns -> ParsedTable schemaName tableName columns [])
|. symbolInsensitive "CREATE TABLE"
|. spaces
|. oneOf
[ symbolInsensitive "IF NOT EXISTS"
, succeed ""
]
|. spaces
|= tableRefParser
|. spaces
|= columnsParser


columnsParser : Parser (List ParsedColumn)
columnsParser =
sequence
{ start = "("
, separator = ","
, end = ")"
, spaces = spaces
, item = columnParser
, trailing = Forbidden
}


columnParser : Parser ParsedColumn
columnParser =
succeed
(\name kind nullable default primaryKey check constraint ->
let
( pk, fk ) =
case constraint of
Just ( constraintName, ColumnPrimaryKey ) ->
( primaryKey |> M.orElse (Just constraintName), Nothing )

Just ( constraintName, ColumnForeignKey ref ) ->
( primaryKey, Just ( constraintName, ref ) )

Nothing ->
( primaryKey, Nothing )
in
ParsedColumn name kind nullable default pk fk check
)
|= columnNameParser
|. spaces
|= columnTypeParser
|. spaces
|= notNullParser
|. spaces
|= defaultValueParser
|. spaces
|= primaryKeyParser
|. spaces
|= checkParser
|. spaces
|= constraintParser
6 changes: 6 additions & 0 deletions src/DataSources/NewSqlParser/StatementParser.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module DataSources.NewSqlParser.StatementParser exposing (parse)


parse : String -> String
parse file =
file
Loading