# HG changeset patch # User Tomas Zeman # Date 1328863985 -3600 # Node ID 828565e7f57147eabcee24e685fa7d6947cf4aab # Parent 8ef5e77ad79eaf44ec6a89eb34ad84380a631eb7 ff8d393251d4dae6 Contact model diff -r 8ef5e77ad79e -r 828565e7f571 src/main/scala/fis/base/model/BaseSchema.scala --- a/src/main/scala/fis/base/model/BaseSchema.scala Fri Feb 10 09:53:04 2012 +0100 +++ b/src/main/scala/fis/base/model/BaseSchema.scala Fri Feb 10 09:53:05 2012 +0100 @@ -15,22 +15,70 @@ */ package fis.base.model -import org.squeryl.{Schema, Table} import net.liftweb.squerylrecord.RecordTypeMode._ +import net.liftweb.util.Helpers.{snakify, tryo} +import org.squeryl.{Schema, Session, Table} +import org.squeryl.internals.StatementWriter +import scala.collection.mutable.ListBuffer trait BaseSchema extends Schema { - val codeListItems = entityTable[CodeListItem] + val entityTableName = "entity" + val entities = new Table[EntityUnion](entityTableName) { + val tables = new ListBuffer[String] + } + + val codeListItems = entityTable[CodeListItem]("code_list_item") + + override def tableNameFromClass(c: Class[_]): String = + snakify(c.getSimpleName) + + protected def entityTable[T <: Entity[_]](name: String)(implicit manifestT: + Manifest[T]): Table[T] = { + + val tbl = table(name)(manifestT) + on(tbl) { t => declare(t.id.is(autoIncremented("entity_id_seq"))) } + entities.tables += name + tbl + } - protected def entityTable[T <: Entity[_]]()(implicit manifestT: Manifest[T]): - Table[T] = { + override def create = { + table[EntityUnion](entityTableName) // register entity table as the last one + super.create + } - val tbl = table() - on(tbl) { t => declare(t.id.is(autoIncremented("entity_id_seq"))) } - tbl + override protected def drop = { + val dba = Session.currentSession.databaseAdapter + val sw = new StatementWriter(dba) + sw.write("drop view " + entityTableName + " cascade") + ex(sw) + super.drop + } + + private def ex(sw: StatementWriter) = { + val sql = sw.statement + val cs = Session.currentSession + cs.log(sql) + val s = cs.connection.createStatement + tryo { s.execute(sql) } + tryo { s.close } } } object BaseSchema extends BaseSchema +class EntityViewH2Adapter extends SeqIdH2Adapter { + override def writeCreateTable[T](t: Table[T], sw: StatementWriter, + schema: Schema) = schema match { + case sch: BaseSchema if t.name == sch.entityTableName => + sw.write("create view " + t.name + " as ") + val it = sch.entities.tables.iterator + while (it.hasNext) { + sw.write("select id, name, note from " + it.next) + if (it.hasNext) + sw.write(" union ") + } + case _ => super.writeCreateTable(t, sw, schema) + } +} // vim: set ts=2 sw=2 et: diff -r 8ef5e77ad79e -r 828565e7f571 src/main/scala/fis/base/model/Entity.scala --- a/src/main/scala/fis/base/model/Entity.scala Fri Feb 10 09:53:04 2012 +0100 +++ b/src/main/scala/fis/base/model/Entity.scala Fri Feb 10 09:53:05 2012 +0100 @@ -15,7 +15,7 @@ */ package fis.base.model -import net.liftweb.record.Record +import net.liftweb.record.{MetaRecord, Record} import net.liftweb.record.field._ import net.liftweb.squerylrecord.KeyedRecord import org.squeryl.annotations.Column @@ -54,6 +54,18 @@ def entity: T } +class EntityUnion private() extends Record[EntityUnion] with + Entity[EntityUnion] { + def meta = EntityUnion + //val entityType = new LongField(this) +} + +object EntityUnion extends EntityUnion with MetaRecord[EntityUnion] with + MetaEntity[EntityUnion] { + + def getTable = BaseSchema.entities +} + /** * Converter interface mixin. */ diff -r 8ef5e77ad79e -r 828565e7f571 src/main/scala/fis/crm/model/Contact.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/scala/fis/crm/model/Contact.scala Fri Feb 10 09:53:05 2012 +0100 @@ -0,0 +1,62 @@ +/* + * Copyright 2011 Tomas Zeman + * + * 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 fis.crm.model + +import fis.base.model.{Entity, MetaEntity} +import net.liftweb.record.{MetaRecord, Record} +import net.liftweb.record.field._ + +class Contact private() extends Record[Contact] with Entity[Contact] { + + def meta = Contact + + val firstName = new StringField(this, 80, "") + val lastName = new StringField(this, 80, "") + val position = new OptionalStringField(this, 40) + val workMail = new EmailField(this, 256) + val privateMail = new OptionalEmailField(this, 256) + val otherMail = new OptionalEmailField(this, 256) + val workMobile = new StringField(this, 40) + val privateMobile = new OptionalStringField(this, 40) + val otherMobile = new OptionalStringField(this, 40) + val workPhone = new OptionalStringField(this, 40) + val privatePhone = new OptionalStringField(this, 40) + val fax = new OptionalStringField(this, 40) + + override def linkName = lastName.get + " " + firstName.get + + lazy val entities = CrmSchema.entityContacts.right(this) +} + +object Contact extends Contact with MetaRecord[Contact] with + MetaEntity[Contact] { + + def getTable = CrmSchema.contacts +} + +import org.squeryl.KeyedEntity +import org.squeryl.dsl.CompositeKey3 + +case class EntityContact(val entityId: Long, val contactId: Long, + val typeId: Long) extends KeyedEntity[CompositeKey3[Long, Long, Long]] { + + def id = CompositeKey3(entityId, contactId, typeId) + + lazy val contactType = + CrmSchema.contactTypeToEntityContacts.rightStateful(this) +} + +// vim: set ts=2 sw=2 et: diff -r 8ef5e77ad79e -r 828565e7f571 src/main/scala/fis/crm/model/CrmSchema.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/scala/fis/crm/model/CrmSchema.scala Fri Feb 10 09:53:05 2012 +0100 @@ -0,0 +1,39 @@ +/* + * Copyright 2011 Tomas Zeman + * + * 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 fis.crm.model + +import fis.base.model.BaseSchema +import net.liftweb.squerylrecord.RecordTypeMode._ + +trait CrmSchema extends BaseSchema { + + val contacts = entityTable[Contact]("contact") + + val entityContacts = manyToManyRelation(entities, contacts). + via[EntityContact]((e, c, ec) => ( + e.id === ec.entityId, + c.id === ec.contactId + )) + + entityContacts.leftForeignKeyDeclaration.unConstrainReference + + val contactTypeToEntityContacts = oneToManyRelation(codeListItems, + entityContacts).via((cli, ec) => cli.id === ec.typeId) +} + +object CrmSchema extends CrmSchema + +// vim: set ts=2 sw=2 et: diff -r 8ef5e77ad79e -r 828565e7f571 src/test/scala/fis/base/model/AbstractTest.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/scala/fis/base/model/AbstractTest.scala Fri Feb 10 09:53:05 2012 +0100 @@ -0,0 +1,61 @@ +/* + * Copyright 2011 Tomas Zeman + * + * 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 fis.base.model + +import net.liftweb.common._ +import net.liftweb.mapper.DB +import net.liftweb.squerylrecord.SquerylRecord +import org.scalatest._ +import org.scalatest.matchers.ShouldMatchers + +abstract class AbstractTest extends FlatSpec with ShouldMatchers with Logger + with BeforeAndAfterEach with BeforeAndAfterAll { + + val db = this.getClass.getSimpleName + val h2vendor = H2Vendor(db) + val ci = TestConnectionIdentifier(db) + + override def beforeAll() { + beforeEach() + } + + override def beforeEach() { + super.beforeEach + DB.defineConnectionManager(ci, h2vendor) + SquerylRecord.init(() => new EntityViewH2Adapter) + } + + override def afterEach() { + h2vendor.closeAllConnections_! + } + + def doInDB(block: => Any) { + DB.use(ci) { _ => block } + } + +} + +import org.squeryl.Schema + +trait DropAndCreate { self: Schema => + def dropAndCreate { + drop + create + } +} + + +// vim: set ts=2 sw=2 et: diff -r 8ef5e77ad79e -r 828565e7f571 src/test/scala/fis/base/model/CodeListSpec.scala --- a/src/test/scala/fis/base/model/CodeListSpec.scala Fri Feb 10 09:53:04 2012 +0100 +++ b/src/test/scala/fis/base/model/CodeListSpec.scala Fri Feb 10 09:53:05 2012 +0100 @@ -17,23 +17,16 @@ import net.liftweb.common._ import org.scalatest._ -import org.scalatest.matchers.ShouldMatchers -class CodeListSpec extends FlatSpec with ShouldMatchers with Logger - with BeforeAndAfterAllFunctions { +class CodeListSpec extends AbstractTest { - import net.liftweb.mapper.{DB, DefaultConnectionIdentifier, StandardDBVendor} import net.liftweb.squerylrecord.RecordTypeMode._ import net.liftweb.squerylrecord.SquerylRecord - import TestBaseSchema._ + import BaseSchema._ - val dbVendor = new StandardDBVendor("org.h2.Driver", - "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", Empty, Empty) - DB.defineConnectionManager(DefaultConnectionIdentifier, dbVendor) - SquerylRecord.init(() => new SeqIdH2Adapter) - - beforeAll { - doInDB { dropAndCreate } + override def beforeAll { + super.beforeAll + doInDB { schema.dropAndCreate } } "CodeListItem" should "create/retrieve item" in { @@ -50,16 +43,7 @@ } } - def doInDB(block: => Any) { - DB.use(DefaultConnectionIdentifier) { _ => block } - } -} - -object TestBaseSchema extends BaseSchema { - def dropAndCreate { - drop - create - } + object schema extends BaseSchema with DropAndCreate } // vim: set ts=2 sw=2 et: diff -r 8ef5e77ad79e -r 828565e7f571 src/test/scala/fis/base/model/H2Vendor.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/scala/fis/base/model/H2Vendor.scala Fri Feb 10 09:53:05 2012 +0100 @@ -0,0 +1,28 @@ +/* + * Copyright 2011 Tomas Zeman + * + * 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 fis.base.model + +import net.liftweb.common._ +import net.liftweb.mapper.ConnectionIdentifier +import net.tz.lift.util.StandardDBVendor + +case class H2Vendor(val db: String) extends StandardDBVendor("org.h2.Driver", + "jdbc:h2:mem:"+ db + ";DB_CLOSE_DELAY=-1", Empty, Empty) + +case class TestConnectionIdentifier(val jndiName: String) extends + ConnectionIdentifier + +// vim: set ts=2 sw=2 et: diff -r 8ef5e77ad79e -r 828565e7f571 src/test/scala/fis/base/model/SeqIdPostgreSqlAdapterSpec.scala --- a/src/test/scala/fis/base/model/SeqIdPostgreSqlAdapterSpec.scala Fri Feb 10 09:53:04 2012 +0100 +++ b/src/test/scala/fis/base/model/SeqIdPostgreSqlAdapterSpec.scala Fri Feb 10 09:53:05 2012 +0100 @@ -23,7 +23,7 @@ with Logger with BeforeAndAfterAllFunctions { import java.sql.Connection - import net.liftweb.mapper.{DB, DefaultConnectionIdentifier} + import net.liftweb.mapper.DB import net.liftweb.squerylrecord.SquerylRecord import net.tz.lift.util.StandardDBVendor import org.squeryl.PrimitiveTypeMode._ @@ -36,7 +36,7 @@ c.prepareStatement(testQuery).executeQuery } } - DB.defineConnectionManager(DefaultConnectionIdentifier, dbVendor) + DB.defineConnectionManager(PgsqlConnectionIdentifier, dbVendor) SquerylRecord.init(() => new SeqIdPostgreSqlAdapter) beforeAll { @@ -70,13 +70,19 @@ } def doInDB(block: => Any) { - DB.use(DefaultConnectionIdentifier) { c => + DB.use(PgsqlConnectionIdentifier) { c => block c.commit } } } +import net.liftweb.db.ConnectionIdentifier + +case object PgsqlConnectionIdentifier extends ConnectionIdentifier { + val jndiName = "pgsql" +} + import org.squeryl.{KeyedEntity, Schema} import org.squeryl.PrimitiveTypeMode._ diff -r 8ef5e77ad79e -r 828565e7f571 src/test/scala/fis/crm/model/ContactSpec.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/scala/fis/crm/model/ContactSpec.scala Fri Feb 10 09:53:05 2012 +0100 @@ -0,0 +1,54 @@ +/* + * Copyright 2011 Tomas Zeman + * + * 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 fis.crm.model + +import fis.base.model._ +import net.liftweb.common._ +import net.liftweb.util._ +import net.liftweb.util.Helpers._ +import org.scalatest._ + +class ContactSpec extends AbstractTest { + import CrmSchema._ + + override def beforeAll() { + super.beforeAll + doInDB { schema.dropAndCreate } + } + + "EntityContact" should "create" in { doInDB { + val c1 = Contact.createRecord.name("c1") + contacts.insert(c1) + val t1 = CodeListItem.createRecord.name("t1") + codeListItems.insert(t1) + val c2 = Contact.createRecord.name("c2") // acts here as entity + contacts.insert(c2) + entityContacts.insert(EntityContact(c2.id, c1.id, t1.id)) + + val el1 = c1.entities.toList + el1.size should equal (1) + el1.head.id should equal (c2.id) + el1.head.name.get should equal ("c2") + val al1 = c1.entities.associations.toList + al1.size should equal (1) + al1.head.contactType.one should equal (Some(t1)) + }} + + object schema extends CrmSchema with DropAndCreate + +} + +// vim: set ts=2 sw=2 et: diff -r 8ef5e77ad79e -r 828565e7f571 src/test/scala/fis/crm/model/CrmSchemaSpec.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/scala/fis/crm/model/CrmSchemaSpec.scala Fri Feb 10 09:53:05 2012 +0100 @@ -0,0 +1,35 @@ +/* + * Copyright 2011 Tomas Zeman + * + * 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 fis.crm.model + +import fis.base.model._ +import net.liftweb.common._ +import net.liftweb.util._ +import net.liftweb.util.Helpers._ + +class CrmSchemaSpec extends AbstractTest { + + "CrmSchema" should "create" in { doInDB { + schema.dropAndCreate + }} + + object schema extends CrmSchema with DropAndCreate + +} + + + +// vim: set ts=2 sw=2 et: