All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
ldbc.codegen.parser.KeyParser.scala Maven / Gradle / Ivy
/**
* Copyright (c) 2023-2024 by Takahiko Tominaga
* This software is licensed under the MIT License (MIT).
* For more information see LICENSE or https://opensource.org/licenses/MIT
*/
package ldbc.codegen.parser
import ldbc.codegen.model.*
import ldbc.codegen.model.Key.*
/**
* Parser for parsing create table key definitions.
*/
trait KeyParser extends ColumnParser:
private def columnsParser: Parser[List[String]] =
customError(
"(" ~> repsep(sqlIdent, ",") <~ ")",
failureMessage("column list format", "(`column_name`) or (`column_name`, `column_name`, ...)")
)
private def withParser: Parser[Key.WithParser] =
customError(
caseSensitivity("with") ~> caseSensitivity("parser") ~> ident ^^ Key.WithParser.apply,
failureMessage("with parser type", "WITH PARSER `parser_name`")
)
private def indexType: Parser[Key.IndexType] =
customError(
caseSensitivity("using") ~> (caseSensitivity("btree") | caseSensitivity("hash")) ^^ {
case str if "(?i)btree".r.matches(str) => Key.IndexType("BTREE")
case str if "(?i)hash".r.matches(str) => Key.IndexType("HASH")
},
failureMessage("Index type", "USING {BTREE | HASH}")
)
private def visible: Parser[Key.Visible] =
customError(
(caseSensitivity("visible") | caseSensitivity("invisible")) ^^ {
case str if "(?i)visible".r.matches(str) => Key.Visible("VISIBLE")
case str if "(?i)invisible".r.matches(str) => Key.Visible("INVISIBLE")
},
failureMessage("visible/invisible", "{VISIBLE | INVISIBLE}")
)
private def indexOptions: Parser[Key.IndexOptions] =
keyBlockSize | indexType | withParser | commentSet | visible |
engineAttribute | secondaryEngineAttribute
private def indexOption: Parser[IndexOption] =
rep1(indexOptions) ^^ { indexOptions =>
indexOptions.foldLeft(IndexOption.empty)((prev, current) =>
current match
case value: Key.KeyBlockSize => prev.setSize(value)
case value: Key.IndexType => prev.setIndexType(value)
case value: Key.WithParser => prev.setWithParser(value)
case value: CommentSet => prev.setComment(value)
case value: Key.EngineAttribute => prev.setEngineAttribute(value)
case value: Key.SecondaryEngineAttribute => prev.setSecondaryEngineAttribute(value)
case value: Key.Visible => prev
)
}
private def indexKey: Parser[Index] =
(caseSensitivity("index") | caseSensitivity("key")) ~> opt(sqlIdent.filter {
case str if "(?i)using".r.matches(str) => false
case _ => true
}) ~ opt(indexType) ~ columnsParser ~ opt(indexOption) ^^ {
case indexName ~ indexType ~ keyParts ~ indexOption =>
Index(indexName, indexType, keyParts, indexOption)
}
private def fulltext: Parser[Index] =
(caseSensitivity("fulltext") | caseSensitivity("spatial")) ~>
opt(caseSensitivity("index") | caseSensitivity("key")) ~>
opt(sqlIdent) ~ columnsParser ~ opt(indexOption) ^^ {
case indexName ~ keyParts ~ indexOption => Index(indexName, None, keyParts, indexOption)
}
private def constraint: Parser[Constraint] =
caseSensitivity("constraint") ~> opt(sqlIdent.filter {
case str if "(?i)primary".r.matches(str) => false
case str if "(?i)unique".r.matches(str) => false
case str if "(?i)foreign".r.matches(str) => false
case str if "(?i)check".r.matches(str) => false
case _ => true
}) ^^ Constraint.apply
private def referenceOption: Parser[String] =
(
caseSensitivity("restrict") | caseSensitivity("cascade") | (caseSensitivity("set") ~
(caseSensitivity("null") | caseSensitivity("default"))) | (caseSensitivity("no") ~
caseSensitivity("action"))
) ^^ {
case set ~ option => s"Reference.ReferenceOption.${ set.toUpperCase }_${ option.toUpperCase }"
case option: String => s"Reference.ReferenceOption.${ option.toUpperCase }"
}
private def matchParser: Parser[String ~ String] =
customError(
caseSensitivity("match") ~ (caseSensitivity("full") | caseSensitivity("partial") | caseSensitivity("simple")),
failureMessage("match type", "MATCH {FULL | PARTIAL | SIMPLE}")
)
private def onDeleteUpdate: Parser[Key.OnDelete | Key.OnUpdate] =
customError(
caseSensitivity("on") ~> (caseSensitivity("delete") | caseSensitivity("update")) ~ referenceOption ^^ {
case str ~ option =>
str match
case str if "(?i)delete".r.matches(str) => Key.OnDelete(option)
case str if "(?i)update".r.matches(str) => Key.OnUpdate(option)
},
failureMessage(
"on delete/update type",
"ON {DELETE | UPDATE} [RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT]"
)
)
private def referenceDefinition: Parser[Reference] =
caseSensitivity("references") ~> sqlIdent ~ columnsParser ~
opt(matchParser) ~ opt(rep1(onDeleteUpdate)) ^^ {
case tableName ~ keyParts ~ _ ~ on =>
Reference(tableName, keyParts, on)
}
private def constraintPrimaryKey: Parser[Primary] =
opt(constraint) ~ primaryKey ~ opt(indexType) ~ columnsParser ~ opt(indexOption) ^^ {
case constraint ~ _ ~ indexType ~ keyParts ~ option =>
Primary(constraint, indexType, keyParts, option)
}
private def constraintUniqueKey: Parser[Unique] =
opt(constraint) ~ caseSensitivity("unique") ~ opt(caseSensitivity("index") | caseSensitivity("key"))
~ opt(sqlIdent) ~ opt(indexType) ~ columnsParser ~ opt(indexOption) ^^ {
case constraint ~ _ ~ _ ~ indexName ~ indexType ~ keyParts ~ option =>
Unique(constraint, indexName, indexType, keyParts, option)
}
private def constraintForeignKey: Parser[Foreign] =
opt(constraint) ~ caseSensitivity("foreign") ~ caseSensitivity("key") ~ opt(sqlIdent) ~
columnsParser ~ referenceDefinition ^^ {
case constraint ~ _ ~ _ ~ indexName ~ columnNames ~ referenceDefinition =>
Foreign(constraint, indexName, columnNames, referenceDefinition)
}
private def checkConstraintDefinition: Parser[String] =
customError(
opt(constraint) ~ caseSensitivity("check") ~ "(" ~ rep1(specialChars.filter(_ != ")")) ~ ")" ~
opt(caseSensitivity("not")) ~ opt(caseSensitivity("enforced")) ^^ {
case constraint ~ _ ~ _ ~ expr ~ _ ~ not ~ enforced =>
s"$constraint ${ expr.mkString(" ") } $not $enforced"
},
failureMessage("check type", "[CONSTRAINT [symbol]] CHECK (expr) [[NOT] ENFORCED]")
)
protected def keyDefinitions: Parser[Key | String] =
indexKey | fulltext | constraintPrimaryKey | constraintUniqueKey | constraintForeignKey | checkConstraintDefinition