diff --git a/src/main/scala/minisql/context/sql/PostgresDialect.scala b/src/main/scala/minisql/context/sql/PostgresDialect.scala new file mode 100644 index 0000000..a8bc14a --- /dev/null +++ b/src/main/scala/minisql/context/sql/PostgresDialect.scala @@ -0,0 +1,54 @@ +package minisql.context.sql.idiom + +import java.util.concurrent.atomic.AtomicInteger + +import minisql.ast.* +import minisql.{NamingStrategy} +import minisql.context.CanReturnClause +import minisql.idiom.StatementInterpolator.* + +trait PostgresDialect + extends SqlIdiom + with QuestionMarkBindVariables + with ConcatSupport + with OnConflictSupport + with CanReturnClause { + + override def astTokenizer(using + astTokenizer: Tokenizer[Ast], + strategy: NamingStrategy + ): Tokenizer[Ast] = + Tokenizer[Ast] { + case ListContains(ast, body) => stmt"${body.token} = ANY(${ast.token})" + case c: OnConflict => conflictTokenizer.token(c) + case ast => super.astTokenizer.token(ast) + } + + override def operationTokenizer(using + astTokenizer: Tokenizer[Ast], + strategy: NamingStrategy + ): Tokenizer[Operation] = + Tokenizer[Operation] { + case UnaryOperation(StringOperator.`toLong`, ast) => + stmt"${scopedTokenizer(ast)}::bigint" + case UnaryOperation(StringOperator.`toInt`, ast) => + stmt"${scopedTokenizer(ast)}::integer" + case operation => super.operationTokenizer.token(operation) + } + + private[minisql] val preparedStatementId = new AtomicInteger + + override def prepareForProbing(string: String) = { + var i = 0 + val query = string.flatMap(x => + if (x != '?') s"$x" + else { + i += 1 + s"$$$i" + } + ) + s"PREPARE p${preparedStatementId.incrementAndGet.toString.token} AS $query" + } +} + +object PostgresDialect extends PostgresDialect diff --git a/src/main/scala/minisql/context/sql/SqlIdiom.scala b/src/main/scala/minisql/context/sql/SqlIdiom.scala index 4b0f2c3..bd138f6 100644 --- a/src/main/scala/minisql/context/sql/SqlIdiom.scala +++ b/src/main/scala/minisql/context/sql/SqlIdiom.scala @@ -316,7 +316,12 @@ trait SqlIdiom extends Idiom { case other => fail(s"Malformed or unsupported construct: $other.") } - given operationTokenizer(using + given (using + astTokenizer: Tokenizer[Ast], + strategy: NamingStrategy + ): Tokenizer[Operation] = operationTokenizer + + def operationTokenizer(using astTokenizer: Tokenizer[Ast], strategy: NamingStrategy ): Tokenizer[Operation] = Tokenizer[Operation] {