Impressive body of work there ;-)
Stating the obvious, would breaking the array out into a join table be
of any interest?
Assume not given the effort you've put in to getting the existing
setup working.
As for the filter/select error, does "inSet" provide any relief?
On Oct 24, 11:11 pm, Adam Mackler <
adammack...@gmail.com> wrote:
> Having partially answered the above question, I'm putting my results on the
> record here before I forget what I've done. In three steps I (1) created a
> PostgreSQL database that uses array-typed columns, (2) put Scala/SLICK code
> into a file, and (3) loaded that file in the REPL shell and did some
> array-based interactions with the database. The upshot is that so far I am
> able to insert, retrieve, and update array values to the database, but have
> not yet figured out how to restrict (SELECT) rows from the database using a
> predicate that filters according to the array value of a column. Here are
> the steps to recreate my results:
>
> 1) Create a database called *sandbox*, and give it a table that holds both
> arrays of integers, and arrays of VARCHARs:
>
> *CREATE TABLE hasarrays (*
> * id integer NOT NULL,*
> * ofints integer[] NOT NULL,*
> * ofvarchars character varying(8)[] NOT NULL*
> *);*
>
> 2) Create a file called *ArrayMappers.scala* that contains the following
> code:
>
> *import scala.slick.lifted.BaseTypeMapper*
> *import scala.slick.driver.PostgresDriver.simple._*
> *import scala.slick.driver.BasicProfile*
> *import scala.slick.session.{PositionedParameters,PositionedResult}*
> *
> *
> *import language.implicitConversions*
> *
> *
> *object DB {*
> * def database = {*
> * val ds = new org.postgresql.ds.PGSimpleDataSource*
> * ds.setDatabaseName("sandbox")*
> * scala.slick.session.Database.forDataSource(ds)*
> * }*
> *
> *
> * val session = database.createSession()*
> *}*
> *
> *
> *abstract class ArrayTypeMapper[T: scala.reflect.ClassTag] extends*
> * BaseTypeMapper[Array[T]] with TypeMapperDelegate[Array[T]] {*
> * def apply(p: BasicProfile) = this*
> * def sqlType = java.sql.Types.ARRAY*
> *
> *
> * implicit def stringArrayToSqlArray(in: Array[String]): java.sql.Array =*
> * DB.session.conn.createArrayOf("varchar", in.map(e =>
> e.asInstanceOf[Object]))*
> *
> *
> * implicit def intArrayToSqlArray(in: Array[Int]): java.sql.Array = *
> * DB.session.conn.createArrayOf("int4", in.map(e => e: Integer))*
> *}*
> *
> *
> *object IntArrayTypeMapper extends ArrayTypeMapper[Int] {*
> *
> *
> * def zero = Array[Int]()*
> *
> *
> * def setValue(value: Array[Int], p: PositionedParameters) {*
> * val npos = p.pos + 1*
> * p.ps.setArray(npos, value)*
> * p.pos = npos*
> * }*
> *
> *
> * def setOption(o: Option[Array[Int]], p: PositionedParameters) {*
> * val npos = p.pos + 1*
> * if(o eq None) p.ps.setNull(npos, sqlType) else p.ps.setArray(npos,
> o.get)*
> * p.pos = npos*
> * }*
> *
> *
> * def nextValue(r: PositionedResult) = {*
> * val npos = r.currentPos + 1*
> * val a = r.rs.getArray(npos)*
> * r.skip*
> * a.getArray.asInstanceOf[Array[Integer]].map(i => i:Int)*
> * }*
> *
> *
> * final def updateValue(value: Array[Int], r: PositionedResult) {*
> * val npos = r.currentPos + 1*
> * r.rs.updateArray (npos, value)*
> * r.skip*
> * }*
> * // TODO is this correct?*
> * override def valueToSQLLiteral(v: Array[Int]) = "'" + v + "'"*
> *}*
> *
> *
> *object StringArrayTypeMapper extends ArrayTypeMapper[String] {*
> *
> *
> * def zero = Array[String]()*
> *
> *
> * def setValue(value: Array[String], p: PositionedParameters) {*
> * val npos = p.pos + 1*
> * p.ps.setArray(npos, value)*
> * p.pos = npos*
> * }*
> *
> *
> * def setOption(value: Option[Array[String]], p: PositionedParameters) {*
> * val npos = p.pos + 1*
> * if (value eq None) p.ps.setNull(npos, sqlType)*
> * else p.ps.setArray(npos, value.get)*
> * p.pos = npos*
> * }*
> *
> *
> * def nextValue(r: PositionedResult) = {*
> * val npos = r.currentPos + 1*
> * val a = r.rs.getArray(npos)*
> * r.skip*
> * a.getArray.asInstanceOf[Array[String]]*
> * }*
> *
> *
> * final def updateValue(value: Array[String], r: PositionedResult) {*
> * val npos = r.currentPos + 1*
> * r.rs.updateArray (npos, value)*
> * r.skip*
> * }*
> * // TODO is this correct?*
> * override def valueToSQLLiteral(v: Array[String]) = "'" + v + "'"*
> *}*
> *
> *
> *object HasArrays extends Table[(Int, Array[Int],
> Array[String])]("hasarrays") {*
> * def id = column[Int]("id")*
> * def ofInt = column[Array[Int]]("ofints")(IntArrayTypeMapper)*
> * def ofString = column[Array[String]]("ofvarchars")(StringArrayTypeMapper)
> *
> * def * = id ~ ofInt ~ ofString*
> *}*
>
> 3) Here is a REPL log showing what worked and didn't work:
>
> *scala> :load ArrayMappers.scala*
> *Loading ArrayMappers.scala...*
>
> *scala> val projection = HasArrays.id ~ HasArrays.ofInt ~ HasArrays.ofString
> *
> *projection: scala.slick.lifted.Projection3[Int,Array[Int],Array[String]] =
> Projection3*
> *
> *
> *scala> projection.insert(1, Array(2,5,12,-2),
> Array("foo","bar","baz"))(DB.session)*
> *res0: Int = 1*
> *
> *
> *scala> HasArrays.map(_.ofString).first()(DB.session)*
> *res1: Array[String] = Array(foo, bar, baz)*
> *
> *
> *scala> HasArrays.map(_.ofInt).first()(DB.session)*
> *res2: Array[Int] = Array(2, 5, 12, -2)*
> *
> *
> *scala> projection.insert(2, Array(2,3,1), Array("
> qu'x\\","b}l\"etch","wal,do "))(DB.session)*
> *res3: Int = 1*
> *
> *
> *scala> HasArrays.filter(_.id === 2).map(_.ofString).first()(DB.session)*
> *res4: Array[String] = Array(" qu'x\", b}l"etch, "wal,do ")*
> *
> *
> *scala> HasArrays.filter(_.id ===
> 2).map(_.ofString).update(Array("a","b","d"))(DB.session)*
> *res5: Int = 1*
> *
> *
> *scala> HasArrays.filter(_.id === 2).map(_.ofString).first()(DB.session)*
> *res6: Array[String] = Array(a, b, d)*
> *
> *
> *scala> HasArrays.filter(_.ofInt ===
> Array(2,3,1)).map(_.ofString).first()(DB.session)*
> *<console>:20: error: value === is not a member of
> scala.slick.lifted.Column[Array[Int]]*
> * HasArrays.filter(_.ofInt ===
> Array(2,3,1)).map(_.ofString).first()(DB.session)*
> * ^*