Skip to content

Commit

Permalink
Support for subqueries in set clause of partial update, fixes #6
Browse files Browse the repository at this point in the history
  • Loading branch information
max-l committed Jan 29, 2011
1 parent d07acf9 commit e75ddec
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 43 deletions.
5 changes: 4 additions & 1 deletion src/main/scala/org/squeryl/dsl/ast/ExpressionNode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package org.squeryl.dsl.ast
import collection.mutable.ArrayBuffer
import org.squeryl.internals._
import org.squeryl.dsl._
import org.squeryl.{KeyedEntity, Schema, Session}
import org.squeryl.{Query, KeyedEntity, Schema, Session}

trait ExpressionNode {

Expand Down Expand Up @@ -267,6 +267,9 @@ trait TypedExpressionNode[T] extends ExpressionNode {
def :=[B <% TypedExpressionNode[T]] (b: B) =
new UpdateAssignment(_fieldMetaData, b : TypedExpressionNode[T])

def :=(q: Query[Measures[T]]) =
new UpdateAssignment(_fieldMetaData, q.ast)

def defaultsTo[B <% TypedExpressionNode[T]](value: B) /*(implicit restrictUsageWithinSchema: Schema) */ =
new DefaultValueAssignment(_fieldMetaData, value : TypedExpressionNode[T])

Expand Down
82 changes: 42 additions & 40 deletions src/main/scala/org/squeryl/internals/DatabaseAdapter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ trait DatabaseAdapter {
for(z <- qen.tableExpressions.zipi) {
z.element.write(sw)
sw.write(" ")
sw.write(sw.quoteName(z.element.alias))
sw.write(sw.quoteName(z.element.alias))
if(!z.isLast) {
sw.write(",")
sw.nextLine
Expand All @@ -80,14 +80,14 @@ trait DatabaseAdapter {
if(z.isFirst) {
z.element.write(sw)
sw.write(" ")
sw.write(sw.quoteName(z.element.alias))
sw.write(sw.quoteName(z.element.alias))
sw.indent
sw.nextLine
} else {
sw.write("inner join ")
z.element.write(sw)
sw.write(" as ")
sw.write(sw.quoteName(z.element.alias))
sw.write(sw.quoteName(z.element.alias))
sw.nextLine
}
}
Expand All @@ -107,7 +107,7 @@ trait DatabaseAdapter {
val restOfJoinExpr = qen.tableExpressions.filter(_.isMemberOfJoinList)
firstJoinExpr.write(sw)
sw.write(" ")
sw.write(sw.quoteName(firstJoinExpr.alias))
sw.write(sw.quoteName(firstJoinExpr.alias))
sw.nextLine

for(z <- restOfJoinExpr.zipi) {
Expand Down Expand Up @@ -176,7 +176,7 @@ trait DatabaseAdapter {
sw.write(" outer join ")
oje.queryableExpressionNode.write(sw)
sw.write(" as ")
sw.write(sw.quoteName(oje.queryableExpressionNode.alias))
sw.write(sw.quoteName(oje.queryableExpressionNode.alias))
sw.write(" on ")
oje.matchExpression.write(sw)
}
Expand All @@ -188,7 +188,7 @@ trait DatabaseAdapter {
sw.write(" join ")
queryableExpressionNode.write(sw)
sw.write(" as ")
sw.write(sw.quoteName(queryableExpressionNode.alias))
sw.write(sw.quoteName(queryableExpressionNode.alias))
sw.write(" on ")
queryableExpressionNode.joinExpression.get.write(sw)
}
Expand Down Expand Up @@ -238,7 +238,7 @@ trait DatabaseAdapter {
val sb = new StringBuilder(128)

sb.append(" ")
sb.append(quoteName(fmd.columnName))
sb.append(quoteName(fmd.columnName))
sb.append(" ")
sb.append(dbTypeDeclaration)

Expand Down Expand Up @@ -269,7 +269,7 @@ trait DatabaseAdapter {
def writeCreateTable[T](t: Table[T], sw: StatementWriter, schema: Schema) = {

sw.write("create table ")
sw.write(quoteName(t.prefixedName))
sw.write(quoteName(t.prefixedName))
sw.write(" (\n");
sw.writeIndented {
sw.writeLinesWithSeparator(
Expand Down Expand Up @@ -395,9 +395,9 @@ trait DatabaseAdapter {
val f = t.posoMetaData.fieldsMetaData.filter(fmd => !fmd.isAutoIncremented)

sw.write("insert into ");
sw.write(quoteName(t.prefixedName));
sw.write(quoteName(t.prefixedName));
sw.write(" (");
sw.write(f.map(fmd => quoteName(fmd.columnName)).mkString(", "));
sw.write(f.map(fmd => quoteName(fmd.columnName)).mkString(", "));
sw.write(") values ");
sw.write(
f.map(fmd => writeValue(o_, fmd, sw)
Expand Down Expand Up @@ -480,17 +480,17 @@ trait DatabaseAdapter {
val o_ = o.asInstanceOf[AnyRef]


sw.write("update ", quoteName(t.prefixedName), " set ")
sw.write("update ", quoteName(t.prefixedName), " set ")
sw.nextLine
sw.indent
sw.writeLinesWithSeparator(
t.posoMetaData.fieldsMetaData.
filter(fmd=> ! fmd.isIdFieldOfKeyedEntity).
map(fmd => {
if(fmd.isOptimisticCounter)
quoteName(fmd.columnName) + " = " + quoteName(fmd.columnName) + " + 1 "
quoteName(fmd.columnName) + " = " + quoteName(fmd.columnName) + " + 1 "
else
quoteName(fmd.columnName) + " = " + writeValue(o_, fmd, sw)
quoteName(fmd.columnName) + " = " + writeValue(o_, fmd, sw)
}),
","
)
Expand All @@ -500,7 +500,7 @@ trait DatabaseAdapter {
sw.indent

t.posoMetaData.primaryKey.getOrElse(error("writeUpdate was called on an object that does not extend from KeyedEntity[]")).fold(
pkMd => sw.write(quoteName(pkMd.columnName), " = ", writeValue(o_, pkMd, sw)),
pkMd => sw.write(quoteName(pkMd.columnName), " = ", writeValue(o_, pkMd, sw)),
pkGetter => {
val astOfQuery4WhereClause = Utils.createQuery4WhereClause(t, (t0:T) =>
pkGetter.invoke(t0).asInstanceOf[CompositeKey].buildEquality(o.asInstanceOf[KeyedEntity[CompositeKey]].id))
Expand All @@ -513,7 +513,7 @@ trait DatabaseAdapter {
if(checkOCC)
t.posoMetaData.optimisticCounter.foreach(occ => {
sw.write(" and ")
sw.write(quoteName(occ.columnName))
sw.write(quoteName(occ.columnName))
sw.write(" = ")
sw.write(writeValue(o_, occ, sw))
})
Expand All @@ -522,7 +522,7 @@ trait DatabaseAdapter {
def writeDelete[T](t: Table[T], whereClause: Option[ExpressionNode], sw: StatementWriter) = {

sw.write("delete from ")
sw.write(quoteName(t.prefixedName))
sw.write(quoteName(t.prefixedName))
if(whereClause != None) {
sw.nextLine
sw.write("where")
Expand Down Expand Up @@ -551,16 +551,18 @@ trait DatabaseAdapter {
val colsToUpdate = us.columns.iterator

sw.write("update ")
sw.write(quoteName(t.prefixedName))
sw.write(quoteName(t.prefixedName))
sw.write(" set")
sw.indent
sw.nextLine
for(z <- us.values.zipi) {
val col = colsToUpdate.next
sw.write(quoteName(col.columnName))
sw.write(quoteName(col.columnName))
sw.write(" = ")
val v = z.element
sw.write("(")
v.write(sw)
sw.write(")")
if(!z.isLast) {
sw.write(",")
sw.nextLine
Expand All @@ -571,9 +573,9 @@ trait DatabaseAdapter {
sw.write(",")
sw.nextLine
val occ = t.posoMetaData.optimisticCounter.get
sw.write(quoteName(occ.columnName))
sw.write(quoteName(occ.columnName))
sw.write(" = ")
sw.write(quoteName(occ.columnName) + " + 1")
sw.write(quoteName(occ.columnName) + " + 1")
}

sw.unindent
Expand Down Expand Up @@ -639,15 +641,15 @@ trait DatabaseAdapter {
val sb = new StringBuilder(256)

sb.append("alter table ")
sb.append(quoteName(foreignKeyTable.prefixedName))
sb.append(quoteName(foreignKeyTable.prefixedName))
sb.append(" add constraint ")
sb.append(quoteName(foreignKeyConstraintName(foreignKeyTable, fkId)))
sb.append(quoteName(foreignKeyConstraintName(foreignKeyTable, fkId)))
sb.append(" foreign key (")
sb.append(quoteName(foreignKeyColumnName))
sb.append(quoteName(foreignKeyColumnName))
sb.append(") references ")
sb.append(quoteName(primaryKeyTable.prefixedName))
sb.append(quoteName(primaryKeyTable.prefixedName))
sb.append("(")
sb.append(quoteName(primaryKeyColumnName))
sb.append(quoteName(primaryKeyColumnName))
sb.append(")")

val f = (ra:ReferentialAction) => {
Expand All @@ -667,7 +669,7 @@ trait DatabaseAdapter {
Session.currentSession

def writeDropForeignKeyStatement(foreignKeyTable: Table[_], fkName: String) =
"alter table " + quoteName(foreignKeyTable.prefixedName) + " drop constraint " + quoteName(fkName)
"alter table " + quoteName(foreignKeyTable.prefixedName) + " drop constraint " + quoteName(fkName)

def dropForeignKeyStatement(foreignKeyTable: Table[_], fkName: String, session: Session):Unit =
execFailSafeExecute(writeDropForeignKeyStatement(foreignKeyTable, fkName), e => true)
Expand All @@ -677,24 +679,24 @@ trait DatabaseAdapter {
def supportsForeignKeyConstraints = true

def writeDropTable(tableName: String) =
"drop table " + quoteName(tableName)
"drop table " + quoteName(tableName)

def dropTable(t: Table[_]) =
execFailSafeExecute(writeDropTable(t.prefixedName), e=> isTableDoesNotExistException(e))

def writeSelectElementAlias(se: SelectElement, sw: StatementWriter) =
sw.write(quoteName(se.alias))
sw.write(quoteName(se.alias))

def writeUniquenessConstraint(t: Table[_], cols: Iterable[FieldMetaData]) = {
//ALTER TABLE TEST ADD CONSTRAINT NAME_UNIQUE UNIQUE(NAME)
val sb = new StringBuilder(256)

sb.append("alter table ")
sb.append(quoteName(t.prefixedName))
sb.append(quoteName(t.prefixedName))
sb.append(" add constraint ")
sb.append(quoteName(t.prefixedName + "CPK"))
sb.append(quoteName(t.prefixedName + "CPK"))
sb.append(" unique(")
sb.append(cols.map(_.columnName).map(quoteName(_)).mkString(","))
sb.append(cols.map(_.columnName).map(quoteName(_)).mkString(","))
sb.append(")")
sb.toString
}
Expand Down Expand Up @@ -735,17 +737,17 @@ trait DatabaseAdapter {
val tableName = columnDefs.head.parentMetaData.viewOrTable.name

if(name != None)
sb.append(quoteName(name.get))
sb.append(quoteName(name.get))
else if(nameOfCompositeKey != None)
sb.append(quoteName("idx" + nameOfCompositeKey.get))
sb.append(quoteName("idx" + nameOfCompositeKey.get))
else
sb.append(quoteName("idx" + generateAlmostUniqueSuffixWithHash(tableName + "-" + columnDefs.map(_.columnName).mkString("-"))))
sb.append(quoteName("idx" + generateAlmostUniqueSuffixWithHash(tableName + "-" + columnDefs.map(_.columnName).mkString("-"))))

sb.append(" on ")

sb.append(quoteName(tableName))
sb.append(quoteName(tableName))

sb.append(columnDefs.map(_.columnName).map(quoteName(_)).mkString(" (",",",")"))
sb.append(columnDefs.map(_.columnName).map(quoteName(_)).mkString(" (",",",")"))

sb.toString
}
Expand All @@ -760,8 +762,8 @@ trait DatabaseAdapter {
a32.update(s.getBytes)
a32.getValue.toHexString
}

def quoteIdentifier(s: String) = s

def quoteName(s: String) = s.split('.').map(quoteIdentifier(_)).mkString(".")

def quoteIdentifier(s: String) = s

def quoteName(s: String) = s.split('.').map(quoteIdentifier(_)).mkString(".")
}
37 changes: 35 additions & 2 deletions src/test/scala/org/squeryl/tests/schooldb/SchoolDb.scala
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class Professor(var lastName: String, var yearlySalary: Float, var weight: Optio

var id: Long = 0
def this() = this("", 0.0F, Some(0.0F), 80.0F, Some(0))
override def toString = "Professor:" + id
override def toString = "Professor:" + id + ",sal=" + yearlySalary
}


Expand Down Expand Up @@ -289,7 +289,11 @@ class SchoolDbTestRun extends QueryTester {
testCountSignatures

blobTest


if(!Session.currentSession.databaseAdapter.isInstanceOf[MySQLAdapter]) {
testPartialUpdateWithSubQueryInSetClause
}

testYieldInspectionResidue

// testNewLeftOuterJoin1Reverse
Expand Down Expand Up @@ -975,6 +979,35 @@ class SchoolDbTestRun extends QueryTester {
passed('testPartialUpdateWithInclusionOperator)
}


def testPartialUpdateWithSubQueryInSetClause = {
//loggerOn

val zarnitsyn = professors.insert(new Professor("zarnitsyn", 60.0F, Some(70.5F), 60.0F, Some(70.5F)))

val before = professors.where(p => p.id === tournesol.id).single.yearlySalary

val expected:Float = from(professors)(p0=> where(tournesol.id === p0.id or p0.id === zarnitsyn.id) compute(nvl(avg(p0.yearlySalary), 123)))

val c = update(professors)(p =>
where(p.id === tournesol.id)
set(p.yearlySalary := from(professors)(p0=> where(p.id === p0.id or p0.id === zarnitsyn.id) compute(nvl(avg(p0.yearlySalary), 123))))
)

val after = professors.where(p => p.id === tournesol.id).single.yearlySalary

assertEquals(expected, after, 'testPartialUpdateWithSubQueryInSetClause)

update(professors)(p =>
where(p.id === tournesol.id)
set(p.yearlySalary := 80.0F)
)

professors.delete(zarnitsyn.id)

passed('testPartialUpdateWithSubQueryInSetClause)
}

def testOptimisticCC1 = {

Session.currentSession.connection.commit // we commit to release all locks
Expand Down

0 comments on commit e75ddec

Please sign in to comment.