diff --git a/.travis.yml b/.travis.yml index 3e1785403f..633598801e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,8 @@ dist: trusty sudo: false scala: - 2.11.12 - - 2.12.10 - - 2.13.1 + - 2.12.11 + - 2.13.2 cache: directories: - '$HOME/node_modules' @@ -15,16 +15,16 @@ jdk: - openjdk8 matrix: include: - - scala: 2.12.10 + - scala: 2.12.11 jdk: openjdk11 env: DISABLE_PUBLISH=true - - scala: 2.12.10 + - scala: 2.12.11 jdk: openjdk12 env: DISABLE_PUBLISH=true - - scala: 2.13.1 + - scala: 2.13.2 jdk: openjdk11 env: DISABLE_PUBLISH=true - - scala: 2.13.1 + - scala: 2.13.2 jdk: openjdk12 env: DISABLE_PUBLISH=true script: ./travis.sh diff --git a/build.sbt b/build.sbt index b16f06c942..1add661794 100644 --- a/build.sbt +++ b/build.sbt @@ -9,8 +9,8 @@ startYear in ThisBuild := Some(2006) organizationName in ThisBuild := "WorldWide Conferencing, LLC" val scala211Version = "2.11.12" -val scala212Version = "2.12.10" -val scala213Version = "2.13.1" +val scala212Version = "2.12.11" +val scala213Version = "2.13.2" val crossUpTo212 = Seq(scala212Version, scala211Version) val crossUpTo213 = scala213Version +: crossUpTo212 @@ -18,7 +18,9 @@ val crossUpTo213 = scala213Version +: crossUpTo212 scalaVersion in ThisBuild := scala212Version crossScalaVersions in ThisBuild := crossUpTo212 // default everyone to 2.12 for now -libraryDependencies in ThisBuild ++= Seq(specs2, specs2Matchers, specs2Mock, scalacheck, scalatest) +libraryDependencies in ThisBuild ++= Seq(specs2, specs2Matchers, specs2Mock, scalacheck, scalactic, scalatest) + +scalacOptions in ThisBuild ++= Seq("-deprecation") // Settings for Sonatype compliance pomIncludeRepository in ThisBuild := { _ => false } @@ -77,7 +79,7 @@ lazy val markdown = .settings( description := "Markdown Parser", parallelExecution in Test := false, - libraryDependencies ++= Seq(scalatest, junit, scala_xml, scala_parser) + libraryDependencies ++= Seq(scalatest, scalatest_junit, scala_xml, scala_parser) ) .settings(crossScalaVersions := crossUpTo213) @@ -160,7 +162,7 @@ lazy val webkit = specs2MatchersProv, jetty6, jwebunit, - mockito_all, + mockito_scalatest, jquery, jasmineCore, jasmineAjax @@ -216,7 +218,7 @@ lazy val persistence: Seq[ProjectReference] = lazy val db = persistenceProject("db") .dependsOn(util, webkit) - .settings(libraryDependencies += mockito_all) + .settings(libraryDependencies += mockito_scalatest) .settings(crossScalaVersions := crossUpTo213) lazy val proto = @@ -238,6 +240,7 @@ lazy val mapper = ) } ) + .settings(crossScalaVersions := crossUpTo213) lazy val record = persistenceProject("record") diff --git a/core/markdown/src/test/scala/net/liftweb/markdown/BaseParsersTest.scala b/core/markdown/src/test/scala/net/liftweb/markdown/BaseParsersTest.scala index 64fb96dcb0..ccc0e12efe 100644 --- a/core/markdown/src/test/scala/net/liftweb/markdown/BaseParsersTest.scala +++ b/core/markdown/src/test/scala/net/liftweb/markdown/BaseParsersTest.scala @@ -19,7 +19,7 @@ package net.liftweb.markdown * Christoph Henkelmann http://henkelmann.eu/ */ -import org.scalatest.junit.JUnitRunner +import org.scalatestplus.junit.JUnitRunner import org.scalatest.FlatSpec import org.scalatest.Matchers import collection.SortedMap @@ -71,4 +71,4 @@ class BaseParsersTest extends FlatSpec with Matchers with BaseParsers{ an [IllegalArgumentException] should be thrownBy(apply(p, "<")) } -} \ No newline at end of file +} diff --git a/core/markdown/src/test/scala/net/liftweb/markdown/BlockParsersTest.scala b/core/markdown/src/test/scala/net/liftweb/markdown/BlockParsersTest.scala index 4d239139c8..15ff828e11 100644 --- a/core/markdown/src/test/scala/net/liftweb/markdown/BlockParsersTest.scala +++ b/core/markdown/src/test/scala/net/liftweb/markdown/BlockParsersTest.scala @@ -20,7 +20,7 @@ package net.liftweb.markdown */ import org.junit.runner.RunWith -import org.scalatest.junit.JUnitRunner +import org.scalatestplus.junit.JUnitRunner import org.scalatest.{Matchers,FlatSpec} import scala.xml.{Group, NodeSeq} diff --git a/core/markdown/src/test/scala/net/liftweb/markdown/InlineParsersTest.scala b/core/markdown/src/test/scala/net/liftweb/markdown/InlineParsersTest.scala index acd2378c5f..96c69ccd45 100644 --- a/core/markdown/src/test/scala/net/liftweb/markdown/InlineParsersTest.scala +++ b/core/markdown/src/test/scala/net/liftweb/markdown/InlineParsersTest.scala @@ -22,7 +22,7 @@ package net.liftweb.markdown import org.scalatest.FlatSpec import org.scalatest.Matchers import org.junit.runner.RunWith -import org.scalatest.junit.JUnitRunner +import org.scalatestplus.junit.JUnitRunner /** * Tests Inline Parsing, i.e. emphasis , strong text, links, escapes etc. diff --git a/core/markdown/src/test/scala/net/liftweb/markdown/LineParsersTest.scala b/core/markdown/src/test/scala/net/liftweb/markdown/LineParsersTest.scala index 4ab214944a..968635d740 100644 --- a/core/markdown/src/test/scala/net/liftweb/markdown/LineParsersTest.scala +++ b/core/markdown/src/test/scala/net/liftweb/markdown/LineParsersTest.scala @@ -21,7 +21,7 @@ package net.liftweb.markdown import org.scalatest.{Matchers,FlatSpec} import org.junit.runner.RunWith -import org.scalatest.junit.JUnitRunner +import org.scalatestplus.junit.JUnitRunner /** * tests parsing of individual lines diff --git a/core/markdown/src/test/scala/net/liftweb/markdown/LineTokenizerTest.scala b/core/markdown/src/test/scala/net/liftweb/markdown/LineTokenizerTest.scala index e22b667f21..6399f797b7 100644 --- a/core/markdown/src/test/scala/net/liftweb/markdown/LineTokenizerTest.scala +++ b/core/markdown/src/test/scala/net/liftweb/markdown/LineTokenizerTest.scala @@ -21,7 +21,7 @@ package net.liftweb.markdown import org.scalatest.{Matchers,FlatSpec} import org.junit.runner.RunWith -import org.scalatest.junit.JUnitRunner +import org.scalatestplus.junit.JUnitRunner /** * Tests the Line Tokenizer that prepares input for parsing. diff --git a/core/markdown/src/test/scala/net/liftweb/markdown/TransformerTest.scala b/core/markdown/src/test/scala/net/liftweb/markdown/TransformerTest.scala index 3e7d29baf5..b0a613e3fb 100644 --- a/core/markdown/src/test/scala/net/liftweb/markdown/TransformerTest.scala +++ b/core/markdown/src/test/scala/net/liftweb/markdown/TransformerTest.scala @@ -21,7 +21,7 @@ package net.liftweb.markdown import org.scalatest.{Matchers,FlatSpec} import org.junit.runner.RunWith -import org.scalatest.junit.JUnitRunner +import org.scalatestplus.junit.JUnitRunner /** * Tests the behavior of the complete parser, i.e. all parsing steps together. diff --git a/persistence/db/src/test/scala/net/liftweb/db/DBSpec.scala b/persistence/db/src/test/scala/net/liftweb/db/DBSpec.scala index dab759ad4c..29aae14f61 100644 --- a/persistence/db/src/test/scala/net/liftweb/db/DBSpec.scala +++ b/persistence/db/src/test/scala/net/liftweb/db/DBSpec.scala @@ -19,12 +19,10 @@ package db import org.specs2.mutable.Specification import org.specs2.mock.Mockito -import org.mockito.Matchers._ -import net.liftweb.common._ -import net.liftweb.db._ -import net.liftweb.util.DefaultConnectionIdentifier -import net.liftweb.util.ControlHelpers._ +import common._ +import util.DefaultConnectionIdentifier +import util.ControlHelpers._ import java.sql._ @@ -35,8 +33,8 @@ class DBSpec extends Specification with Mockito { def f(success: Boolean): Unit } - def dBVendor(connection: Connection) = new ProtoDBVendor { - def createOne = { + def dBVendor(connection: Connection): ProtoDBVendor = new ProtoDBVendor { + def createOne: Box[Connection] = { connection.createStatement returns mock[PreparedStatement] Full(connection) } diff --git a/persistence/mapper/src/main/scala-2.11/net/liftweb/mapper/FieldFinder.scala b/persistence/mapper/src/main/scala-2.11/net/liftweb/mapper/FieldFinder.scala new file mode 100644 index 0000000000..7736b1c190 --- /dev/null +++ b/persistence/mapper/src/main/scala-2.11/net/liftweb/mapper/FieldFinder.scala @@ -0,0 +1,107 @@ +/* + * Copyright 2006-2011 WorldWide Conferencing, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.liftweb +package mapper + +import scala.reflect.{ClassTag, classTag} + +class FieldFinder[T: ClassTag](metaMapper: AnyRef, logger: common.Logger) { + + import java.lang.reflect._ + + logger.debug("Created FieldFinder for " + classTag[T].runtimeClass) + + def isMagicObject(m: Method): Boolean = m.getReturnType.getName.endsWith("$" + m.getName + "$") && m.getParameterTypes.length == 0 + + def typeFilter: Class[_] => Boolean = classTag[T].runtimeClass.isAssignableFrom + + /** + * Find the magic mapper fields on the superclass + */ + def findMagicFields(onMagic: AnyRef, startingClass: Class[_]): List[Method] = { + // If a class name ends in $module, it's a subclass created for scala object instances + def deMod(in: String): String = + if (in.endsWith("$module")) in.substring(0, in.length - 7) + else in + + // find the magic fields for the given superclass + def findForClass(clz: Class[_]): List[Method] = clz match { + case null => Nil + case c => + // get the names of fields that represent the type we want + + val fields = Map(c.getDeclaredFields + .filter { f => + val ret = typeFilter(f.getType) + logger.trace("typeFilter(" + f.getType + "); T=" + classTag[T].runtimeClass) + ret + } + .map(f => (deMod(f.getName), f)): _*) + + logger.trace("fields: " + fields) + + // this method will find all the super classes and super-interfaces + def getAllSupers(clz: Class[_]): List[Class[_]] = clz match { + case null => Nil + case c => + c :: c.getInterfaces.toList.flatMap(getAllSupers) ::: + getAllSupers(c.getSuperclass) + } + + // does the method return an actual instance of an actual class that's + // associated with this Mapper class + def validActualType(meth: Method): Boolean = { + try { + // invoke the method + meth.invoke(onMagic) match { + case null => + logger.debug("Not a valid mapped field: %s".format(meth.getName)) + false + case inst => + // do we get a T of some sort back? + if (!typeFilter(inst.getClass)) false + else { + // find out if the class name of the actual thing starts + // with the name of this class or some superclass... + // basically, is an inner class of this class + getAllSupers(clz).exists(c => inst.getClass.getName.startsWith(c.getName)) + } + } + + } catch { + case e: Exception => + logger.debug("Not a valid mapped field: %s, got exception: %s".format(meth.getName, e)) + false + } + } + + // find all the declared methods + val meths = c.getDeclaredMethods.toList. + filter(_.getParameterTypes.length == 0). // that take no parameters + filter(m => Modifier.isPublic(m.getModifiers)). // that are public + filter(m => fields.contains(m.getName) && // that are associated with private fields + fields(m.getName).getType == m.getReturnType). + filter(validActualType) // and have a validated type + + meths ::: findForClass(clz.getSuperclass) + } + + findForClass(startingClass).distinct + } + + lazy val accessorMethods = findMagicFields(metaMapper, metaMapper.getClass.getSuperclass) +} diff --git a/persistence/mapper/src/main/scala-2.11/net/liftweb/mapper/ManyToMany.scala b/persistence/mapper/src/main/scala-2.11/net/liftweb/mapper/ManyToMany.scala new file mode 100644 index 0000000000..441612eceb --- /dev/null +++ b/persistence/mapper/src/main/scala-2.11/net/liftweb/mapper/ManyToMany.scala @@ -0,0 +1,217 @@ +package net.liftweb +package mapper + +import common.{Empty, Full} + +import scala.annotation.tailrec + +/** + * Add this trait to a Mapper to add support for many-to-many relationships + * + * @author nafg + */ +trait ManyToMany extends BaseKeyedMapper { + this: KeyedMapper[_, _] => + + private[this] type K = TheKeyType + private[this] type T = KeyedMapperType + + private var manyToManyFields: List[MappedManyToMany[_,_,_]] = Nil + + /** + * An override for save to propagate the save to all children + * of this parent. + * Returns false as soon as the parent or a one-to-many field returns false. + * If they are all successful returns true. + */ + abstract override def save: Boolean = { + super.save && manyToManyFields.forall(_.save) + } + + /** + * An override for delete_! to propogate the deletion to all children + * of this parent. + * Returns false as soon as the parent or a one-to-many field returns false. + * If they are all successful returns true. + */ + abstract override def delete_! : Boolean = { + super.delete_! && + manyToManyFields.forall( _.delete_!) + } + + + /** + * This is the base class to extend for fields that track many-to-many relationships. + * @param joinMeta The singleton of the join table + * @param thisField The foreign key in the join table that refers to this mapper's primaryKey. + * @param otherField The foreign key in the join table that refers to the other mapper's primaryKey + * @param otherMeta The singleton of the other mapper + * @param qp Any QueryParams to limit entries in the join table (other than matching thisField to primaryKey) + * To limit children based on fields in the other table (not the join table), it is currently necessary + * to point the join mapper to a view which pulls the join table's fields as well as fields of the other table. + */ + class MappedManyToMany[O<:Mapper[O], K2, T2 <: KeyedMapper[K2,T2]]( + val joinMeta: MetaMapper[O], + thisField: MappedForeignKey[K,O,_ <: KeyedMapper[_,_]], + val otherField: MappedForeignKey[K2, O, T2], + val otherMeta: MetaMapper[T2], + val qp: QueryParam[O]*) extends scala.collection.mutable.Buffer[T2] { + + def otherFK[A](join: O)(f: MappedForeignKey[K2,O,T2] => A): A = + otherField.actualField(join) match { case mfk: MappedForeignKey[K2,O,T2] => f(mfk) } + + protected def children: List[T2] = joins.flatMap(otherFK(_)(_.obj)) + + protected var _joins: List[O] = _ + + /** + * Get the list of instances of joinMeta + */ + def joins: List[O] = _joins // read only to the public + protected var removedJoins: List[O] = Nil + + refresh + manyToManyFields ::= this + + protected def isJoinForChild(e: T2)(join: O): Boolean = otherField.actualField(join).get == e.primaryKeyField.get + + protected def joinForChild(e: T2): Option[O] = joins.find(isJoinForChild(e)) + + protected def own(e: T2): O = { + joinForChild(e).fold { + removedJoins + // first check if we can recycle a removed join + .find(otherField.actualField(_).get == e.primaryKeyField) + .fold{ + val newJoin = joinMeta.create + thisField.actualField(newJoin) match { + case mfk: MappedForeignKey[K, O, T] => mfk.set(primaryKeyField.get.asInstanceOf[K]) + } + otherFK(newJoin)(_.apply(e)) + newJoin + }{ removedJoin => + removedJoins = removedJoins filter removedJoin.ne + removedJoin // well, noLongerRemovedJoin... + } + }(join => join) + } + + protected def unown(e: T2): Option[O] = + joinForChild(e).map{ join => + removedJoins = join :: removedJoins + val o = otherField.actualField(join) + o.set(o.defaultValue) + thisField.actualField(join) match { case mfk => mfk set mfk.defaultValue } + join + } + + /** + * Get the List backing this Buffer. + */ + def all: List[T2] = children + + def length: Int = children.length + + def iterator: Iterator[T2] = children.iterator + + protected def childAt(n: Int): T2 = children(n) + def apply(n: Int): T2 = childAt(n) + def indexOf(e: T2): Int = children.indexWhere(e.eq) + + def insertAll(n: Int, traversable: Traversable[T2]) { + val ownedJoins = traversable map own + val n2 = joins.indexWhere(isJoinForChild(children(n))) + val before = joins.take(n2) + val after = joins.drop(n2) + + _joins = before ++ ownedJoins ++ after + } + + def +=:(elem: T2): MappedManyToMany.this.type = { + _joins ::= own(elem) + this + } + + def +=(elem: T2): MappedManyToMany.this.type = { + _joins ++= List(own(elem)) + this + } + + def update(n: Int, newelem: T2): Unit = { + unown(childAt(n)) match { + case Some(join) => + val n2 = joins.indexOf(join) + val (before, after) = (joins.take(n2), joins.drop(n2+1)) + _joins = before ++ List(own(newelem)) ++ after + case None => + } + } + + def remove(n: Int): T2 = { + val child = childAt(n) + unown(child).foreach(join => _joins = joins filterNot join.eq) + child + } + + override def remove(idx: Int, count: Int): Unit = { + if (count > 0) { + @tailrec + def loop(c: Int, a: List[T2]): List[T2] = + if (c == 0) childAt(idx) :: a + else loop(c - 1, childAt(idx + c) :: a) + + val joins0 = loop(count - 1, Nil) flatMap unown + _joins = joins filterNot joins0.contains + } + } + + def clear(): Unit = { + children foreach unown + _joins = Nil + } + + /** + * Discard the cached state of this MappedManyToMany's children and reinitialize it from the database + */ + def refresh: List[T2] = { + val by = new Cmp[O, TheKeyType](thisField, OprEnum.Eql, Full(primaryKeyField.get.asInstanceOf[K]), Empty, Empty) + + _joins = joinMeta.findAll( (by :: qp.toList): _*) + all + } + + /** + * Save the state of this MappedManyToMany to the database. + * This will do the following: + * 1) Prune join table instances whose "child" foreign key's value is its defaultValue, i.e., -1 + * 2) Set all join table instances' "parent" foreign key + * 3) Delete all join table instances whose child instance was removed + * 4) Save all child instances + * 5) If step 3 succeeds save all join instances + * 6) Return true if steps 2-4 all returned true; otherwise false + */ + def save: Boolean = { + _joins = joins.filter { join => + otherFK(join)(f => f.get != f.defaultValue) + } + _joins foreach { + thisField.actualField(_).asInstanceOf[MappedForeignKey[K,O,X] forSome {type X <: KeyedMapper[K,X]}] set ManyToMany.this.primaryKeyField.get.asInstanceOf[K] + } + + removedJoins.forall {_.delete_!} & ( // continue saving even if deleting fails + children.forall(_.save) && + joins.forall(_.save) + ) + } + + /** + * Deletes all join rows, including those + * marked for removal. + * Returns true if both succeed, otherwise false + */ + def delete_! : Boolean = { + removedJoins.forall(_.delete_!) & + joins.forall(_.delete_!) + } + } +} diff --git a/persistence/mapper/src/main/scala-2.11/net/liftweb/mapper/OneToMany.scala b/persistence/mapper/src/main/scala-2.11/net/liftweb/mapper/OneToMany.scala new file mode 100644 index 0000000000..b959516f7d --- /dev/null +++ b/persistence/mapper/src/main/scala-2.11/net/liftweb/mapper/OneToMany.scala @@ -0,0 +1,284 @@ +/* + * Copyright 2006-2011 WorldWide Conferencing, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.liftweb +package mapper + + +private[mapper] object RecursiveType { + val rec: { type R0 <: Mapper[R0] } = null + type Rec = rec.R0 +} +import net.liftweb.mapper.RecursiveType._ + +/** + * Add this trait to a Mapper for managed one-to-many support + * For example: class Contact extends LongKeyedMapper[Contact] with OneToMany[Long, Contact] { ... } + * @tparam K the type of the primary key + * @tparam T the mapper type + * @author nafg + */ +trait OneToMany[K,T<:KeyedMapper[K, T]] extends KeyedMapper[K,T] { this: T => + + private[mapper] lazy val oneToManyFields: List[MappedOneToManyBase[Rec]] = { + new FieldFinder[MappedOneToManyBase[Rec]]( + getSingleton, + net.liftweb.common.Logger(classOf[OneToMany[K,T]]) + ).accessorMethods map (_.invoke(this).asInstanceOf[MappedOneToManyBase[Rec]]) + } + + /** + * An override for save to propagate the save to all children + * of this parent. + * Returns false as soon as the parent or a one-to-many field returns false. + * If they are all successful returns true. + */ + override def save: Boolean = { + val ret = super.save && + oneToManyFields.forall(_.save) + ret + } + + /** + * An override for delete_! to propagate the deletion + * to all children of one-to-many fields implementing Cascade. + * Returns false as soon as the parent or a one-to-many field returns false. + * If they are all successful returns true. + */ + override def delete_! : Boolean = DB.use(connectionIdentifier){ _ => + if(oneToManyFields.forall{(_: MappedOneToManyBase[_ <: Mapper[_]]) match { + case f: Cascade[_] => f.delete_! + case _ => true + } + }) + super.delete_! + else { + DB.rollback(connectionIdentifier) + false + } + } + + + /** + * This implicit allows a MappedForeignKey to be used as foreignKey function. + * Returns a function that takes a Mapper and looks up the actualField of field on the Mapper. + */ + implicit def foreignKey[K, O<:Mapper[O], T<:KeyedMapper[K,T]](field: MappedForeignKey[K,O,T]): O=>MappedForeignKey[K,O,T] = + field.actualField(_).asInstanceOf[MappedForeignKey[K,O,T]] + + /** + * Simple OneToMany support for children from the same table + */ + class MappedOneToMany[O <: Mapper[O]](meta: MetaMapper[O], foreign: MappedForeignKey[K,O,T], qp: QueryParam[O]*) + extends MappedOneToManyBase[O]( + ()=>{ + val ret = meta.findAll(By(foreign, primaryKeyField.get) :: qp.toList : _*) + for(child <- ret) { + foreign.actualField(child).asInstanceOf[MappedForeignKey[K,O,T]].primeObj(net.liftweb.common.Full(OneToMany.this : T)) + } + ret + }, + foreign + ) + + /** + * This is the base class to use for fields that represent one-to-many or parent-child relationships. + * Maintains a list of children, tracking pending additions and deletions, and + * keeping their foreign key pointed to this mapper. + * Implements Buffer, so the children can be managed as one. + * Most users will use MappedOneToMany, however to support children from multiple tables + * it is necessary to use MappedOneToManyBase. + * @param reloadFunc A function that returns a sequence of children from storage. + * @param foreign A function that gets the MappedForeignKey on the child that refers to this parent + */ + class MappedOneToManyBase[O <: Mapper[_]](val reloadFunc: () => Seq[O], + val foreign: O => MappedForeignKey[K,_,T]) extends scala.collection.mutable.Buffer[O] { + private var inited = false + private var _delegate: List[O] = _ + /** + * children that were added before the parent was ever saved + */ + private var unlinked: List[O] = Nil + protected def delegate: List[O] = { + if(!inited) { + refresh() + inited = true + } + _delegate + } + protected def delegate_=(d: List[O]): Unit = _delegate = d + + /** + * Takes ownership of e. Sets e's foreign key to our primary key + */ + protected def own(e: O): O = { + val f0 = foreign(e).asInstanceOf[Any] + f0 match { + case f: MappedLongForeignKey[O,T] with MappedForeignKey[K,_,T] => + f.apply(OneToMany.this) + case f: MappedForeignKey[K,_,T] => + f.set(OneToMany.this.primaryKeyField.get) + } + if(!OneToMany.this.saved_?) + unlinked ::= e + e + } + /** + * Relinquishes ownership of e. Resets e's foreign key to its default value. + */ + protected def unown(e: O): O = { + val f = foreign(e) + f.set(f.defaultValue) + unlinked = unlinked filter {e.ne} + e + } + /** + * Returns the backing List + */ + def all: List[O] = delegate + + // 2.8: return this + def +=(elem: O): MappedOneToManyBase.this.type = { + delegate = delegate ++ List(own(elem)) + this + } + // 2.7 + //def readOnly = all + def length: Int = delegate.length + // 2.7 + //def elements = delegate.elements + // 2.8 + def iterator: Iterator[O] = delegate.iterator + + def apply(n: Int): O = delegate(n) + + // 2.7 + /* def +:(elem: O) = { + delegate ::= own(elem) + this + } */ + // 2.8 + def +=:(elem: O): MappedOneToManyBase.this.type = { + delegate ::= own(elem) + this + } + + override def indexOf[B >: O](e: B): Int = delegate.indexWhere(e.asInstanceOf[AnyRef].eq) + + // 2.7 + // def insertAll(n: Int, iter: Iterable[O]) { + // 2.8 + def insertAll(n: Int, iter: Traversable[O]) { + val (before, after) = delegate.splitAt(n) + iter foreach own + delegate = before ++ iter ++ after + } + + def update(n: Int, newelem: O): Unit = { + unown(delegate(n)) + delegate = delegate.take(n) ++ List(own(newelem)) ++ delegate.drop(n+1) + } + + def remove(n: Int): O = { + val e = unown(delegate(n)) + delegate = delegate.filterNot(e.eq) + e + } + + def clear(): Unit = { + while(delegate.nonEmpty) + remove(0) + } + + /** + * Reloads the children from storage. + * NOTE: This may leave children in an inconsistent state. + * It is recommended to call save or clear() before calling refresh. + */ + def refresh(): Unit = { + delegate = reloadFunc().toList + if(saved_?) + unlinked = Nil + else + unlinked = _delegate + } + + /** + * Saves this "field," i.e., all the children it represents. + * Returns false as soon as save on a child returns false. + * Returns true if all children were saved successfully. + */ + def save: Boolean = { + unlinked foreach {u => + val f = foreign(u) + if(f.obj.map(_ eq OneToMany.this) openOr true) // obj is Empty or this + f.apply(OneToMany.this) + } + unlinked = Nil + delegate = delegate.filter {e => + foreign(e).get == OneToMany.this.primaryKeyField.get || + foreign(e).obj.map(_ eq OneToMany.this).openOr(false) // obj is this but not Empty + } + delegate.forall(_.save) + } + + override def toString: String = { + val c = getClass.getSimpleName + val l = c.lastIndexOf("$") + c.substring(c.lastIndexOf("$",l-1)+1, l) + delegate.mkString("[",", ","]") + } + } + + /** + * Adds behavior to delete orphaned fields before save. + */ + trait Owned[O<:Mapper[_]] extends MappedOneToManyBase[O] { + var removed: List[O] = Nil + override def unown(e: O) = { + removed = e :: removed + super.unown(e) + } + override def own(e: O) = { + removed = removed filter {e.ne} + super.own(e) + } + override def save: Boolean = { + val unowned = removed.filter{ e => + val f = foreign(e) + f.get == f.defaultValue + } + unowned foreach {_.delete_!} + super.save + } + } + + /** + * Trait that indicates that the children represented + * by this field should be deleted when the parent is deleted. + */ + trait Cascade[O<:Mapper[_]] extends MappedOneToManyBase[O] { + def delete_! : Boolean = { + delegate.forall { e => + if(foreign(e).get == + OneToMany.this.primaryKeyField.get) { + e.delete_! + } + else + true // doesn't constitute a failure + } + } + } +} diff --git a/persistence/mapper/src/main/scala-2.12/net/liftweb/mapper/FieldFinder.scala b/persistence/mapper/src/main/scala-2.12/net/liftweb/mapper/FieldFinder.scala new file mode 100644 index 0000000000..7736b1c190 --- /dev/null +++ b/persistence/mapper/src/main/scala-2.12/net/liftweb/mapper/FieldFinder.scala @@ -0,0 +1,107 @@ +/* + * Copyright 2006-2011 WorldWide Conferencing, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.liftweb +package mapper + +import scala.reflect.{ClassTag, classTag} + +class FieldFinder[T: ClassTag](metaMapper: AnyRef, logger: common.Logger) { + + import java.lang.reflect._ + + logger.debug("Created FieldFinder for " + classTag[T].runtimeClass) + + def isMagicObject(m: Method): Boolean = m.getReturnType.getName.endsWith("$" + m.getName + "$") && m.getParameterTypes.length == 0 + + def typeFilter: Class[_] => Boolean = classTag[T].runtimeClass.isAssignableFrom + + /** + * Find the magic mapper fields on the superclass + */ + def findMagicFields(onMagic: AnyRef, startingClass: Class[_]): List[Method] = { + // If a class name ends in $module, it's a subclass created for scala object instances + def deMod(in: String): String = + if (in.endsWith("$module")) in.substring(0, in.length - 7) + else in + + // find the magic fields for the given superclass + def findForClass(clz: Class[_]): List[Method] = clz match { + case null => Nil + case c => + // get the names of fields that represent the type we want + + val fields = Map(c.getDeclaredFields + .filter { f => + val ret = typeFilter(f.getType) + logger.trace("typeFilter(" + f.getType + "); T=" + classTag[T].runtimeClass) + ret + } + .map(f => (deMod(f.getName), f)): _*) + + logger.trace("fields: " + fields) + + // this method will find all the super classes and super-interfaces + def getAllSupers(clz: Class[_]): List[Class[_]] = clz match { + case null => Nil + case c => + c :: c.getInterfaces.toList.flatMap(getAllSupers) ::: + getAllSupers(c.getSuperclass) + } + + // does the method return an actual instance of an actual class that's + // associated with this Mapper class + def validActualType(meth: Method): Boolean = { + try { + // invoke the method + meth.invoke(onMagic) match { + case null => + logger.debug("Not a valid mapped field: %s".format(meth.getName)) + false + case inst => + // do we get a T of some sort back? + if (!typeFilter(inst.getClass)) false + else { + // find out if the class name of the actual thing starts + // with the name of this class or some superclass... + // basically, is an inner class of this class + getAllSupers(clz).exists(c => inst.getClass.getName.startsWith(c.getName)) + } + } + + } catch { + case e: Exception => + logger.debug("Not a valid mapped field: %s, got exception: %s".format(meth.getName, e)) + false + } + } + + // find all the declared methods + val meths = c.getDeclaredMethods.toList. + filter(_.getParameterTypes.length == 0). // that take no parameters + filter(m => Modifier.isPublic(m.getModifiers)). // that are public + filter(m => fields.contains(m.getName) && // that are associated with private fields + fields(m.getName).getType == m.getReturnType). + filter(validActualType) // and have a validated type + + meths ::: findForClass(clz.getSuperclass) + } + + findForClass(startingClass).distinct + } + + lazy val accessorMethods = findMagicFields(metaMapper, metaMapper.getClass.getSuperclass) +} diff --git a/persistence/mapper/src/main/scala-2.12/net/liftweb/mapper/ManyToMany.scala b/persistence/mapper/src/main/scala-2.12/net/liftweb/mapper/ManyToMany.scala new file mode 100644 index 0000000000..441612eceb --- /dev/null +++ b/persistence/mapper/src/main/scala-2.12/net/liftweb/mapper/ManyToMany.scala @@ -0,0 +1,217 @@ +package net.liftweb +package mapper + +import common.{Empty, Full} + +import scala.annotation.tailrec + +/** + * Add this trait to a Mapper to add support for many-to-many relationships + * + * @author nafg + */ +trait ManyToMany extends BaseKeyedMapper { + this: KeyedMapper[_, _] => + + private[this] type K = TheKeyType + private[this] type T = KeyedMapperType + + private var manyToManyFields: List[MappedManyToMany[_,_,_]] = Nil + + /** + * An override for save to propagate the save to all children + * of this parent. + * Returns false as soon as the parent or a one-to-many field returns false. + * If they are all successful returns true. + */ + abstract override def save: Boolean = { + super.save && manyToManyFields.forall(_.save) + } + + /** + * An override for delete_! to propogate the deletion to all children + * of this parent. + * Returns false as soon as the parent or a one-to-many field returns false. + * If they are all successful returns true. + */ + abstract override def delete_! : Boolean = { + super.delete_! && + manyToManyFields.forall( _.delete_!) + } + + + /** + * This is the base class to extend for fields that track many-to-many relationships. + * @param joinMeta The singleton of the join table + * @param thisField The foreign key in the join table that refers to this mapper's primaryKey. + * @param otherField The foreign key in the join table that refers to the other mapper's primaryKey + * @param otherMeta The singleton of the other mapper + * @param qp Any QueryParams to limit entries in the join table (other than matching thisField to primaryKey) + * To limit children based on fields in the other table (not the join table), it is currently necessary + * to point the join mapper to a view which pulls the join table's fields as well as fields of the other table. + */ + class MappedManyToMany[O<:Mapper[O], K2, T2 <: KeyedMapper[K2,T2]]( + val joinMeta: MetaMapper[O], + thisField: MappedForeignKey[K,O,_ <: KeyedMapper[_,_]], + val otherField: MappedForeignKey[K2, O, T2], + val otherMeta: MetaMapper[T2], + val qp: QueryParam[O]*) extends scala.collection.mutable.Buffer[T2] { + + def otherFK[A](join: O)(f: MappedForeignKey[K2,O,T2] => A): A = + otherField.actualField(join) match { case mfk: MappedForeignKey[K2,O,T2] => f(mfk) } + + protected def children: List[T2] = joins.flatMap(otherFK(_)(_.obj)) + + protected var _joins: List[O] = _ + + /** + * Get the list of instances of joinMeta + */ + def joins: List[O] = _joins // read only to the public + protected var removedJoins: List[O] = Nil + + refresh + manyToManyFields ::= this + + protected def isJoinForChild(e: T2)(join: O): Boolean = otherField.actualField(join).get == e.primaryKeyField.get + + protected def joinForChild(e: T2): Option[O] = joins.find(isJoinForChild(e)) + + protected def own(e: T2): O = { + joinForChild(e).fold { + removedJoins + // first check if we can recycle a removed join + .find(otherField.actualField(_).get == e.primaryKeyField) + .fold{ + val newJoin = joinMeta.create + thisField.actualField(newJoin) match { + case mfk: MappedForeignKey[K, O, T] => mfk.set(primaryKeyField.get.asInstanceOf[K]) + } + otherFK(newJoin)(_.apply(e)) + newJoin + }{ removedJoin => + removedJoins = removedJoins filter removedJoin.ne + removedJoin // well, noLongerRemovedJoin... + } + }(join => join) + } + + protected def unown(e: T2): Option[O] = + joinForChild(e).map{ join => + removedJoins = join :: removedJoins + val o = otherField.actualField(join) + o.set(o.defaultValue) + thisField.actualField(join) match { case mfk => mfk set mfk.defaultValue } + join + } + + /** + * Get the List backing this Buffer. + */ + def all: List[T2] = children + + def length: Int = children.length + + def iterator: Iterator[T2] = children.iterator + + protected def childAt(n: Int): T2 = children(n) + def apply(n: Int): T2 = childAt(n) + def indexOf(e: T2): Int = children.indexWhere(e.eq) + + def insertAll(n: Int, traversable: Traversable[T2]) { + val ownedJoins = traversable map own + val n2 = joins.indexWhere(isJoinForChild(children(n))) + val before = joins.take(n2) + val after = joins.drop(n2) + + _joins = before ++ ownedJoins ++ after + } + + def +=:(elem: T2): MappedManyToMany.this.type = { + _joins ::= own(elem) + this + } + + def +=(elem: T2): MappedManyToMany.this.type = { + _joins ++= List(own(elem)) + this + } + + def update(n: Int, newelem: T2): Unit = { + unown(childAt(n)) match { + case Some(join) => + val n2 = joins.indexOf(join) + val (before, after) = (joins.take(n2), joins.drop(n2+1)) + _joins = before ++ List(own(newelem)) ++ after + case None => + } + } + + def remove(n: Int): T2 = { + val child = childAt(n) + unown(child).foreach(join => _joins = joins filterNot join.eq) + child + } + + override def remove(idx: Int, count: Int): Unit = { + if (count > 0) { + @tailrec + def loop(c: Int, a: List[T2]): List[T2] = + if (c == 0) childAt(idx) :: a + else loop(c - 1, childAt(idx + c) :: a) + + val joins0 = loop(count - 1, Nil) flatMap unown + _joins = joins filterNot joins0.contains + } + } + + def clear(): Unit = { + children foreach unown + _joins = Nil + } + + /** + * Discard the cached state of this MappedManyToMany's children and reinitialize it from the database + */ + def refresh: List[T2] = { + val by = new Cmp[O, TheKeyType](thisField, OprEnum.Eql, Full(primaryKeyField.get.asInstanceOf[K]), Empty, Empty) + + _joins = joinMeta.findAll( (by :: qp.toList): _*) + all + } + + /** + * Save the state of this MappedManyToMany to the database. + * This will do the following: + * 1) Prune join table instances whose "child" foreign key's value is its defaultValue, i.e., -1 + * 2) Set all join table instances' "parent" foreign key + * 3) Delete all join table instances whose child instance was removed + * 4) Save all child instances + * 5) If step 3 succeeds save all join instances + * 6) Return true if steps 2-4 all returned true; otherwise false + */ + def save: Boolean = { + _joins = joins.filter { join => + otherFK(join)(f => f.get != f.defaultValue) + } + _joins foreach { + thisField.actualField(_).asInstanceOf[MappedForeignKey[K,O,X] forSome {type X <: KeyedMapper[K,X]}] set ManyToMany.this.primaryKeyField.get.asInstanceOf[K] + } + + removedJoins.forall {_.delete_!} & ( // continue saving even if deleting fails + children.forall(_.save) && + joins.forall(_.save) + ) + } + + /** + * Deletes all join rows, including those + * marked for removal. + * Returns true if both succeed, otherwise false + */ + def delete_! : Boolean = { + removedJoins.forall(_.delete_!) & + joins.forall(_.delete_!) + } + } +} diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/OneToMany.scala b/persistence/mapper/src/main/scala-2.12/net/liftweb/mapper/OneToMany.scala similarity index 85% rename from persistence/mapper/src/main/scala/net/liftweb/mapper/OneToMany.scala rename to persistence/mapper/src/main/scala-2.12/net/liftweb/mapper/OneToMany.scala index bde7eedb49..d31e6a93f0 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/OneToMany.scala +++ b/persistence/mapper/src/main/scala-2.12/net/liftweb/mapper/OneToMany.scala @@ -22,7 +22,7 @@ private[mapper] object RecursiveType { val rec: { type R0 <: Mapper[R0] } = null type Rec = rec.R0 } -import RecursiveType._ +import net.liftweb.mapper.RecursiveType._ /** * Add this trait to a Mapper for managed one-to-many support @@ -46,7 +46,7 @@ trait OneToMany[K,T<:KeyedMapper[K, T]] extends KeyedMapper[K,T] { this: T => * Returns false as soon as the parent or a one-to-many field returns false. * If they are all successful returns true. */ - override def save = { + override def save: Boolean = { val ret = super.save && oneToManyFields.forall(_.save) ret @@ -58,7 +58,7 @@ trait OneToMany[K,T<:KeyedMapper[K, T]] extends KeyedMapper[K,T] { this: T => * Returns false as soon as the parent or a one-to-many field returns false. * If they are all successful returns true. */ - override def delete_! = DB.use(connectionIdentifier){_ => + override def delete_! : Boolean = DB.use(connectionIdentifier){ _ => if(oneToManyFields.forall{(_: MappedOneToManyBase[_ <: Mapper[_]]) match { case f: Cascade[_] => f.delete_! case _ => true @@ -104,8 +104,8 @@ trait OneToMany[K,T<:KeyedMapper[K, T]] extends KeyedMapper[K,T] { this: T => * @param reloadFunc A function that returns a sequence of children from storage. * @param foreign A function that gets the MappedForeignKey on the child that refers to this parent */ - class MappedOneToManyBase[O <: Mapper[_]](val reloadFunc: ()=>Seq[O], - val foreign: O => MappedForeignKey[K,_,T] /*forSome { type X <: Mapper[X] }*/) extends scala.collection.mutable.Buffer[O] { + class MappedOneToManyBase[O <: Mapper[_]](val reloadFunc: () => Seq[O], + val foreign: O => MappedForeignKey[K,_,T]) extends scala.collection.mutable.Buffer[O] { private var inited = false private var _delegate: List[O] = _ /** @@ -114,17 +114,17 @@ trait OneToMany[K,T<:KeyedMapper[K, T]] extends KeyedMapper[K,T] { this: T => private var unlinked: List[O] = Nil protected def delegate: List[O] = { if(!inited) { - refresh + refresh() inited = true } _delegate } - protected def delegate_=(d: List[O]) = _delegate = d + protected def delegate_=(d: List[O]): Unit = _delegate = d /** * Takes ownership of e. Sets e's foreign key to our primary key */ - protected def own(e: O) = { + protected def own(e: O): O = { val f0 = foreign(e).asInstanceOf[Any] f0 match { case f: MappedLongForeignKey[O,T] with MappedForeignKey[K,_,T] => @@ -139,7 +139,7 @@ trait OneToMany[K,T<:KeyedMapper[K, T]] extends KeyedMapper[K,T] { this: T => /** * Relinquishes ownership of e. Resets e's foreign key to its default value. */ - protected def unown(e: O) = { + protected def unown(e: O): O = { val f = foreign(e) f.set(f.defaultValue) unlinked = unlinked filter {e.ne} @@ -148,21 +148,22 @@ trait OneToMany[K,T<:KeyedMapper[K, T]] extends KeyedMapper[K,T] { this: T => /** * Returns the backing List */ - def all = delegate + def all: List[O] = delegate // 2.8: return this - def +=(elem: O) = { + def +=(elem: O): MappedOneToManyBase.this.type = { delegate = delegate ++ List(own(elem)) this } // 2.7 //def readOnly = all - def length = delegate.length + def length: Int = delegate.length // 2.7 //def elements = delegate.elements // 2.8 - def iterator = delegate.iterator - def apply(n: Int) = delegate(n) + def iterator: Iterator[O] = delegate.iterator + + def apply(n: Int): O = delegate(n) // 2.7 /* def +:(elem: O) = { @@ -170,13 +171,12 @@ trait OneToMany[K,T<:KeyedMapper[K, T]] extends KeyedMapper[K,T] { this: T => this } */ // 2.8 - def +=:(elem: O) = { + def +=:(elem: O): MappedOneToManyBase.this.type = { delegate ::= own(elem) this } - override def indexOf[B >: O](e: B): Int = - delegate.indexWhere(e.asInstanceOf[AnyRef].eq) + override def indexOf[B >: O](e: B): Int = delegate.indexWhere(e.asInstanceOf[AnyRef].eq) // 2.7 // def insertAll(n: Int, iter: Iterable[O]) { @@ -187,21 +187,19 @@ trait OneToMany[K,T<:KeyedMapper[K, T]] extends KeyedMapper[K,T] { this: T => delegate = before ++ iter ++ after } - def update(n: Int, newelem: O) { + def update(n: Int, newelem: O): Unit = { unown(delegate(n)) - val (before, after) = (delegate.take(n), delegate.drop(n+1)) - delegate = before ++ List(own(newelem)) ++ after + delegate = delegate.take(n) ++ List(own(newelem)) ++ delegate.drop(n+1) } - def remove(n: Int) = { + def remove(n: Int): O = { val e = unown(delegate(n)) delegate = delegate.filterNot(e.eq) e } - - def clear() { - while(delegate.length>0) + def clear(): Unit = { + while(delegate.nonEmpty) remove(0) } @@ -210,7 +208,7 @@ trait OneToMany[K,T<:KeyedMapper[K, T]] extends KeyedMapper[K,T] { this: T => * NOTE: This may leave children in an inconsistent state. * It is recommended to call save or clear() before calling refresh. */ - def refresh { + def refresh(): Unit = { delegate = reloadFunc().toList if(saved_?) unlinked = Nil @@ -223,7 +221,7 @@ trait OneToMany[K,T<:KeyedMapper[K, T]] extends KeyedMapper[K,T] { this: T => * Returns false as soon as save on a child returns false. * Returns true if all children were saved successfully. */ - def save = { + def save: Boolean = { unlinked foreach {u => val f = foreign(u) if(f.obj.map(_ eq OneToMany.this) openOr true) // obj is Empty or this @@ -237,7 +235,7 @@ trait OneToMany[K,T<:KeyedMapper[K, T]] extends KeyedMapper[K,T] { this: T => delegate.forall(_.save) } - override def toString = { + override def toString: String = { val c = getClass.getSimpleName val l = c.lastIndexOf("$") c.substring(c.lastIndexOf("$",l-1)+1, l) + delegate.mkString("[",", ","]") @@ -257,7 +255,7 @@ trait OneToMany[K,T<:KeyedMapper[K, T]] extends KeyedMapper[K,T] { this: T => removed = removed filter {e.ne} super.own(e) } - override def save = { + override def save: Boolean = { val unowned = removed.filter{ e => val f = foreign(e) f.get == f.defaultValue @@ -272,7 +270,7 @@ trait OneToMany[K,T<:KeyedMapper[K, T]] extends KeyedMapper[K,T] { this: T => * by this field should be deleted when the parent is deleted. */ trait Cascade[O<:Mapper[_]] extends MappedOneToManyBase[O] { - def delete_! = { + def delete_! : Boolean = { delegate.forall { e => if(foreign(e).get == OneToMany.this.primaryKeyField.get) { @@ -284,4 +282,3 @@ trait OneToMany[K,T<:KeyedMapper[K, T]] extends KeyedMapper[K,T] { this: T => } } } - diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/FieldFinder.scala b/persistence/mapper/src/main/scala-2.13/net/liftweb/mapper/FieldFinder.scala similarity index 81% rename from persistence/mapper/src/main/scala/net/liftweb/mapper/FieldFinder.scala rename to persistence/mapper/src/main/scala-2.13/net/liftweb/mapper/FieldFinder.scala index c1f70bd2eb..ee258ab82c 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/FieldFinder.scala +++ b/persistence/mapper/src/main/scala-2.13/net/liftweb/mapper/FieldFinder.scala @@ -17,14 +17,14 @@ package net.liftweb package mapper -import scala.reflect.{ClassTag,classTag} +import scala.reflect.{ClassTag, classTag} -class FieldFinder[T: ClassTag](metaMapper: AnyRef, logger: net.liftweb.common.Logger) { +class FieldFinder[T: ClassTag](metaMapper: AnyRef, logger: common.Logger) { import java.lang.reflect._ logger.debug("Created FieldFinder for " + classTag[T].runtimeClass) - def isMagicObject(m: Method) = m.getReturnType.getName.endsWith("$"+m.getName+"$") && m.getParameterTypes.length == 0 + def isMagicObject(m: Method): Boolean = m.getReturnType.getName.endsWith("$"+m.getName+"$") && m.getParameterTypes.length == 0 def typeFilter: Class[_]=>Boolean = classTag[T].runtimeClass.isAssignableFrom @@ -43,13 +43,13 @@ class FieldFinder[T: ClassTag](metaMapper: AnyRef, logger: net.liftweb.common.Lo case c => // get the names of fields that represent the type we want - val fields = Map(c.getDeclaredFields. - filter{f => - val ret = typeFilter(f.getType) - logger.trace("typeFilter(" + f.getType + "); T=" + classTag[T].runtimeClass) - ret - }. - map(f => (deMod(f.getName), f)) :_*) + val fields = Map.from(c.getDeclaredFields + .filter{f => + val ret = typeFilter(f.getType) + logger.trace("typeFilter(" + f.getType + "); T=" + classTag[T].runtimeClass) + ret + } + .map(f => (deMod(f.getName), f))) logger.trace("fields: " + fields) @@ -77,9 +77,7 @@ class FieldFinder[T: ClassTag](metaMapper: AnyRef, logger: net.liftweb.common.Lo // find out if the class name of the actual thing starts // with the name of this class or some superclass... // basically, is an inner class of this class - getAllSupers(clz).find{ - c => - inst.getClass.getName.startsWith(c.getName)}.isDefined + getAllSupers(clz).exists(c => inst.getClass.getName.startsWith(c.getName)) } } @@ -106,4 +104,3 @@ class FieldFinder[T: ClassTag](metaMapper: AnyRef, logger: net.liftweb.common.Lo lazy val accessorMethods = findMagicFields(metaMapper, metaMapper.getClass.getSuperclass) } - diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/ManyToMany.scala b/persistence/mapper/src/main/scala-2.13/net/liftweb/mapper/ManyToMany.scala similarity index 67% rename from persistence/mapper/src/main/scala/net/liftweb/mapper/ManyToMany.scala rename to persistence/mapper/src/main/scala-2.13/net/liftweb/mapper/ManyToMany.scala index feff467a1d..636dd633db 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/ManyToMany.scala +++ b/persistence/mapper/src/main/scala-2.13/net/liftweb/mapper/ManyToMany.scala @@ -17,10 +17,10 @@ package net.liftweb package mapper -import scala.language.existentials +import common._ -import net.liftweb.util._ -import net.liftweb.common._ +import scala.annotation.tailrec +import scala.language.existentials /** * Add this trait to a Mapper to add support for many-to-many relationships @@ -40,7 +40,7 @@ trait ManyToMany extends BaseKeyedMapper { * Returns false as soon as the parent or a one-to-many field returns false. * If they are all successful returns true. */ - abstract override def save = { + abstract override def save: Boolean = { super.save && manyToManyFields.forall(_.save) } @@ -50,7 +50,7 @@ trait ManyToMany extends BaseKeyedMapper { * Returns false as soon as the parent or a one-to-many field returns false. * If they are all successful returns true. */ - abstract override def delete_! = { + abstract override def delete_! : Boolean = { super.delete_! && manyToManyFields.forall( _.delete_!) } @@ -83,67 +83,61 @@ trait ManyToMany extends BaseKeyedMapper { /** * Get the list of instances of joinMeta */ - def joins = _joins // read only to the public + def joins: List[O] = _joins // read only to the public protected var removedJoins: List[O] = Nil - refresh manyToManyFields ::= this - protected def isJoinForChild(e: T2)(join: O) = otherField.actualField(join).get == e.primaryKeyField.get - protected def joinForChild(e: T2): Option[O] = - joins.find(isJoinForChild(e)) + protected def isJoinForChild(e: T2)(join: O): Boolean = otherField.actualField(join).get == e.primaryKeyField.get + + protected def joinForChild(e: T2): Option[O] = joins.find(isJoinForChild(e)) protected def own(e: T2): O = { - joinForChild(e) match { - case None => - removedJoins.find { // first check if we can recycle a removed join - otherField.actualField(_).get == e.primaryKeyField - } match { - case Some(removedJoin) => - removedJoins = removedJoins filter removedJoin.ne - removedJoin // well, noLongerRemovedJoin... - case None => - val newJoin = joinMeta.create - thisField.actualField(newJoin) match { - case mfk: MappedForeignKey[K,O,T] => mfk.set(primaryKeyField.get.asInstanceOf[K]) - } - otherFK(newJoin)(_.apply(e)) - newJoin + joinForChild(e).fold { + removedJoins + // first check if we can recycle a removed join + .find(otherField.actualField(_).get == e.primaryKeyField) + .fold{ + val newJoin = joinMeta.create + thisField.actualField(newJoin) match { + case mfk: MappedForeignKey[K, O, T] => mfk.set(primaryKeyField.get.asInstanceOf[K]) + } + otherFK(newJoin)(_.apply(e)) + newJoin + }{ removedJoin => + removedJoins = removedJoins filter removedJoin.ne + removedJoin // well, noLongerRemovedJoin... } - case Some(join) => - join - } + }(join => join) } - protected def unown(e: T2) = { - joinForChild(e) match { - case Some(join) => - removedJoins = join :: removedJoins - val o = otherField.actualField(join) - o.set(o.defaultValue) - thisField.actualField(join) match { case mfk => mfk set mfk.defaultValue } - Some(join) - case None => - None + + protected def unown(e: T2): Option[O] = + joinForChild(e).map{ join => + removedJoins = join :: removedJoins + val o = otherField.actualField(join) + o.set(o.defaultValue) + thisField.actualField(join) match { case mfk => mfk set mfk.defaultValue } + join } - } /** * Get the List backing this Buffer. */ - def all = children + def all: List[T2] = children - def length = children.length + def length: Int = children.length - def iterator = children.iterator + def iterator: Iterator[T2] = children.iterator - protected def childAt(n: Int) = children(n) - def apply(n: Int) = childAt(n) - def indexOf(e: T2) = - children.indexWhere(e.eq) + protected def childAt(n: Int): T2 = children(n) + def apply(n: Int): T2 = childAt(n) + def indexOf(e: T2): Int = children.indexWhere(e.eq) - def insertAll(n: Int, traversable: Traversable[T2]) { - val ownedJoins = traversable map own + def insert(idx: Int, elem: T2): Unit = insertAll(idx, Seq(elem)) + + def insertAll(n: Int, traversable: IterableOnce[T2]): Unit = { + val ownedJoins = traversable.iterator.map(own) val n2 = joins.indexWhere(isJoinForChild(children(n))) val before = joins.take(n2) val after = joins.drop(n2) @@ -151,17 +145,17 @@ trait ManyToMany extends BaseKeyedMapper { _joins = before ++ ownedJoins ++ after } - def +=:(elem: T2) = { + def prepend(elem: T2): MappedManyToMany.this.type = { _joins ::= own(elem) this } - def +=(elem: T2) = { + def addOne(elem: T2): MappedManyToMany.this.type = { _joins ++= List(own(elem)) this } - def update(n: Int, newelem: T2) { + def update(n: Int, newelem: T2): Unit = { unown(childAt(n)) match { case Some(join) => val n2 = joins.indexOf(join) @@ -171,18 +165,31 @@ trait ManyToMany extends BaseKeyedMapper { } } - def remove(n: Int) = { + def remove(n: Int): T2 = { val child = childAt(n) - unown(child) match { - case Some(join) => - _joins = joins filterNot join.eq - case None => - } + unown(child).foreach(join => _joins = joins filterNot join.eq) child } + override def remove(idx: Int, count: Int): Unit = { + if (count > 0) { + @tailrec + def loop(c: Int, a: List[T2]): List[T2] = + if (c == 0) childAt(idx) :: a + else loop(c - 1, childAt(idx + c) :: a) - def clear() { + val joins0 = loop(count - 1, Nil) flatMap unown + _joins = joins filterNot joins0.contains + } + } + + override def patchInPlace(from: Int, patch: IterableOnce[T2], replaced: Int): MappedManyToMany.this.type = { + remove(from, replaced) + insertAll(from, patch) + this + } + + def clear(): Unit = { children foreach unown _joins = Nil } @@ -190,7 +197,7 @@ trait ManyToMany extends BaseKeyedMapper { /** * Discard the cached state of this MappedManyToMany's children and reinitialize it from the database */ - def refresh = { + def refresh: List[T2] = { val by = new Cmp[O, TheKeyType](thisField, OprEnum.Eql, Full(primaryKeyField.get.asInstanceOf[K]), Empty, Empty) _joins = joinMeta.findAll( (by :: qp.toList): _*) @@ -207,7 +214,7 @@ trait ManyToMany extends BaseKeyedMapper { * 5) If step 3 succeeds save all join instances * 6) Return true if steps 2-4 all returned true; otherwise false */ - def save = { + def save: Boolean = { _joins = joins.filter { join => otherFK(join)(f => f.get != f.defaultValue) } @@ -226,10 +233,9 @@ trait ManyToMany extends BaseKeyedMapper { * marked for removal. * Returns true if both succeed, otherwise false */ - def delete_! = { + def delete_! : Boolean = { removedJoins.forall(_.delete_!) & joins.forall(_.delete_!) } } } - diff --git a/persistence/mapper/src/main/scala-2.13/net/liftweb/mapper/OneToMany.scala b/persistence/mapper/src/main/scala-2.13/net/liftweb/mapper/OneToMany.scala new file mode 100644 index 0000000000..b868894f6c --- /dev/null +++ b/persistence/mapper/src/main/scala-2.13/net/liftweb/mapper/OneToMany.scala @@ -0,0 +1,296 @@ +/* + * Copyright 2006-2011 WorldWide Conferencing, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.liftweb.mapper + +private[mapper] object RecursiveType { + val rec: { type R0 <: Mapper[R0] } = null + type Rec = rec.R0 +} +import RecursiveType._ + +/** + * Add this trait to a Mapper for managed one-to-many support + * For example: class Contact extends LongKeyedMapper[Contact] with OneToMany[Long, Contact] { ... } + * @tparam K the type of the primary key + * @tparam T the mapper type + * @author nafg + */ +trait OneToMany[K,T<:KeyedMapper[K, T]] extends KeyedMapper[K,T] { this: T => + + private[mapper] lazy val oneToManyFields: List[MappedOneToManyBase[Rec]] = { + new FieldFinder[MappedOneToManyBase[Rec]]( + getSingleton, + net.liftweb.common.Logger(classOf[OneToMany[K,T]]) + ).accessorMethods map (_.invoke(this).asInstanceOf[MappedOneToManyBase[Rec]]) + } + + /** + * An override for save to propagate the save to all children + * of this parent. + * Returns false as soon as the parent or a one-to-many field returns false. + * If they are all successful returns true. + */ + override def save: Boolean = { + val ret = super.save && + oneToManyFields.forall(_.save) + ret + } + + /** + * An override for delete_! to propagate the deletion + * to all children of one-to-many fields implementing Cascade. + * Returns false as soon as the parent or a one-to-many field returns false. + * If they are all successful returns true. + */ + override def delete_! : Boolean = DB.use(connectionIdentifier){ _ => + if(oneToManyFields.forall{(_: MappedOneToManyBase[_ <: Mapper[_]]) match { + case f: Cascade[_] => f.delete_! + case _ => true + } + }) + super.delete_! + else { + DB.rollback(connectionIdentifier) + false + } + } + + + /** + * This implicit allows a MappedForeignKey to be used as foreignKey function. + * Returns a function that takes a Mapper and looks up the actualField of field on the Mapper. + */ + implicit def foreignKey[K, O<:Mapper[O], T<:KeyedMapper[K,T]](field: MappedForeignKey[K,O,T]): O=>MappedForeignKey[K,O,T] = + field.actualField(_).asInstanceOf[MappedForeignKey[K,O,T]] + + /** + * Simple OneToMany support for children from the same table + */ + class MappedOneToMany[O <: Mapper[O]](meta: MetaMapper[O], foreign: MappedForeignKey[K,O,T], qp: QueryParam[O]*) + extends MappedOneToManyBase[O]( + ()=>{ + val ret = meta.findAll(By(foreign, primaryKeyField.get) :: qp.toList : _*) + for(child <- ret) { + foreign.actualField(child).asInstanceOf[MappedForeignKey[K,O,T]].primeObj(net.liftweb.common.Full(OneToMany.this : T)) + } + ret + }, + foreign + ) + + /** + * This is the base class to use for fields that represent one-to-many or parent-child relationships. + * Maintains a list of children, tracking pending additions and deletions, and + * keeping their foreign key pointed to this mapper. + * Implements Buffer, so the children can be managed as one. + * Most users will use MappedOneToMany, however to support children from multiple tables + * it is necessary to use MappedOneToManyBase. + * @param reloadFunc A function that returns a sequence of children from storage. + * @param foreign A function that gets the MappedForeignKey on the child that refers to this parent + */ + class MappedOneToManyBase[O <: Mapper[_]](val reloadFunc: () => Seq[O], + val foreign: O => MappedForeignKey[K,_,T]) extends scala.collection.mutable.Buffer[O] { + private var inited = false + private var _delegate: List[O] = _ + /** + * children that were added before the parent was ever saved + */ + private var unlinked: List[O] = Nil + protected def delegate: List[O] = { + if(!inited) { + refresh() + inited = true + } + _delegate + } + protected def delegate_=(d: List[O]): Unit = _delegate = d + + /** + * Takes ownership of e. Sets e's foreign key to our primary key + */ + protected def own(e: O): O = { + val f0 = foreign(e).asInstanceOf[Any] + f0 match { + case f: MappedLongForeignKey[O,T] with MappedForeignKey[K,_,T] => + f.apply(OneToMany.this) + case f: MappedForeignKey[K,_,T] => + f.set(OneToMany.this.primaryKeyField.get) + } + if(!OneToMany.this.saved_?) + unlinked ::= e + e + } + /** + * Relinquishes ownership of e. Resets e's foreign key to its default value. + */ + protected def unown(e: O): O = { + val f = foreign(e) + f.set(f.defaultValue) + unlinked = unlinked filter {e.ne} + e + } + /** + * Returns the backing List + */ + def all: List[O] = delegate + + // 2.8: return this + def addOne(elem: O): MappedOneToManyBase.this.type = { + delegate = delegate ++ List(own(elem)) + this + } + // 2.7 + //def readOnly = all + def length: Int = delegate.length + // 2.7 + //def elements = delegate.elements + // 2.8 + def iterator: Iterator[O] = delegate.iterator + + def apply(n: Int): O = delegate(n) + + // 2.7 + /* def +:(elem: O) = { + delegate ::= own(elem) + this + } */ + // 2.8 + def prepend(elem: O): MappedOneToManyBase.this.type = { + delegate ::= own(elem) + this + } + + override def indexOf[B >: O](e: B): Int = delegate.indexWhere(e.asInstanceOf[AnyRef].eq) + + override def insert(idx: Int, elem: O): Unit = insertAll(idx, List(elem)) + + // 2.7 + // def insertAll(n: Int, iter: Iterable[O]) { + // 2.8 + def insertAll(n: Int, iter: IterableOnce[O]): Unit = { + val (before, after) = delegate.splitAt(n) + delegate = before ++ iter.iterator.map(own) ++ after + } + + def patchInPlace(from: Int, patch: IterableOnce[O], replaced: Int): MappedOneToManyBase.this.type = { + val endIds = from + replaced + delegate.slice(from, endIds).foreach(unown) + delegate = delegate.take(from) ++ patch.iterator.map(own) ++ delegate.drop(endIds) + this + } + + def update(n: Int, newelem: O): Unit = { + unown(delegate(n)) + delegate = delegate.take(n) ++ List(own(newelem)) ++ delegate.drop(n+1) + } + + def remove(n: Int): O = { + val e = unown(delegate(n)) + delegate = delegate.filterNot(e.eq) + e + } + + def remove(idx: Int, count: Int): Unit = { + val endIds = idx + count + delegate.slice(idx, endIds).foreach(unown) + delegate = delegate.take(idx) ++ delegate.drop(endIds) + } + + def clear(): Unit = { + while(delegate.nonEmpty) + remove(0) + } + + /** + * Reloads the children from storage. + * NOTE: This may leave children in an inconsistent state. + * It is recommended to call save or clear() before calling refresh. + */ + def refresh(): Unit = { + delegate = reloadFunc().toList + if(saved_?) + unlinked = Nil + else + unlinked = _delegate + } + + /** + * Saves this "field," i.e., all the children it represents. + * Returns false as soon as save on a child returns false. + * Returns true if all children were saved successfully. + */ + def save: Boolean = { + unlinked foreach {u => + val f = foreign(u) + if(f.obj.map(_ eq OneToMany.this) openOr true) // obj is Empty or this + f.apply(OneToMany.this) + } + unlinked = Nil + delegate = delegate.filter {e => + foreign(e).get == OneToMany.this.primaryKeyField.get || + foreign(e).obj.map(_ eq OneToMany.this).openOr(false) // obj is this but not Empty + } + delegate.forall(_.save) + } + + override def toString: String = { + val c = getClass.getSimpleName + val l = c.lastIndexOf("$") + c.substring(c.lastIndexOf("$",l-1)+1, l) + delegate.mkString("[",", ","]") + } + } + + /** + * Adds behavior to delete orphaned fields before save. + */ + trait Owned[O<:Mapper[_]] extends MappedOneToManyBase[O] { + var removed: List[O] = Nil + override def unown(e: O) = { + removed = e :: removed + super.unown(e) + } + override def own(e: O) = { + removed = removed filter {e.ne} + super.own(e) + } + override def save: Boolean = { + val unowned = removed.filter{ e => + val f = foreign(e) + f.get == f.defaultValue + } + unowned foreach {_.delete_!} + super.save + } + } + + /** + * Trait that indicates that the children represented + * by this field should be deleted when the parent is deleted. + */ + trait Cascade[O<:Mapper[_]] extends MappedOneToManyBase[O] { + def delete_! : Boolean = { + delegate.forall { e => + if(foreign(e).get == + OneToMany.this.primaryKeyField.get) { + e.delete_! + } + else + true // doesn't constitute a failure + } + } + } +} diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/AjaxMapper.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/AjaxMapper.scala index c9243a5b3b..565794bced 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/AjaxMapper.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/AjaxMapper.scala @@ -29,7 +29,7 @@ trait AjaxEditableField[FieldType,OwnerType <: Mapper[OwnerType]] extends Mapped if (editableField) { { toForm.map { form => - SHtml.ajaxEditable(super.asHtml, form, () => {fieldOwner.save; onSave; net.liftweb.http.js.JsCmds.Noop}) + SHtml.ajaxEditable(super.asHtml, form, () => {fieldOwner.save; onSave(); net.liftweb.http.js.JsCmds.Noop}) } openOr super.asHtml } } else { @@ -37,7 +37,7 @@ trait AjaxEditableField[FieldType,OwnerType <: Mapper[OwnerType]] extends Mapped } /** This method is called when the element's data are saved. The default is to do nothing */ - def onSave {} + def onSave(): Unit = {} /** This method allows you to do programmatic control of whether the field will display * as editable. The default is true */ diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/CRUDify.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/CRUDify.scala index 94104ab247..9ef7d5e594 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/CRUDify.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/CRUDify.scala @@ -17,12 +17,8 @@ package net.liftweb package mapper -import sitemap._ -import Loc._ -import http._ import util._ import common._ -import Helpers._ import scala.xml._ diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/DB.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/DB.scala index 93344d7ce2..d6301d2dd0 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/DB.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/DB.scala @@ -22,9 +22,6 @@ import http.S object DB extends db.DB1 { db.DB.queryCollector = { case (query, time) => - query.statementEntries.foreach( - {case db.DBLogEntry(stmt, duration) => S.logQuery(stmt, duration) - } - ) + query.statementEntries.foreach{ case db.DBLogEntry(stmt, duration) => S.logQuery(stmt, duration) } } } diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/HasManyThrough.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/HasManyThrough.scala index e9d0f9ea19..3fa143467f 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/HasManyThrough.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/HasManyThrough.scala @@ -17,10 +17,11 @@ package net.liftweb package mapper -import scala.collection.mutable.HashSet import util.FatLazy import common._ +import scala.collection.mutable + class HasManyThrough[From <: KeyedMapper[ThroughType, From], To <: Mapper[To], Through <: Mapper[Through], @@ -59,29 +60,29 @@ class HasManyThrough[From <: KeyedMapper[ThroughType, From], def get: List[To] = this() - def reset = others.reset + def reset(): Unit = others.reset def set(what: Seq[ThroughType]): Seq[ThroughType] = { theSetList = what theSetList } - override def beforeDelete { + override def beforeDelete: Unit = { through.findAll(By(throughFromField, owner.primaryKeyField.get)).foreach { toDelete => toDelete.delete_! } } - override def afterUpdate { + override def afterUpdate: Unit = { val current = through.findAll(By(throughFromField, owner.primaryKeyField.get)) - val newKeys = new HashSet[ThroughType]; + val newKeys = new mutable.HashSet[ThroughType] theSetList.foreach(i => newKeys += i) val toDelete = current.filter(c => !newKeys.contains(throughToField.actualField(c).get)) toDelete.foreach(_.delete_!) - val oldKeys = new HashSet[ThroughType]; + val oldKeys = new mutable.HashSet[ThroughType] current.foreach(i => oldKeys += throughToField.actualField(i).get) theSetList.toList.distinct.filter(i => !oldKeys.contains(i)).foreach { i => @@ -96,7 +97,7 @@ class HasManyThrough[From <: KeyedMapper[ThroughType, From], super.afterUpdate } - override def afterCreate { + override def afterCreate: Unit = { theSetList.toList.distinct.foreach { i => val toCreate = through.createInstance throughFromField.actualField(toCreate)(owner.primaryKeyField.get) diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedBinary.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedBinary.scala index d1d64cafe4..08c34f952f 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedBinary.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedBinary.scala @@ -40,7 +40,6 @@ abstract class MappedBinary[T<:Mapper[T]](val fieldOwner: T) extends MappedField value } - def manifest: TypeTag[Array[Byte]] = typeTag[Array[Byte]] /** @@ -84,23 +83,23 @@ abstract class MappedBinary[T<:Mapper[T]](val fieldOwner: T) extends MappedField def asSeq(v: T): Box[Seq[SourceFieldInfo]] = Empty }) - def dbFieldClass = classOf[Array[Byte]] + def dbFieldClass: Class[Array[Byte]] = classOf[Array[Byte]] /** * Get the JDBC SQL Type for this field */ // def getTargetSQLType(field : String) = Types.BINARY - def targetSQLType = Types.BINARY + def targetSQLType: Int = Types.BINARY def defaultValue: Array[Byte] = null override def writePermission_? = true override def readPermission_? = true - protected def i_is_! = data.get + protected def i_is_! : Array[Byte] = data.get - protected def i_was_! = orgData.get + protected def i_was_! : Array[Byte] = orgData.get - protected[mapper] def doneWithSave() {orgData.setFrom(data)} + protected[mapper] def doneWithSave(): Unit = {orgData.setFrom(data)} protected def i_obscure_!(in : Array[Byte]) : Array[Byte] = { new Array[Byte](0) @@ -202,23 +201,23 @@ abstract class MappedText[T<:Mapper[T]](val fieldOwner: T) extends MappedField[S def asSeq(v: T): Box[Seq[SourceFieldInfo]] = Empty }) - def dbFieldClass = classOf[String] + def dbFieldClass: Class[String] = classOf[String] /** * Get the JDBC SQL Type for this field */ // def getTargetSQLType(field : String) = Types.BINARY - def targetSQLType = Types.VARCHAR + def targetSQLType: Int = Types.VARCHAR def defaultValue: String = null override def writePermission_? = true override def readPermission_? = true - protected def i_is_! = data.get + protected def i_is_! : String = data.get - protected def i_was_! = orgData.get + protected def i_was_! : String = orgData.get - protected[mapper] def doneWithSave() {orgData.setFrom(data)} + protected[mapper] def doneWithSave(): Unit = {orgData.setFrom(data)} def asJsExp: JsExp = JE.Str(get) @@ -229,11 +228,11 @@ abstract class MappedText[T<:Mapper[T]](val fieldOwner: T) extends MappedField[S protected def i_obscure_!(in: String): String = "" - override def setFromAny(in: Any): String = { + override def setFromAny(in: Any): String = { in match { case JsonAST.JNull => this.set(null) case JsonAST.JString(str) => this.set(str) - case seq: Seq[_] if !seq.isEmpty => seq.map(setFromAny).apply(0) + case seq: Seq[_] if seq.nonEmpty => seq.map(setFromAny).head case (s: String) :: _ => this.set(s) case s :: _ => this.setFromAny(s) case null => this.set(null) @@ -247,7 +246,6 @@ abstract class MappedText[T<:Mapper[T]](val fieldOwner: T) extends MappedField[S def jdbcFriendly(field : String): Object = real_convertToJDBCFriendly(data.get) - def real_convertToJDBCFriendly(value: String): Object = value match { case null => null case s => s @@ -268,10 +266,7 @@ abstract class MappedText[T<:Mapper[T]](val fieldOwner: T) extends MappedField[S def buildSetLongValue(accessor : Method, columnName : String): (T, Long, Boolean) => Unit = null def buildSetStringValue(accessor : Method, columnName : String): (T, String) => Unit = (inst, v) => doField(inst, accessor, {case f: MappedText[T] => - val toSet = v match { - case null => null - case other => other - } + val toSet = v f.data() = toSet f.orgData() = toSet }) @@ -294,7 +289,7 @@ abstract class MappedFakeClob[T<:Mapper[T]](val fieldOwner: T) extends MappedFie value } - def dbFieldClass = classOf[String] + def dbFieldClass: Class[String] = classOf[String] def manifest: TypeTag[String] = typeTag[String] @@ -344,17 +339,17 @@ abstract class MappedFakeClob[T<:Mapper[T]](val fieldOwner: T) extends MappedFie * Get the JDBC SQL Type for this field */ // def getTargetSQLType(field : String) = Types.BINARY - def targetSQLType = Types.BINARY + def targetSQLType: Int = Types.BINARY def defaultValue: String = null override def writePermission_? = true override def readPermission_? = true - protected def i_is_! = data.get + protected def i_is_! : String = data.get - protected def i_was_! = orgData.get + protected def i_was_! : String = orgData.get - protected[mapper] def doneWithSave() {orgData.setFrom(data)} + protected[mapper] def doneWithSave(): Unit = {orgData.setFrom(data)} protected def i_obscure_!(in: String): String = "" @@ -365,12 +360,11 @@ abstract class MappedFakeClob[T<:Mapper[T]](val fieldOwner: T) extends MappedFie case str => JsonAST.JString(str) }) - - override def setFromAny(in: Any): String = { + override def setFromAny(in: Any): String = { in match { case JsonAST.JNull => this.set(null) case JsonAST.JString(str) => this.set(str) - case seq: Seq[_] if !seq.isEmpty => seq.map(setFromAny).apply(0) + case seq: Seq[_] if seq.nonEmpty => seq.map(setFromAny).head case (s: String) :: _ => this.set(s) case s :: _ => this.setFromAny(s) case null => this.set(null) @@ -384,7 +378,6 @@ abstract class MappedFakeClob[T<:Mapper[T]](val fieldOwner: T) extends MappedFie def jdbcFriendly(field : String): Object = real_convertToJDBCFriendly(data.get) - def real_convertToJDBCFriendly(value: String): Object = value match { case null => null case s => s.getBytes("UTF-8") @@ -403,11 +396,8 @@ abstract class MappedFakeClob[T<:Mapper[T]](val fieldOwner: T) extends MappedFie }) def buildSetLongValue(accessor : Method, columnName : String): (T, Long, Boolean) => Unit = null - def buildSetStringValue(accessor : Method, columnName : String): (T, String) => Unit = (inst, v) => doField(inst, accessor, {case f: MappedFakeClob[T] => - val toSet = v match { - case null => null - case other => other - } + def buildSetStringValue(accessor : Method, columnName : String): (T, String) => Unit = (inst, v) => doField(inst, accessor, {case f: MappedFakeClob[T] => + val toSet = v f.data() = toSet f.orgData() = toSet }) @@ -419,4 +409,3 @@ abstract class MappedFakeClob[T<:Mapper[T]](val fieldOwner: T) extends MappedFie */ def fieldCreatorString(dbType: DriverType, colName: String): String = colName + " " + dbType.binaryColumnType + notNullAppender() } - diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedBoolean.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedBoolean.scala index 67823a9c92..9c526e5520 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedBoolean.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedBoolean.scala @@ -17,7 +17,7 @@ package net.liftweb package mapper -import java.sql.{ResultSet, Types} +import java.sql.Types import java.lang.reflect.Method import net.liftweb.util.Helpers._ import net.liftweb.http.{S, SHtml} @@ -88,9 +88,9 @@ abstract class MappedBoolean[T<:Mapper[T]](val fieldOwner: T) extends MappedFiel }) - protected def i_is_! = data openOr false - protected def i_was_! = orgData openOr false - protected[mapper] def doneWithSave() {orgData = data} + protected def i_is_! : Boolean = data openOr false + protected def i_was_! : Boolean = orgData openOr false + protected[mapper] def doneWithSave(): Unit = {orgData = data} protected def real_i_set_!(value : Boolean) : Boolean = { val boxed = Full(value) @@ -103,7 +103,7 @@ abstract class MappedBoolean[T<:Mapper[T]](val fieldOwner: T) extends MappedFiel override def readPermission_? = true override def writePermission_? = true - def asJsonValue: Box[JsonAST.JValue] = Full(JsonAST.JBool(get)) + def asJsonValue: Box[JsonAST.JValue] = Full(JsonAST.JBool(get)) def real_convertToJDBCFriendly(value: Boolean): Object = new java.lang.Integer(if (value) 1 else 0) @@ -136,7 +136,7 @@ abstract class MappedBoolean[T<:Mapper[T]](val fieldOwner: T) extends MappedFiel } } - private def allSet(in: Box[Boolean]) { + private def allSet(in: Box[Boolean]): Unit = { this.data = in this.orgData = in } diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedDate.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedDate.scala index d944a5a0b9..f414e975f5 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedDate.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedDate.scala @@ -135,7 +135,7 @@ abstract class MappedDate[T<:Mapper[T]](val fieldOwner: T) extends MappedField[D protected def i_is_! = data.get protected def i_was_! = orgData.get - protected[mapper] def doneWithSave() {orgData.setFrom(data)} + protected[mapper] def doneWithSave(): Unit = {orgData.setFrom(data)} protected def i_obscure_!(in : Date) : Date = { new Date(0L) diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedDateTime.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedDateTime.scala index 9d1cb5bf41..14dba95d00 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedDateTime.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedDateTime.scala @@ -128,7 +128,7 @@ abstract class MappedDateTime[T<:Mapper[T]](val fieldOwner: T) extends MappedFie protected def i_is_! = data.get protected def i_was_! = orgData.get - protected[mapper] def doneWithSave() {orgData.setFrom(data)} + protected[mapper] def doneWithSave(): Unit = {orgData.setFrom(data)} protected def i_obscure_!(in : Date) : Date = { new Date(0L) diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedDecimal.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedDecimal.scala index 82619c9db0..5a7582934a 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedDecimal.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedDecimal.scala @@ -138,7 +138,7 @@ abstract class MappedDecimal[T <: Mapper[T]] (val fieldOwner : T, val context : protected def i_is_! = data protected def i_was_! = orgData - override def doneWithSave() { + override def doneWithSave(): Unit = { orgData = data } diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedDouble.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedDouble.scala index ec4d26d72f..bcff6bd756 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedDouble.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedDouble.scala @@ -17,11 +17,10 @@ package net.liftweb package mapper -import java.sql.{ResultSet, Types} +import java.sql.Types import java.lang.reflect.Method import net.liftweb.common._ import net.liftweb.util._ -import Helpers._ import java.util.Date import net.liftweb.http._ import scala.xml.{Text, NodeSeq} @@ -32,18 +31,18 @@ abstract class MappedDouble[T<:Mapper[T]](val fieldOwner: T) extends MappedField private var data: Double = defaultValue private var orgData: Double = defaultValue - private def st(in: Double) { + private def st(in: Double): Unit = { data = in orgData = in } def defaultValue: Double = 0.0 - def dbFieldClass = classOf[Double] + def dbFieldClass: Class[Double] = classOf[Double] - protected def i_is_! = data - protected def i_was_! = orgData + protected def i_is_! : Double = data + protected def i_was_! : Double = orgData - override def doneWithSave() { + override def doneWithSave(): Unit = { orgData = data } @@ -95,15 +94,15 @@ abstract class MappedDouble[T<:Mapper[T]](val fieldOwner: T) extends MappedField in match { case null => 0.0 case i: Int => i - case n: Long => n + case n: Long => n.toDouble case n : Number => n.doubleValue case (n: Number) :: _ => n.doubleValue case Full(n) => toDouble(n) // fixes issue 185 - case x: EmptyBox => 0.0 + case _: EmptyBox => 0.0 case Some(n) => toDouble(n) case None => 0.0 case s: String => s.toDouble - case x :: xs => toDouble(x) + case x :: _ => toDouble(x) case o => toDouble(o.toString) } } @@ -111,7 +110,7 @@ abstract class MappedDouble[T<:Mapper[T]](val fieldOwner: T) extends MappedField override def readPermission_? = true override def writePermission_? = true - protected def i_obscure_!(in : Double) = defaultValue + protected def i_obscure_!(in : Double): Double = defaultValue protected def real_i_set_!(value : Double): Double = { if (value != data) { @@ -146,17 +145,17 @@ abstract class MappedDouble[T<:Mapper[T]](val fieldOwner: T) extends MappedField /** * Get the JDBC SQL Type for this field */ - def targetSQLType = Types.DOUBLE + def targetSQLType: Int = Types.DOUBLE def jdbcFriendly(field : String) = new java.lang.Double(i_is_!) def buildSetBooleanValue(accessor : Method, columnName : String) : (T, Boolean, Boolean) => Unit = null def buildSetDateValue(accessor : Method, columnName : String) : (T, Date) => Unit = - (inst, v) => doField(inst, accessor, {case f: MappedDouble[T] => f.st(if (v == null) defaultValue else v.getTime)}) + (inst, v) => doField(inst, accessor, {case f: MappedDouble[T] => f.st(if (v == null) defaultValue else v.getTime.toDouble)}) def buildSetStringValue(accessor: Method, columnName: String): (T, String) => Unit = (inst, v) => doField(inst, accessor, {case f: MappedDouble[T] => f.st(toDouble(v))}) def buildSetLongValue(accessor: Method, columnName : String) : (T, Long, Boolean) => - Unit = (inst, v, isNull) => doField(inst, accessor, {case f: MappedDouble[T] => f.st(if (isNull) defaultValue else v)}) + Unit = (inst, v, isNull) => doField(inst, accessor, {case f: MappedDouble[T] => f.st(if (isNull) defaultValue else v.toDouble)}) def buildSetActualValue(accessor: Method, data: AnyRef, columnName: String) : (T, AnyRef) => Unit = (inst, v) => doField(inst, accessor, {case f: MappedDouble[T] => f.st(toDouble(v))}) diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedEmail.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedEmail.scala index 445b722732..538406cf0b 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedEmail.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedEmail.scala @@ -17,11 +17,11 @@ package net.liftweb package mapper -import java.util.regex._ +import http.S +import util.FieldError +import proto._ + import scala.xml.Text -import net.liftweb.http.{S} -import net.liftweb.util.{FieldError} -import net.liftweb.proto._ object MappedEmail { def emailPattern = ProtoRules.emailRegexPattern.vend diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedField.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedField.scala index 25037ffc1b..256545095f 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedField.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedField.scala @@ -19,14 +19,17 @@ package mapper import scala.collection.mutable._ import java.lang.reflect.Method + import scala.xml._ import java.util.Date + import net.liftweb.http.{S, SHtml} -import net.liftweb.http.S._ import net.liftweb.http.js._ import net.liftweb.common._ import net.liftweb.json._ import net.liftweb.util._ + +import scala.annotation.tailrec import scala.reflect.runtime.universe._ /** @@ -39,7 +42,6 @@ trait MixableMappedField extends BaseField { */ type TheOwnerType <: Mapper[TheOwnerType] - /** * Return the field name and field value, delimited by an '=' */ @@ -47,7 +49,6 @@ trait MixableMappedField extends BaseField { def dbColumnCount: Int - def dbIndexed_? : Boolean def dbNotNull_? : Boolean @@ -70,14 +71,13 @@ trait BaseMappedField extends SelectableField with Bindable with MixableMappedFi def dbDisplay_? = true - def dbIncludeInForm_? = dbDisplay_? + def dbIncludeInForm_? : Boolean = dbDisplay_? def asJsonField: Box[JsonAST.JField] = asJsonValue.map(v => JsonAST.JField(name, v)) def asJsonValue: Box[JsonAST.JValue] - /** * Get a JDBC friendly representation of the named field (this is used for MappedFields that correspond to more than * 1 column in the database.) @@ -106,7 +106,6 @@ trait BaseMappedField extends SelectableField with Bindable with MixableMappedFi */ def targetSQLType: Int - /** * Given the driver type, return the string required to create the column in the database */ @@ -117,7 +116,6 @@ trait BaseMappedField extends SelectableField with Bindable with MixableMappedFi */ def fieldCreatorString(dbType: DriverType): List[String] - /** * Convert the field to its name/value pair (e.g., name=David) */ @@ -128,7 +126,6 @@ trait BaseMappedField extends SelectableField with Bindable with MixableMappedFi */ def dbColumnCount: Int - def dbColumnNames(in: String): List[String] def dbColumnName: String @@ -136,7 +133,7 @@ trait BaseMappedField extends SelectableField with Bindable with MixableMappedFi /** * The forced lower case column names */ - final def _dbColumnNameLC = { + final def _dbColumnNameLC: String = { val name = dbColumnName val conn = DB.currentConnection @@ -182,13 +179,12 @@ trait BaseMappedField extends SelectableField with Bindable with MixableMappedFi */ def dbAddedIndex: Box[() => Unit] - def asHtml: NodeSeq /** * Called after the field is saved to the database */ - protected[mapper] def doneWithSave() + protected[mapper] def doneWithSave(): Unit def asJsExp: JsExp @@ -201,12 +197,12 @@ trait BaseMappedField extends SelectableField with Bindable with MixableMappedFi def renderJs_? = true - /** - * This is where the instance creates its "toForm" stuff. - * The actual toForm method wraps the information based on - * mode. - */ - def _toForm: Box[NodeSeq] + /** + * This is where the instance creates its "toForm" stuff. + * The actual toForm method wraps the information based on + * mode. + */ + def _toForm: Box[NodeSeq] } /** @@ -226,7 +222,6 @@ trait TypedField[FieldType] { */ def defaultValue: FieldType - /** * What is the real class that corresponds to FieldType */ @@ -242,7 +237,7 @@ trait MappedNullableField[NullableFieldType <: Any,OwnerType <: Mapper[OwnerType */ override final def dbNotNull_? : Boolean = false - override def toString = get.map(_.toString) openOr "" + override def toString: String = get.map(_.toString) openOr "" /** * Create an input field for the item @@ -292,8 +287,6 @@ trait MappedField[FieldType <: Any,OwnerType <: Mapper[OwnerType]] extends Typed def sourceFieldInfo(): SourceFieldInfo{type T = FieldType} = SourceFieldInfoRep(get, sourceInfoMetadata()) - - /** * Get the field that this prototypical field represents * @@ -311,7 +304,7 @@ trait MappedField[FieldType <: Any,OwnerType <: Mapper[OwnerType]] extends Typed */ def fieldCreatorString(dbType: DriverType): List[String] = dbColumnNames(name).map{c => fieldCreatorString(dbType, c)} - def notNullAppender() = if (dbNotNull_?) " NOT NULL " else "" + def notNullAppender(): String = if (dbNotNull_?) " NOT NULL " else "" /** * Is the field dirty @@ -321,12 +314,12 @@ trait MappedField[FieldType <: Any,OwnerType <: Mapper[OwnerType]] extends Typed /** * Is the field dirty (has it been changed since the record was loaded from the database */ - def dirty_? = !dbPrimaryKey_? && _dirty_? + def dirty_? : Boolean = !dbPrimaryKey_? && _dirty_? /** * Make the field dirty */ - protected def dirty_?(b: Boolean) = _dirty_? = b + protected def dirty_?(b: Boolean): Unit = _dirty_? = b /** * Called when a column has been added to the database via Schemifier @@ -363,8 +356,6 @@ trait MappedField[FieldType <: Any,OwnerType <: Mapper[OwnerType]] extends Typed */ def readPermission_? = false - - /** * Assignment from the underlying type. It's ugly, but:
* field() = new_value
@@ -372,11 +363,11 @@ trait MappedField[FieldType <: Any,OwnerType <: Mapper[OwnerType]] extends Typed * field.set(new_value)
* are all the same */ - def update[Q <% FieldType](v: Q) { + def update[Q](v: Q)(implicit implFn: Q => FieldType): Unit = { this.set(v) } - def apply[Q <% FieldType](v: Q): OwnerType = { + def apply[Q](v: Q)(implicit implFn: Q => FieldType): OwnerType = { this.set(v) fieldOwner } @@ -386,7 +377,6 @@ trait MappedField[FieldType <: Any,OwnerType <: Mapper[OwnerType]] extends Typed fieldOwner } - /** * The unique field id is the field name and the mapper name */ @@ -401,28 +391,27 @@ trait MappedField[FieldType <: Any,OwnerType <: Mapper[OwnerType]] extends Typed else throw new Exception("Do not have permissions to set this field") } - def :=[Q <% FieldType](v: Q): FieldType = { + def :=[Q](v: Q)(implicit implFn: Q => FieldType): FieldType = { set(v) } - def :=(v: FieldType): FieldType = { + def :=(v: FieldType): FieldType = { set(v) } - - private var _name : String = null + private var _name : String = _ /** * The internal name of this field. Use name */ - private[mapper] final def i_name_! = _name + private[mapper] final def i_name_! : String = _name /** * The name of this field */ - final def name = synchronized { + final def name: String = synchronized { if (_name eq null) { - fieldOwner.checkNames + fieldOwner.checkNames() } _name } @@ -440,11 +429,10 @@ trait MappedField[FieldType <: Any,OwnerType <: Mapper[OwnerType]] extends Typed */ override def displayName: String = MapperRules.displayNameCalculator.vend(fieldOwner, S.locale, name) - def resetDirty { + def resetDirty(): Unit = { if (safe_?) dirty_?(false) } - /** * Attempt to figure out what the incoming value is and set the field to that value. Return true if * the value could be assigned @@ -490,14 +478,12 @@ trait MappedField[FieldType <: Any,OwnerType <: Mapper[OwnerType]] extends Typed * If the field has a defined fieldId, append it */ protected def appendFieldId(in: Elem): Elem = fieldId match { - case Some(i) => { + case Some(i) => import util.Helpers._ in % ("id" -> i) - } case _ => in } - /** * Set the field to the Box value if the Box is Full */ @@ -534,7 +520,7 @@ trait MappedField[FieldType <: Any,OwnerType <: Mapper[OwnerType]] extends Typed def buildSetDateValue(accessor: Method, columnName: String): (OwnerType, Date) => Unit def buildSetBooleanValue(accessor: Method, columnName: String) : (OwnerType, Boolean, Boolean) => Unit protected def getField(inst: OwnerType, meth: Method) = meth.invoke(inst).asInstanceOf[MappedField[FieldType,OwnerType]]; - protected def doField(inst: OwnerType, meth: Method, func: PartialFunction[MappedField[FieldType, OwnerType], Unit]) { + protected def doField(inst: OwnerType, meth: Method, func: PartialFunction[MappedField[FieldType, OwnerType], Unit]): Unit = { val f = getField(inst, meth) if (func.isDefinedAt(f)) func(f) } @@ -577,13 +563,13 @@ trait MappedField[FieldType <: Any,OwnerType <: Mapper[OwnerType]] extends Typed /** * Return the field name and field value, delimited by an '=' */ - def asString = name + "=" + toString + def asString: String = name + "=" + toString def dbColumnCount = 1 - def dbColumnNames(in : String) = if (dbColumnCount == 1) List(_dbColumnNameLC) else List(in.toLowerCase) + def dbColumnNames(in : String): List[String] = if (dbColumnCount == 1) List(_dbColumnNameLC) else List(in.toLowerCase) - def dbColumnName = { + def dbColumnName: String = { val columnName = MapperRules.columnName(fieldOwner.connectionIdentifier, name) if(DB.reservedWords.contains(columnName.toLowerCase)) columnName+"_c" @@ -591,7 +577,7 @@ trait MappedField[FieldType <: Any,OwnerType <: Mapper[OwnerType]] extends Typed columnName } - def dbSelectString = fieldOwner.getSingleton._dbTableNameLC + "." + _dbColumnNameLC + def dbSelectString: String = fieldOwner.getSingleton._dbTableNameLC + "." + _dbColumnNameLC def dbIndexed_? : Boolean = false @@ -642,7 +628,8 @@ trait MappedField[FieldType <: Any,OwnerType <: Mapper[OwnerType]] extends Typed } */ - def runValidations(validators: List[FieldType => List[FieldError]]) { + @tailrec + def runValidations(validators: List[FieldType => List[FieldError]]): Unit = { validators match { case Nil => () case x :: rest => @@ -692,7 +679,7 @@ trait MappedField[FieldType <: Any,OwnerType <: Mapper[OwnerType]] extends Typed ) } - def canEqual(that: Any) = that match { + def canEqual(that: Any): Boolean = that match { case ar: AnyRef => ar.getClass==this.getClass case _ => false } @@ -715,22 +702,22 @@ trait BaseIndexedField extends BaseMappedField { trait LifecycleCallbacks { - def beforeValidation {} - def beforeValidationOnCreate {} - def beforeValidationOnUpdate {} - def afterValidation {} - def afterValidationOnCreate {} - def afterValidationOnUpdate {} - - def beforeSave {} - def beforeCreate {} - def beforeUpdate {} - - def afterSave {} - def afterCreate {} - def afterUpdate {} - - def beforeDelete {} - def afterDelete {} + def beforeValidation: Unit = {} + def beforeValidationOnCreate: Unit = {} + def beforeValidationOnUpdate: Unit = {} + def afterValidation: Unit = {} + def afterValidationOnCreate: Unit = {} + def afterValidationOnUpdate: Unit = {} + + def beforeSave: Unit = {} + def beforeCreate: Unit = {} + def beforeUpdate: Unit = {} + + def afterSave: Unit = {} + def afterCreate: Unit = {} + def afterUpdate: Unit = {} + + def beforeDelete: Unit = {} + def afterDelete: Unit = {} } diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedForeignKey.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedForeignKey.scala index 4d1810cd7b..d6ba790b06 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedForeignKey.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedForeignKey.scala @@ -95,7 +95,7 @@ with LifecycleCallbacks { private def checkTypes(km: KeyedMapper[KeyType, _]): Boolean = km.getSingleton eq foreignMeta - override def equals(other: Any) = other match { + override def equals(other: Any): Boolean = other match { case km: KeyedMapper[KeyType, Other] if checkTypes(km) => this.get == km.primaryKeyField.get case _ => super.equals(other) } @@ -124,7 +124,7 @@ with LifecycleCallbacks { */ def cached_? : Boolean = synchronized{ _calcedObj} - override protected def dirty_?(b: Boolean) = synchronized { // issue 165 + override protected def dirty_?(b: Boolean): Unit = synchronized { // issue 165 // invalidate if the primary key has changed Issue 370 if (_obj.isEmpty || (_calcedObj && _obj.isDefined && _obj.openOrThrowException("_obj was just checked as full.").primaryKeyField.get != this.i_is_!)) { @@ -151,13 +151,13 @@ with LifecycleCallbacks { _obj } - private[mapper] def _primeObj(obj: Box[Any]) = + private[mapper] def _primeObj(obj: Box[Any]): Unit = primeObj(obj.asInstanceOf[Box[Other]]) /** * Prime the reference of this FK reference */ - def primeObj(obj: Box[Other]) = synchronized { + def primeObj(obj: Box[Other]): Unit = synchronized { _obj = obj _calcedObj = true } @@ -194,7 +194,7 @@ with LifecycleCallbacks { * sets the field's value from obj if it's set to the default (!defined_?). * Overrides LifecycleCallbacks.beforeSave */ - override def beforeSave { + override def beforeSave: Unit = { if(!defined_?) for(o <- obj) set(o.primaryKeyField.get) @@ -212,7 +212,7 @@ with LifecycleCallbacks { abstract class MappedLongForeignKey[T<:Mapper[T],O<:KeyedMapper[Long, O]](theOwner: T, _foreignMeta: => KeyedMetaMapper[Long, O]) extends MappedLong[T](theOwner) with MappedForeignKey[Long,T,O] with BaseForeignKey { - def defined_? = i_is_! > 0L + def defined_? : Boolean = i_is_! > 0L def foreignMeta = _foreignMeta @@ -255,7 +255,7 @@ extends MappedLong[T](theOwner) with MappedForeignKey[Long,T,O] with BaseForeign */ def dbAddedForeignKey: Box[() => Unit] = Empty - override def toString = if (defined_?) super.toString else "NULL" + override def toString: String = if (defined_?) super.toString else "NULL" def findFor(key: KeyType): List[OwnerType] = theOwner.getSingleton.findAll(By(this, key)) @@ -272,7 +272,7 @@ extends MappedLong[T](theOwner) with MappedForeignKey[Long,T,O] with BaseForeign abstract class MappedStringForeignKey[T<:Mapper[T],O<:KeyedMapper[String, O]](override val fieldOwner: T, foreign: => KeyedMetaMapper[String, O],override val maxLen: Int) extends MappedString[T](fieldOwner, maxLen) with MappedForeignKey[String,T,O] with BaseForeignKey { - def defined_? = i_is_! ne null + def defined_? : Boolean = i_is_! ne null type KeyType = String type KeyedForeignType = O @@ -297,7 +297,7 @@ extends MappedString[T](fieldOwner, maxLen) with MappedForeignKey[String,T,O] wi */ def dbAddedForeignKey: Box[() => Unit] = Empty - override def toString = if (defined_?) super.toString else "NULL" + override def toString: String = if (defined_?) super.toString else "NULL" def set(v: Box[O]): T = { val toSet: String = v match { diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedInt.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedInt.scala index eec22ce66f..71c80a066e 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedInt.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedInt.scala @@ -17,7 +17,7 @@ package net.liftweb package mapper -import java.sql.{ResultSet, Types} +import java.sql.Types import java.lang.reflect.Method import net.liftweb.common._ import net.liftweb.util._ @@ -30,7 +30,6 @@ import scala.xml.{Text, NodeSeq} import js._ - /** * Warning: Do not use unnamed Enumerations with 2.8.1 as this will cause too many items to be displayed in the dropdown. * @@ -40,19 +39,19 @@ abstract class MappedEnum[T<:Mapper[T], ENUM <: Enumeration](val fieldOwner: T, private var data: ENUM#Value = defaultValue private var orgData: ENUM#Value = defaultValue def defaultValue: ENUM#Value = enum.values.iterator.next - def dbFieldClass = classOf[ENUM#Value] + def dbFieldClass: Class[ENUM#Value] = classOf[ENUM#Value] /** * Get the JDBC SQL Type for this field */ - def targetSQLType = Types.BIGINT + def targetSQLType: Int = Types.BIGINT - protected def i_is_! = data - protected def i_was_! = orgData + protected def i_is_! : ENUM#Value = data + protected def i_was_! : ENUM#Value = orgData /** * Called after the field is saved to the database */ - override protected[mapper] def doneWithSave() { + override protected[mapper] def doneWithSave(): Unit = { orgData = data } @@ -141,7 +140,7 @@ abstract class MappedEnum[T<:Mapper[T], ENUM <: Enumeration](val fieldOwner: T, protected def i_obscure_!(in : ENUM#Value) = defaultValue - private def st(in: ENUM#Value) { + private def st(in: ENUM#Value): Unit = { data = in orgData = in } @@ -251,12 +250,12 @@ abstract class MappedInt[T<:Mapper[T]](val fieldOwner: T) extends MappedField[In private var orgData: Int = defaultValue def defaultValue = 0 - def dbFieldClass = classOf[Int] + def dbFieldClass: Class[Int] = classOf[Int] /** * Get the JDBC SQL Type for this field */ - def targetSQLType = Types.INTEGER + def targetSQLType: Int = Types.INTEGER import scala.reflect.runtime.universe._ def manifest: TypeTag[Int] = typeTag[Int] @@ -302,12 +301,12 @@ abstract class MappedInt[T<:Mapper[T]](val fieldOwner: T) extends MappedField[In def asSeq(v: T): Box[Seq[SourceFieldInfo]] = Empty }) - protected def i_is_! = data - protected def i_was_! = orgData + protected def i_is_! : Int = data + protected def i_was_! : Int = orgData /** * Called after the field is saved to the database */ - override protected[mapper] def doneWithSave() { + override protected[mapper] def doneWithSave(): Unit = { orgData = data } @@ -349,7 +348,7 @@ abstract class MappedInt[T<:Mapper[T]](val fieldOwner: T) extends MappedField[In protected def i_obscure_!(in : Int) = 0 - private def st(in: Int) { + private def st(in: Int): Unit = { data = in orgData = in } diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedLong.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedLong.scala index dae152e042..d06bd9af5e 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedLong.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedLong.scala @@ -19,14 +19,16 @@ package mapper import java.sql.Types import java.lang.reflect.Method -import net.liftweb.util.Helpers._ -import net.liftweb.util._ -import net.liftweb.common._ import java.util.Date + +import common._ +import util.Helpers._ +import util._ +import http.SHtml +import http.js._ +import json._ + import scala.xml.{Text, NodeSeq} -import net.liftweb.http.{S, SHtml} -import net.liftweb.http.js._ -import net.liftweb.json._ abstract class MappedLongIndex[T<:Mapper[T]](theOwner: T) extends MappedLong[T](theOwner) with IndexedField[Long] { @@ -80,21 +82,19 @@ abstract class MappedEnumList[T<:Mapper[T], ENUM <: Enumeration](val fieldOwner: private var orgData: Seq[ENUM#Value] = defaultValue def defaultValue: Seq[ENUM#Value] = Nil - def dbFieldClass = classOf[Seq[ENUM#Value]] + def dbFieldClass: Class[Seq[ENUM#Value]] = classOf[Seq[ENUM#Value]] /** * Get the JDBC SQL Type for this field */ - def targetSQLType = Types.BIGINT + def targetSQLType: Int = Types.BIGINT - protected def i_is_! = data - protected def i_was_! = orgData + protected def i_is_! : Seq[ENUM#Value] = data + protected def i_was_! : Seq[ENUM#Value] = orgData /** * Called after the field is saved to the database */ - override protected[mapper] def doneWithSave() { - orgData = data - } + override protected[mapper] def doneWithSave(): Unit = orgData = data /** * Get the source field metadata for the field @@ -183,7 +183,7 @@ abstract class MappedEnumList[T<:Mapper[T], ENUM <: Enumeration](val fieldOwner: protected def i_obscure_!(in : Seq[ENUM#Value]) = Nil - private def st(in: Seq[ENUM#Value]) { + private def st(in: Seq[ENUM#Value]): Unit = { data = in orgData = in } @@ -219,7 +219,7 @@ abstract class MappedEnumList[T<:Mapper[T], ENUM <: Enumeration](val fieldOwner: * Mix with MappedLong to give a default time of millis */ trait DefaultMillis extends TypedField[Long] { - override def defaultValue = millis + override def defaultValue: Long = millis } @@ -228,12 +228,12 @@ abstract class MappedNullableLong[T<:Mapper[T]](val fieldOwner: T) extends Mappe private var orgData: Box[Long] = defaultValue def defaultValue: Box[Long] = Empty - def dbFieldClass = classOf[Box[Long]] + def dbFieldClass: Class[Box[Long]] = classOf[Box[Long]] /** * Get the JDBC SQL Type for this field */ - def targetSQLType = Types.BIGINT + def targetSQLType: Int = Types.BIGINT import scala.reflect.runtime.universe._ def manifest: TypeTag[Box[Long]] = typeTag[Box[Long]] @@ -280,12 +280,12 @@ abstract class MappedNullableLong[T<:Mapper[T]](val fieldOwner: T) extends Mappe }) - protected def i_is_! = data - protected def i_was_! = orgData + protected def i_is_! : Box[Long] = data + protected def i_was_! : Box[Long] = orgData /** * Called after the field is saved to the database */ - override protected[mapper] def doneWithSave() { + override protected[mapper] def doneWithSave(): Unit = { orgData = data } @@ -336,7 +336,7 @@ abstract class MappedNullableLong[T<:Mapper[T]](val fieldOwner: T) extends Mappe protected def i_obscure_!(in: Box[Long]) = defaultValue - private def st(in: Box[Long]) { + private def st(in: Box[Long]): Unit = { data = in orgData = in } @@ -410,19 +410,19 @@ abstract class MappedLong[T<:Mapper[T]](val fieldOwner: T) extends MappedField[L }) def defaultValue: Long = 0L - def dbFieldClass = classOf[Long] + def dbFieldClass: Class[Long] = classOf[Long] /** * Get the JDBC SQL Type for this field */ - def targetSQLType = Types.BIGINT + def targetSQLType: Int = Types.BIGINT - protected def i_is_! = data - protected def i_was_! = orgData + protected def i_is_! : Long = data + protected def i_was_! : Long = orgData /** * Called after the field is saved to the database */ - override protected[mapper] def doneWithSave() { + override protected[mapper] def doneWithSave(): Unit = { orgData = data } @@ -468,7 +468,7 @@ abstract class MappedLong[T<:Mapper[T]](val fieldOwner: T) extends MappedField[L protected def i_obscure_!(in : Long) = defaultValue - private def st(in: Long) { + private def st(in: Long): Unit = { data = in orgData = in } diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedPassword.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedPassword.scala index 18cf9642e5..588997e752 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedPassword.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedPassword.scala @@ -183,7 +183,7 @@ extends MappedField[String, T] { /** * Called after the field is saved to the database */ - override protected[mapper] def doneWithSave() { + override protected[mapper] def doneWithSave(): Unit = { } protected def i_obscure_!(in : String) : String = in diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedPostalCode.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedPostalCode.scala index f8754654c9..307b3c0e28 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedPostalCode.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedPostalCode.scala @@ -68,17 +68,16 @@ object Countries extends Enumeration(1) { def I18NCountry = new I18NCountry class I18NCountry extends Val { - override def toString() = - S.?("country_" + id) + override def toString(): String = S.?("country_" + id) } } abstract class MappedLocale[T <: Mapper[T]](owner: T) extends MappedString[T](owner, 16) { - override def defaultValue = Locale.getDefault.toString + override def defaultValue: String = Locale.getDefault.toString def isAsLocale: Locale = Locale.getAvailableLocales.filter(_.toString == get).toList match { case Nil => Locale.getDefault - case x :: xs => x + case x :: _ => x } override def _toForm: Box[Elem] = @@ -89,7 +88,7 @@ abstract class MappedLocale[T <: Mapper[T]](owner: T) extends MappedString[T](ow } abstract class MappedTimeZone[T <: Mapper[T]](owner: T) extends MappedString[T](owner, 32) { - override def defaultValue = TimeZone.getDefault.getID + override def defaultValue: String = TimeZone.getDefault.getID def isAsTimeZone: TimeZone = TimeZone.getTimeZone(get) match { case null => TimeZone.getDefault diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedString.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedString.scala index cb4e4c64b5..45e47acd1d 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedString.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedString.scala @@ -17,22 +17,18 @@ package net.liftweb package mapper -import java.sql.{ResultSet, Types} +import java.sql.Types import java.lang.reflect.Method -import util._ -import net.liftweb.common.{Box, Full, Empty, Failure} import java.util.Date -import java.util.regex._ -import scala.xml.{NodeSeq, Text, Elem} -import net.liftweb.http.{S} -import net.liftweb.http.js._ -import net.liftweb.json._ + +import util._ +import common.{Box, Full, Empty, Failure} +import http.S +import http.js._ +import json._ import S._ -import common.Full -import scala.Some -import common.Full -import scala.Some -import util.SourceFieldMetadataRep + +import scala.xml.{NodeSeq, Text, Elem} /** * Just like MappedString, except it's defaultValue is "" and the length is auto-cropped to @@ -62,7 +58,7 @@ abstract class MappedString[T<:Mapper[T]](val fieldOwner: T,val maxLen: Int) ext private val data: FatLazy[String] = FatLazy(defaultValue) // defaultValue private val orgData: FatLazy[String] = FatLazy(defaultValue) // defaultValue - def dbFieldClass = classOf[String] + def dbFieldClass: Class[String] = classOf[String] import scala.reflect.runtime.universe._ def manifest: TypeTag[String] = typeTag[String] @@ -123,15 +119,15 @@ abstract class MappedString[T<:Mapper[T]](val fieldOwner: T,val maxLen: Int) ext /** * Get the JDBC SQL Type for this field */ - def targetSQLType = Types.VARCHAR + def targetSQLType: Int = Types.VARCHAR def defaultValue = "" override def writePermission_? = true override def readPermission_? = true - protected def i_is_! = data.get - protected def i_was_! = orgData.get + protected def i_is_! : String = data.get + protected def i_was_! : String = orgData.get def asJsonValue: Box[JsonAST.JValue] = Full(get match { case null => JsonAST.JNull @@ -141,7 +137,7 @@ abstract class MappedString[T<:Mapper[T]](val fieldOwner: T,val maxLen: Int) ext /** * Called after the field is saved to the database */ - override protected[mapper] def doneWithSave() { + override protected[mapper] def doneWithSave(): Unit = { orgData.setFrom(data) } @@ -167,7 +163,7 @@ abstract class MappedString[T<:Mapper[T]](val fieldOwner: T,val maxLen: Int) ext override def setFromAny(in: Any): String = { in match { case JsonAST.JNull => this.set(null) - case seq: Seq[_] if !seq.isEmpty => seq.map(setFromAny).apply(0) + case seq: Seq[_] if seq.nonEmpty => seq.map(setFromAny).head case (s: String) :: _ => this.set(s) case s :: _ => this.setFromAny(s) case JsonAST.JString(v) => this.set(v) @@ -188,7 +184,7 @@ abstract class MappedString[T<:Mapper[T]](val fieldOwner: T,val maxLen: Int) ext def real_convertToJDBCFriendly(value: String): Object = value - private def wholeSet(in: String) { + private def wholeSet(in: String): Unit = { this.data() = in this.orgData() = in } diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedTextarea.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedTextarea.scala index 6dca64430a..c4a1b161f0 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedTextarea.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedTextarea.scala @@ -17,11 +17,10 @@ package net.liftweb package mapper -import scala.xml.{NodeSeq, Elem} -import net.liftweb.http.S -import net.liftweb.http.S._ -import net.liftweb.util._ -import net.liftweb.common._ +import http.S +import common._ + +import scala.xml.Elem abstract class MappedTextarea[T<:Mapper[T]](owner : T, maxLen: Int) extends MappedString[T](owner, maxLen) { /** @@ -37,7 +36,7 @@ abstract class MappedTextarea[T<:Mapper[T]](owner : T, maxLen: Int) extends Mapp case s => s}}))} } - override def toString = { + override def toString: String = { val v = get if (v == null || v.length < 100) super.toString else v.substring(0,40)+" ... "+v.substring(v.length - 40) diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedTime.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedTime.scala index bfde33d444..66ebb6ccb8 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedTime.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedTime.scala @@ -17,16 +17,14 @@ package net.liftweb package mapper -import java.sql.{ResultSet, Types} +import java.sql.Types import java.util.Date import java.lang.reflect.Method -import net.liftweb._ import util._ import common._ import Helpers._ import http._ -import S._ import js._ import json._ @@ -136,7 +134,7 @@ abstract class MappedTime[T<:Mapper[T]](val fieldOwner: T) extends MappedField[D protected def i_is_! = data.get protected def i_was_! = orgData.get - protected[mapper] def doneWithSave() {orgData.setFrom(data)} + protected[mapper] def doneWithSave(): Unit = {orgData.setFrom(data)} protected def i_obscure_!(in : Date) : Date = { new Date(0L) diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedUniqueId.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedUniqueId.scala index 372da1fb52..c61c313d49 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedUniqueId.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/MappedUniqueId.scala @@ -17,12 +17,12 @@ package net.liftweb package mapper -import net.liftweb.common._ -import net.liftweb.util._ +import common._ +import util._ import Helpers._ -import net.liftweb.http.{S, SHtml} +import http.{S, SHtml} + import scala.xml.NodeSeq -import net.liftweb.http.js._ abstract class MappedUniqueId[T<:Mapper[T]](override val fieldOwner: T, override val maxLen: Int) extends MappedString[T](fieldOwner, maxLen) { override def writePermission_? = false diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/Mapper.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/Mapper.scala index ebb9dbd176..c3d65d03db 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/Mapper.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/Mapper.scala @@ -17,15 +17,15 @@ package net.liftweb package mapper +import java.util.Date + import scala.xml.{Elem, NodeSeq} -import net.liftweb.http.S -import net.liftweb.http.js._ +import http.S +import http.js._ import util._ -import net.liftweb.common.{Box, Empty, Full, ParamFailure} +import common.{Box, Empty, Full, ParamFailure} + import collection.mutable.StringBuilder -import net.liftweb.util -import common.Full -import common.Full trait BaseMapper extends FieldContainer { type MapperType <: Mapper[MapperType] @@ -85,7 +85,7 @@ trait Mapper[A<:Mapper[A]] extends BaseMapper with Serializable with SourceInfo this } - def save(): Boolean = { + def save: Boolean = { runSafe { getSingleton.save(this) } @@ -161,7 +161,7 @@ trait Mapper[A<:Mapper[A]] extends BaseMapper with Serializable with SourceInfo def formFields: List[MappedField[_, A]] = getSingleton.formFields(this) - def allFields: scala.collection.Seq[BaseField] = formFields + def allFields: Seq[BaseField] = formFields /** * map the fields titles and forms to generate a list @@ -176,7 +176,7 @@ trait Mapper[A<:Mapper[A]] extends BaseMapper with Serializable with SourceInfo * @param func called with displayHtml, fieldId, form */ def flatMapFieldTitleForm[T] - (func: (NodeSeq, Box[NodeSeq], NodeSeq) => scala.collection.Seq[T]): List[T] = + (func: (NodeSeq, Box[NodeSeq], NodeSeq) => Seq[T]): List[T] = getSingleton.flatMapFieldTitleForm(this, func) /** @@ -184,7 +184,7 @@ trait Mapper[A<:Mapper[A]] extends BaseMapper with Serializable with SourceInfo * @param func called with displayHtml, fieldId, form */ def flatMapFieldTitleForm2[T] - (func: (NodeSeq, MappedField[_, A], NodeSeq) => scala.collection.Seq[T]): List[T] = + (func: (NodeSeq, MappedField[_, A], NodeSeq) => Seq[T]): List[T] = getSingleton.flatMapFieldTitleForm2(this, func) /** @@ -225,7 +225,7 @@ trait Mapper[A<:Mapper[A]] extends BaseMapper with Serializable with SourceInfo def toForm(button: Box[String], redoSnippet: NodeSeq => NodeSeq, onSuccess: A => Unit): NodeSeq = { val snipName = S.currentSnippet - def doSubmit() { + def doSubmit(): Unit = { this.validate match { case Nil => onSuccess(this) case xs => S.error(xs) @@ -247,25 +247,18 @@ trait Mapper[A<:Mapper[A]] extends BaseMapper with Serializable with SourceInfo def dirty_? : Boolean = getSingleton.dirty_?(this) - override def toString = { - val ret = new StringBuilder - - ret.append(this.getClass.getName) - - ret.append("={") - - ret.append(getSingleton.appendFieldToStrings(this)) - - ret.append("}") - - ret.toString - } + override def toString: String = + new StringBuilder(this.getClass.getName) + .append("={") + .append(getSingleton.appendFieldToStrings(this)) + .append("}") + .toString def toXml: Elem = { getSingleton.toXml(this) } - def checkNames { + def checkNames(): Unit = { runSafe { getSingleton match { case null => @@ -304,11 +297,11 @@ trait Mapper[A<:Mapper[A]] extends BaseMapper with Serializable with SourceInfo */ def fieldTransforms = fieldTransforms_i - def appendFieldTransform(transform: CssSel) { + def appendFieldTransform(transform: CssSel): Unit = { fieldTransforms_i = fieldTransforms_i :+ transform } - def prependFieldTransform(transform: CssSel) { + def prependFieldTransform(transform: CssSel): Unit = { fieldTransforms_i = transform +: fieldTransforms_i } @@ -405,9 +398,9 @@ trait UpdatedTrait { lazy val updatedAt: MyUpdatedAt = new MyUpdatedAt(this) protected class MyUpdatedAt(obj: self.type) extends MappedDateTime(obj.asInstanceOf[MapperType]) with LifecycleCallbacks { - override def beforeSave() {super.beforeSave; this.set(Helpers.now)} - override def defaultValue = Helpers.now - override def dbIndexed_? = updatedAtIndexed_? + override def beforeSave: Unit = {super.beforeSave; this.set(Helpers.now)} + override def defaultValue: Date = Helpers.now + override def dbIndexed_? : Boolean = updatedAtIndexed_? } } @@ -429,7 +422,7 @@ trait KeyedMapper[KeyType, OwnerType<:KeyedMapper[KeyType, OwnerType]] extends M def primaryKeyField: MappedField[KeyType, OwnerType] with IndexedField[KeyType] def getSingleton: KeyedMetaMapper[KeyType, OwnerType]; - override def comparePrimaryKeys(other: OwnerType) = primaryKeyField.get == other.primaryKeyField.get + override def comparePrimaryKeys(other: OwnerType): Boolean = primaryKeyField.get == other.primaryKeyField.get def reload: OwnerType = getSingleton.find(By(primaryKeyField, primaryKeyField.get)) openOr this diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/MetaMapper.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/MetaMapper.scala index d7ec3db8f2..a5c7cd89af 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/MetaMapper.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/MetaMapper.scala @@ -42,7 +42,7 @@ trait BaseMetaMapper { def dbTableName: String def _dbTableNameLC: String - def mappedFields: scala.collection.Seq[BaseMappedField]; + def mappedFields: Seq[BaseMappedField]; def dbAddTable: Box[() => Unit] def dbIndexes: List[BaseIndex[RealType]] @@ -91,13 +91,13 @@ object MapperRules extends Factory { * What are the rules and mechanisms for putting quotes around table names? */ val quoteTableName: FactoryMaker[String => String] = - new FactoryMaker[String => String]((s: String) => if (s.indexOf(' ') >= 0) '"'+s+'"' else s) {} + new FactoryMaker[String => String]((s: String) => if (s.indexOf(' ') >= 0) "\""+s+"\"" else s) {} /** * What are the rules and mechanisms for putting quotes around column names? */ val quoteColumnName: FactoryMaker[String => String] = - new FactoryMaker[String => String]((s: String) => if (s.indexOf(' ') >= 0) '"'+s+'"' else s) {} + new FactoryMaker[String => String]((s: String) => if (s.indexOf(' ') >= 0) "\""+s+"\"" else s) {} /** * Function that determines if foreign key constraints are @@ -173,7 +173,7 @@ trait MetaMapper[A<:Mapper[A]] extends BaseMetaMapper with Mapper[A] { */ def validation: List[A => List[FieldError]] = Nil - private def clearPostCommit(in: A) { + private def clearPostCommit(in: A): Unit = { in.addedPostCommit = false } @@ -271,7 +271,7 @@ trait MetaMapper[A<:Mapper[A]] extends BaseMetaMapper with Mapper[A] { //type OtherMapper = KeyedMapper[_, (T forSome {type T})] //type OtherMetaMapper = KeyedMetaMapper[_, OtherMapper] - def findAllFields(fields: scala.collection.Seq[SelectableField], + def findAllFields(fields: Seq[SelectableField], by: QueryParam[A]*): List[A] = findMapFieldDb(dbDefaultConnectionIdentifier, fields, by :_*)(v => Full(v)) @@ -759,7 +759,7 @@ trait MetaMapper[A<:Mapper[A]] extends BaseMetaMapper with Mapper[A] { index: Int, field: MappedField[_, A], columnName : String, - setObj : (PreparedStatement, Int, AnyRef, Int) => Unit) { + setObj : (PreparedStatement, Int, AnyRef, Int) => Unit): Unit = { setPreparedStatementValue(conn, st, index, field, field.targetSQLType(columnName), field.jdbcFriendly(columnName), @@ -784,7 +784,7 @@ trait MetaMapper[A<:Mapper[A]] extends BaseMetaMapper with Mapper[A] { field: BaseMappedField, columnType : Int, value : Object, - setObj : (PreparedStatement, Int, AnyRef, Int) => Unit) { + setObj : (PreparedStatement, Int, AnyRef, Int) => Unit): Unit = { // Remap the type if the driver wants val mappedColumnType = conn.driverType.columnTypeMap(columnType) @@ -905,7 +905,7 @@ trait MetaMapper[A<:Mapper[A]] extends BaseMetaMapper with Mapper[A] { val query = "INSERT INTO "+MapperRules.quoteTableName.vend(_dbTableNameLC)+" ("+columnNamesForInsert+") VALUES ("+columnQueriesForInsert+")" - def prepStat(st : PreparedStatement) { + def prepStat(st : PreparedStatement): Unit = { var colNum = 1 for (col <- mappedColumns) { @@ -1394,7 +1394,7 @@ trait MetaMapper[A<:Mapper[A]] extends BaseMetaMapper with Mapper[A] { private[mapper] lazy val internal_dbTableName = fixTableName(internalTableName_$_$) - private def setupInstanceForPostCommit(inst: A) { + private def setupInstanceForPostCommit(inst: A): Unit = { afterCommit match { case Nil => // If there's no post-commit functions, then don't @@ -1408,7 +1408,7 @@ trait MetaMapper[A<:Mapper[A]] extends BaseMetaMapper with Mapper[A] { } } - private def eachField(what: A, toRun: List[(A) => Any])(f: (LifecycleCallbacks) => Any) { + private def eachField(what: A, toRun: List[(A) => Any])(f: (LifecycleCallbacks) => Any): Unit = { mappedCallbacks.foreach (e => e._2.invoke(what) match { case lccb: LifecycleCallbacks => f(lccb) @@ -1416,26 +1416,26 @@ trait MetaMapper[A<:Mapper[A]] extends BaseMetaMapper with Mapper[A] { }) toRun.foreach{tf => tf(what)} } - private def _beforeValidation(what: A) {setupInstanceForPostCommit(what); eachField(what, beforeValidation) {field => field.beforeValidation} } - private def _beforeValidationOnCreate(what: A) {eachField(what, beforeValidationOnCreate) {field => field.beforeValidationOnCreate} } - private def _beforeValidationOnUpdate(what: A) {eachField(what, beforeValidationOnUpdate) {field => field.beforeValidationOnUpdate} } - private def _afterValidation(what: A) { eachField(what, afterValidation) {field => field.afterValidation} } - private def _afterValidationOnCreate(what: A) {eachField(what, afterValidationOnCreate) {field => field.afterValidationOnCreate} } - private def _afterValidationOnUpdate(what: A) {eachField(what, afterValidationOnUpdate) {field => field.afterValidationOnUpdate} } + private def _beforeValidation(what: A): Unit = {setupInstanceForPostCommit(what); eachField(what, beforeValidation) { field => field.beforeValidation} } + private def _beforeValidationOnCreate(what: A): Unit = {eachField(what, beforeValidationOnCreate) { field => field.beforeValidationOnCreate} } + private def _beforeValidationOnUpdate(what: A): Unit = {eachField(what, beforeValidationOnUpdate) { field => field.beforeValidationOnUpdate} } + private def _afterValidation(what: A): Unit = { eachField(what, afterValidation) { field => field.afterValidation} } + private def _afterValidationOnCreate(what: A): Unit = {eachField(what, afterValidationOnCreate) { field => field.afterValidationOnCreate} } + private def _afterValidationOnUpdate(what: A): Unit = {eachField(what, afterValidationOnUpdate) { field => field.afterValidationOnUpdate} } - private def _beforeSave(what: A) {setupInstanceForPostCommit(what); eachField(what, beforeSave) {field => field.beforeSave} } - private def _beforeCreate(what: A) { eachField(what, beforeCreate) {field => field.beforeCreate} } - private def _beforeUpdate(what: A) { eachField(what, beforeUpdate) {field => field.beforeUpdate} } + private def _beforeSave(what: A): Unit = {setupInstanceForPostCommit(what); eachField(what, beforeSave) { field => field.beforeSave} } + private def _beforeCreate(what: A): Unit = { eachField(what, beforeCreate) { field => field.beforeCreate} } + private def _beforeUpdate(what: A): Unit = { eachField(what, beforeUpdate) { field => field.beforeUpdate} } - private def _afterSave(what: A) {eachField(what, afterSave) {field => field.afterSave} } - private def _afterCreate(what: A) {eachField(what, afterCreate) {field => field.afterCreate} } - private def _afterUpdate(what: A) {eachField(what, afterUpdate) {field => field.afterUpdate} } + private def _afterSave(what: A): Unit = {eachField(what, afterSave) { field => field.afterSave} } + private def _afterCreate(what: A): Unit = {eachField(what, afterCreate) { field => field.afterCreate} } + private def _afterUpdate(what: A): Unit = {eachField(what, afterUpdate) { field => field.afterUpdate} } - private def _beforeDelete(what: A) {setupInstanceForPostCommit(what); eachField(what, beforeDelete) {field => field.beforeDelete} } - private def _afterDelete(what: A) {eachField(what, afterDelete) {field => field.afterDelete} } + private def _beforeDelete(what: A): Unit = {setupInstanceForPostCommit(what); eachField(what, beforeDelete) { field => field.beforeDelete} } + private def _afterDelete(what: A): Unit = {eachField(what, afterDelete) { field => field.afterDelete} } - def beforeSchemifier {} - def afterSchemifier {} + def beforeSchemifier: Unit = {} + def afterSchemifier: Unit = {} def dbIndexes: List[BaseIndex[A]] = Nil @@ -1605,12 +1605,10 @@ final case class InRaw[TheType <: extends QueryParam[TheType] object NotIn { - def fk[InnerMapper <: Mapper[InnerMapper], JoinTypeA, - Zoom <% QueryParam[InnerMapper], - OuterMapper <:KeyedMapper[JoinTypeA, OuterMapper]] - (fielda: MappedForeignKey[JoinTypeA, InnerMapper, OuterMapper], - qp: Zoom*): InThing[OuterMapper] - = { + def fk[InnerMapper <: Mapper[InnerMapper], JoinTypeA, Zoom, OuterMapper <: KeyedMapper[JoinTypeA, OuterMapper]]( + fielda: MappedForeignKey[JoinTypeA, InnerMapper, OuterMapper], + qp: Zoom* + )(implicit ev: Zoom => QueryParam[InnerMapper]): InThing[OuterMapper] = { new InThing[OuterMapper] { type JoinType = JoinTypeA type InnerType = InnerMapper @@ -1626,13 +1624,11 @@ object NotIn { } } - def apply[InnerMapper <: Mapper[InnerMapper], JoinTypeA, - Zoom <% QueryParam[InnerMapper], - OuterMapper <: Mapper[OuterMapper]] - (_outerField: MappedField[JoinTypeA, OuterMapper], - _innerField: MappedField[JoinTypeA, InnerMapper], - qp: Zoom*): InThing[OuterMapper] - = { + def apply[InnerMapper <: Mapper[InnerMapper], JoinTypeA, Zoom, OuterMapper <: Mapper[OuterMapper]]( + _outerField: MappedField[JoinTypeA, OuterMapper], + _innerField: MappedField[JoinTypeA, InnerMapper], + qp: Zoom* + )(implicit ev: Zoom => QueryParam[InnerMapper]): InThing[OuterMapper] = { new InThing[OuterMapper] { type JoinType = JoinTypeA type InnerType = InnerMapper @@ -1651,12 +1647,10 @@ object NotIn { } object In { - def fk[InnerMapper <: Mapper[InnerMapper], JoinTypeA, - Zoom <% QueryParam[InnerMapper], - OuterMapper <:KeyedMapper[JoinTypeA, OuterMapper]] - (fielda: MappedForeignKey[JoinTypeA, InnerMapper, OuterMapper], - qp: Zoom*): InThing[OuterMapper] - = { + def fk[InnerMapper <: Mapper[InnerMapper], JoinTypeA, Zoom, OuterMapper <: KeyedMapper[JoinTypeA, OuterMapper]]( + fielda: MappedForeignKey[JoinTypeA, InnerMapper, OuterMapper], + qp: Zoom* + )(implicit ev: Zoom => QueryParam[InnerMapper]): InThing[OuterMapper] = { new InThing[OuterMapper] { type JoinType = JoinTypeA type InnerType = InnerMapper @@ -1672,13 +1666,11 @@ object In { } } - def apply[InnerMapper <: Mapper[InnerMapper], JoinTypeA, - Zoom <% QueryParam[InnerMapper], - OuterMapper <: Mapper[OuterMapper]] - (_outerField: MappedField[JoinTypeA, OuterMapper], - _innerField: MappedField[JoinTypeA, InnerMapper], - qp: Zoom*): InThing[OuterMapper] - = { + def apply[InnerMapper <: Mapper[InnerMapper], JoinTypeA, Zoom, OuterMapper <: Mapper[OuterMapper]]( + _outerField: MappedField[JoinTypeA, OuterMapper], + _innerField: MappedField[JoinTypeA, InnerMapper], + qp: Zoom* + )(implicit ev: Zoom => QueryParam[InnerMapper]): InThing[OuterMapper] = { new InThing[OuterMapper] { type JoinType = JoinTypeA type InnerType = InnerMapper @@ -1709,7 +1701,7 @@ object NotLike { object By { import OprEnum._ - def apply[O <: Mapper[O], T, U <% T](field: MappedField[T, O], value: U) = Cmp[O,T](field, Eql, Full(value), Empty, Empty) + def apply[O <: Mapper[O], T, U](field: MappedField[T, O], value: U)(implicit ev: U => T) = Cmp[O,T](field, Eql, Full(value), Empty, Empty) def apply[O <: Mapper[O], T](field: MappedNullableField[T, O], value: Box[T]) = value match { case Full(x) => Cmp[O,Box[T]](field, Eql, Full(value), Empty, Empty) case _ => NullRef(field) @@ -1728,8 +1720,8 @@ object By_>= { import OprEnum._ - def apply[O <: Mapper[O], T, U <% T](field: MappedField[T, O], - value: U) = Cmp[O, T](field, >=, Full(value), Empty, Empty) + def apply[O <: Mapper[O], T, U](field: MappedField[T, O], + value: U)(implicit ev: U => T) = Cmp[O, T](field, >=, Full(value), Empty, Empty) def apply[O <: Mapper[O], T](field: MappedField[T, O], otherField: MappedField[T, O]) = Cmp[O, T](field, >=, Empty, Full(otherField), @@ -1740,8 +1732,8 @@ object By_<= { import OprEnum._ - def apply[O <: Mapper[O], T, U <% T](field: MappedField[T, O], - value: U) = Cmp[O, T](field, <=, Full(value), Empty, Empty) + def apply[O <: Mapper[O], T, U](field: MappedField[T, O], + value: U)(implicit ev: U => T) = Cmp[O, T](field, <=, Full(value), Empty, Empty) def apply[O <: Mapper[O], T](field: MappedField[T, O], otherField: MappedField[T, O]) = Cmp[O, T](field, <=, Empty, Full(otherField), @@ -1751,7 +1743,7 @@ object By_<= { object NotBy { import OprEnum._ - def apply[O <: Mapper[O], T, U <% T](field: MappedField[T, O], value: U) = Cmp[O,T](field, <>, Full(value), Empty, Empty) + def apply[O <: Mapper[O], T, U](field: MappedField[T, O], value: U)(implicit ev: U => T) = Cmp[O,T](field, <>, Full(value), Empty, Empty) def apply[O <: Mapper[O], T](field: MappedNullableField[T, O], value: Box[T]) = value match { case Full(x) => Cmp[O,Box[T]](field, <>, Full(value), Empty, Empty) @@ -1782,14 +1774,14 @@ object NotByRef { object By_> { import OprEnum._ - def apply[O <: Mapper[O], T, U <% T](field: MappedField[T, O], value: U) = Cmp[O,T](field, >, Full(value), Empty, Empty) + def apply[O <: Mapper[O], T, U](field: MappedField[T, O], value: U)(implicit ev: U => T) = Cmp[O,T](field, >, Full(value), Empty, Empty) def apply[O <: Mapper[O], T](field: MappedField[T, O], otherField: MappedField[T,O]) = Cmp[O,T](field, >, Empty, Full(otherField), Empty) } object By_< { import OprEnum._ - def apply[O <: Mapper[O], T, U <% T](field: MappedField[T, O], value: U) = Cmp[O,T](field, <, Full(value), Empty, Empty) + def apply[O <: Mapper[O], T, U](field: MappedField[T, O], value: U)(implicit ev: U => T) = Cmp[O,T](field, <, Full(value), Empty, Empty) def apply[O <: Mapper[O], T](field: MappedField[T, O], otherField: MappedField[T,O]) = Cmp[O,T](field, <, Empty, Full(otherField), Empty) } @@ -1874,15 +1866,15 @@ trait KeyedMetaMapper[Type, A<:KeyedMapper[Type, A]] extends MetaMapper[A] with def find(key: Any): Box[A] = key match { - case qp: QueryParam[A] => find(List(qp.asInstanceOf[QueryParam[A]]) :_*) - case prod: Product if (testProdArity(prod)) => find(convertToQPList(prod) :_*) + case qp: QueryParam[A] => find(qp) + case prod: Product if (testProdArity(prod)) => find(convertToQPList(prod).toIndexedSeq :_*) case key => anyToFindString(key) flatMap (find(_)) } def findDb(dbId: ConnectionIdentifier, key: Any): Box[A] = key match { case qp: QueryParam[A] => findDb(dbId, List(qp.asInstanceOf[QueryParam[A]]) :_*) - case prod: Product if (testProdArity(prod)) => findDb(dbId, convertToQPList(prod) :_*) + case prod: Product if (testProdArity(prod)) => findDb(dbId, convertToQPList(prod).toIndexedSeq :_*) case key => anyToFindString(key) flatMap (find(dbId, _)) } @@ -1947,6 +1939,8 @@ trait KeyedMetaMapper[Type, A<:KeyedMapper[Type, A]] extends MetaMapper[A] with } } + def find(by: QueryParam[A]): Box[A] = find(Seq(by): _*) + def find(by: QueryParam[A]*): Box[A] = findDb(dbDefaultConnectionIdentifier, by :_*) @@ -1973,7 +1967,7 @@ trait KeyedMetaMapper[Type, A<:KeyedMapper[Type, A]] extends MetaMapper[A] with } } - override def afterSchemifier { + override def afterSchemifier: Unit = { if (crudSnippets_?) { LiftRules.snippets.append(crudSnippets) } @@ -2014,7 +2008,7 @@ trait KeyedMetaMapper[Type, A<:KeyedMapper[Type, A]] extends MetaMapper[A] with def formSnippet(html: NodeSeq, obj: A, cleanup: (A => Unit)): NodeSeq = { val name = internal_dbTableName - def callback() { + def callback(): Unit = { cleanup(obj) } @@ -2115,14 +2109,14 @@ trait KeyedMetaMapper[Type, A<:KeyedMapper[Type, A]] extends MetaMapper[A] with * * @param obj mapped object of this metamapper's type */ - def editSnippetCallback(obj: A) { obj.save } + def editSnippetCallback(obj: A): Unit = { obj.save } /** * Default callback behavior of the add snippet. Called when the user * presses submit. Saves the passed in object. * * @param obj mapped object of this metamapper's type */ - def addSnippetCallback(obj: A) { obj.save } + def addSnippetCallback(obj: A): Unit = { obj.save } } @@ -2153,8 +2147,8 @@ class KeyObfuscator { obscure(what.getSingleton, what.primaryKeyField.get) } - def apply[KeyType, MetaType <: KeyedMapper[KeyType, MetaType], Q <% KeyType](theType: - KeyedMetaMapper[KeyType, MetaType], key: Q): String = { + def apply[KeyType, MetaType <: KeyedMapper[KeyType, MetaType], Q](theType: + KeyedMetaMapper[KeyType, MetaType], key: Q)(implicit ev: Q => KeyType): String = { val k: KeyType = key obscure(theType, k) } diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/ProtoExtendedSession.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/ProtoExtendedSession.scala index 75b4d74b9a..a28bfc7ba1 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/ProtoExtendedSession.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/ProtoExtendedSession.scala @@ -17,16 +17,14 @@ package net.liftweb package mapper -import net.liftweb._ -import net.liftweb.http.provider._ +import http.provider._ import common._ import util._ import http._ import Helpers._ -trait ProtoExtendedSession[T <: ProtoExtendedSession[T]] extends -KeyedMapper[Long, T] { +trait ProtoExtendedSession[T <: ProtoExtendedSession[T]] extends KeyedMapper[Long, T] { self: T => override def primaryKeyField: MappedLongIndex[T] = id @@ -95,16 +93,16 @@ KeyedMetaMapper[Long, T] with ProtoSessionCookiePath { def recoverUserId: Box[String] - def userDidLogin(uid: UserType) { + def userDidLogin(uid: UserType): Unit = { userDidLogout(Full(uid)) - val inst = create.userId(uid.userIdAsString).saveMe + val inst = create.userId(uid.userIdAsString).saveMe() val cookie = HTTPCookie(CookieName, inst.cookieId.get). setMaxAge(((inst.expiration.get - millis) / 1000L).toInt). setPath(sessionCookiePath) S.addCookie(cookie) } - def userDidLogout(uid: Box[UserType]) { + def userDidLogout(uid: Box[UserType]): Unit = { for (cook <- S.findCookie(CookieName)) { S.deleteCookie(cook) find(By(cookieId, cook.value openOr "")).foreach(_.delete_!) diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/ProtoTag.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/ProtoTag.scala index 81775ad079..e36e8eaebf 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/ProtoTag.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/ProtoTag.scala @@ -35,7 +35,7 @@ trait MetaProtoTag[ModelType <: ProtoTag[ModelType]] extends KeyedMetaMapper[Lon else { find(By(name, tag)) match { case Full(t) => tagCache(tag) = t; t - case _ => val ret: ModelType = (createInstance).name(tag).saveMe + case _ => val ret: ModelType = createInstance.name(tag).saveMe tagCache(tag) = ret ret } diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/ProtoUser.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/ProtoUser.scala index 9dd169dfce..d181721212 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/ProtoUser.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/ProtoUser.scala @@ -17,19 +17,12 @@ package net.liftweb package mapper -import net.liftweb.http._ -import js._ -import JsCmds._ -import scala.xml.{NodeSeq, Node, Text, Elem} -import scala.xml.transform._ -import net.liftweb.sitemap._ -import net.liftweb.sitemap.Loc._ -import net.liftweb.util.Helpers._ -import net.liftweb.util._ -import net.liftweb.common._ -import net.liftweb.util.Mailer._ -import S._ -import net.liftweb.proto.{ProtoUser => GenProtoUser} +import http._ +import util._ +import common._ +import proto.{ProtoUser => GenProtoUser} + +import scala.xml.{NodeSeq, Text} /** * ProtoUser is a base class that gives you a "User" that has a first name, diff --git a/persistence/mapper/src/main/scala/net/liftweb/mapper/Schemifier.scala b/persistence/mapper/src/main/scala/net/liftweb/mapper/Schemifier.scala index e4b4928be1..330f537232 100644 --- a/persistence/mapper/src/main/scala/net/liftweb/mapper/Schemifier.scala +++ b/persistence/mapper/src/main/scala/net/liftweb/mapper/Schemifier.scala @@ -17,14 +17,15 @@ package net.liftweb package mapper -import java.sql.{Connection, ResultSet, DatabaseMetaData} +import java.sql.{Connection, DatabaseMetaData, ResultSet} import scala.collection.mutable.{HashMap, ListBuffer} - -import common.{Full, Box, Loggable} +import common.{Box, Full, Loggable} import util.Helpers import Helpers._ +import scala.annotation.tailrec + /** * Given a list of MetaMappers, make sure the database has the right schema *