All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.scalaquery.ql.extended.SQLiteDriver.scala Maven / Gradle / Ivy

package org.scalaquery.ql.extended

import org.scalaquery.SQueryException
import org.scalaquery.ql._
import org.scalaquery.ql.basic._
import org.scalaquery.util._
import org.scalaquery.util.SQLBuilder._

/**
 * ScalaQuery driver for SQLite.
 *
 * 

This driver implements the ExtendedProfile with the following * limitations:

*
    *
  • Sequences are not supported because SQLite does not have them.
  • *
  • Blobs are not supported by the SQLite JDBC driver (but binary data in * the form of Array[Byte] is).
  • *
  • SQLite does not allow mutation of result sets. All cursors are * read-only.
  • *
  • Functions.user and Functions.database are * not available in SQLite. ScalaQuery will return empty strings for * both.
  • *
*/ class SQLiteDriver extends ExtendedProfile { self => type ImplicitT = ExtendedImplicitConversions[SQLiteDriver] type TypeMapperDelegatesT = BasicTypeMapperDelegates val Implicit = new ExtendedImplicitConversions[SQLiteDriver] { implicit val scalaQueryDriver = self } val typeMapperDelegates = new SQLiteTypeMapperDelegates override def createQueryBuilder(query: Query[_], nc: NamingContext) = new SQLiteQueryBuilder(query, nc, None, this) override def buildTableDDL(table: AbstractBasicTable[_]): DDL = new SQLiteDDLBuilder(table, this).buildDDL } object SQLiteDriver extends SQLiteDriver class SQLiteTypeMapperDelegates extends BasicTypeMapperDelegates { import SQLiteTypeMapperDelegates._ override val booleanTypeMapperDelegate = new BooleanTypeMapperDelegate } object SQLiteTypeMapperDelegates { /* SQLite does not have a proper BOOLEAN type. The suggested workaround is * INTEGER with constants 1 and 0 for TRUE and FALSE. */ class BooleanTypeMapperDelegate extends BasicTypeMapperDelegates.BooleanTypeMapperDelegate { override def sqlTypeName = "INTEGER" override def valueToSQLLiteral(value: Boolean) = if(value) "1" else "0" } } class SQLiteDDLBuilder(table: AbstractBasicTable[_], profile: SQLiteDriver) extends BasicDDLBuilder(table, profile) { import profile.sqlUtils._ protected class SQLiteColumnDDLBuilder(column: NamedColumn[_]) extends BasicColumnDDLBuilder(column) { override protected def appendOptions(sb: StringBuilder) { if(defaultLiteral ne null) sb append " DEFAULT " append defaultLiteral if(autoIncrement) sb append " PRIMARY KEY AUTOINCREMENT" else if(notNull) sb append " NOT NULL" else if(primaryKey) sb append " PRIMARY KEY" } } override protected def createColumnDDLBuilder(c: NamedColumn[_]) = new SQLiteColumnDDLBuilder(c) override def buildDDL: DDL = { val b = new StringBuilder append "CREATE TABLE " append table.tableName append " (" var first = true for(n <- table.create_*) { if(first) first = false else b append "," createColumnDDLBuilder(n).appendColumn(b) } var prevPK: String = null for(pk <- table.primaryKeys) { if(prevPK eq null) prevPK = pk.name else throw new SQueryException("Table "+table.tableName+" defines multiple primary keys "+prevPK+" and "+pk.name) b append "," addPrimaryKey(pk, b) } for(fk <- table.foreignKeys) { b append "," addForeignKey(fk, b) } b append ")" new DDL { val createPhase1 = Iterable(b.toString) val createPhase2 = Iterable() val dropPhase1 = Nil val dropPhase2 = Iterable("DROP TABLE " + table.tableName) } } } class SQLiteQueryBuilder(_query: Query[_], _nc: NamingContext, parent: Option[BasicQueryBuilder], profile: SQLiteDriver) extends BasicQueryBuilder(_query, _nc, parent, profile) { import ExtendedQueryOps._ import profile.sqlUtils._ override type Self = SQLiteQueryBuilder protected def createSubQueryBuilder(query: Query[_], nc: NamingContext) = new SQLiteQueryBuilder(query, nc, Some(this), profile) override protected def table(t: Node, name: String, b: SQLBuilder): Unit = t match { case j: Join[_,_] => createJoin(j, b) case _ => super.table(t, name, b) } override protected def appendOrdering(o: Ordering, b: SQLBuilder) { val desc = o.isInstanceOf[Ordering.Desc] if(o.nullOrdering == Ordering.NullsLast && !desc) { b += "(" expr(o.by, b) b += ") is null," } else if(o.nullOrdering == Ordering.NullsFirst && desc) { b += "(" expr(o.by, b) b += ") is null desc," } expr(o.by, b) if(desc) b += " desc" } override protected def appendClauses(b: SQLBuilder): Unit = { super.appendClauses(b) appendLimitClause(b) } protected def appendLimitClause(b: SQLBuilder): Unit = query.typedModifiers[TakeDrop].lastOption.foreach { case TakeDrop(Some(t), Some(d)) => b += " LIMIT " += d += "," += t case TakeDrop(Some(t), None) => b += " LIMIT " += t case TakeDrop(None, Some(d)) => b += " LIMIT " += d += ",-1" case _ => } override protected def innerExpr(c: Node, b: SQLBuilder): Unit = c match { case a @ ColumnOps.AsColumnOf(ch, name) => /* SQLite does not support {fn convert}, so we use the SQL CAST syntax */ b += "cast("; expr(ch, b); b += " as " += name.getOrElse(mapTypeName(a.typeMapper(profile))) += ")" case ColumnOps.Exists(q: Query[_]) => // SQLite doesn't like double parens around the sub-expression b += "exists"; expr(q, b) case ColumnOps.Concat(l, r) => b += '('; expr(l, b); b += "||"; expr(r, b); b += ')' case ColumnOps.ToUpperCase(ch) => b += "upper("; expr(ch, b); b += ')' case ColumnOps.ToLowerCase(ch) => b += "lower("; expr(ch, b); b += ')' case ColumnOps.Mod(l, r, _) => b += '('; expr(l, b); b += '%'; expr(r, b); b += ')' case ColumnOps.Ceil(ch, _) => b += "round("; expr(ch, b); b += "+0.5)" case ColumnOps.Floor(ch, _) => b += "round("; expr(ch, b); b += "-0.5)" case SimpleFunction("user", true) => b += "''" case SimpleFunction("database", true) => b += "''" case s @ SimpleFunction(fname, true) => /* The SQLite JDBC driver does not support ODBC {fn ...} escapes, so we try * unescaped function calls by default */ b += fname += '(' for(ch <- b.sep(s.nodeChildren, ",")) expr(ch, b) b += ")" case fk: ForeignKey[_] => /* SQLite does not support row value constructor syntax (tuple syntax), * so we need to untuple and compare the individual columns (which * may not not kosher in the presence of NULLs). */ val cols = untupleColumn(fk.left) zip untupleColumn(fk.right) b += "(" for((l,r) <- b.sep(cols, " and ")) { expr(l, b); b += "="; expr(r, b); } b += ")" case _ => super.innerExpr(c, b) } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy