从postgres ltree列设置的Anorm字符串

时间:2013-02-06 14:15:13

标签: scala anorm

我有一个表,其中一列具有ltree类型,以及以下代码从中获取数据:

SQL("""select * from "queue"""")()
.map(
    row =>
        {
            val queue =
                Queue(
                    row[String]("path"),
                    row[String]("email_recipients"),
                    new DateTime(row[java.util.Date]("created_at")),
                    row[Boolean]("template_required")
                )
            queue
        }
).toList

会导致以下错误:

RuntimeException: TypeDoesNotMatch(Cannot convert notification.en.incident_happened:class org.postgresql.util.PGobject to String for column ColumnName(queue.path,Some(path)))

队列表模式如下:

CREATE TABLE queue
(
  id serial NOT NULL,
  template_id integer,
  template_version integer,
  path ltree NOT NULL,
  json_params text,
  email_recipients character varying(1024) NOT NULL,
  email_from character varying(128),
  email_subject character varying(512),
  created_at timestamp with time zone NOT NULL,
  sent_at timestamp with time zone,
  failed_recipients character varying(1024),
  template_required boolean NOT NULL DEFAULT true,
  attachments hstore,
  CONSTRAINT pk_queue PRIMARY KEY (id ),
  CONSTRAINT fk_queue__email_template FOREIGN KEY (template_id)
      REFERENCES email_template (id) MATCH SIMPLE
      ON UPDATE CASCADE ON DELETE RESTRICT
)
WITH (
  OIDS=FALSE
);
ALTER TABLE queue
  OWNER TO postgres;
GRANT ALL ON TABLE queue TO postgres;
GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE queue TO writer;
GRANT SELECT ON TABLE queue TO reader;

为什么? notification.en.incident_happened只是一个普通的字符串吗?或者我错过了什么?

UPD

这个问题仍然适用,但这是一个解决方法:

SQL("""select id, path::varchar, email_recipients, created_at, template_required from "queue"""")()

1 个答案:

答案 0 :(得分:4)

这看起来像一个有趣的项目,所以我实现了ltree列映射器。

我捎带anorm-postgresql,因为那个项目已经在anorm中实现了一些postgres类型。它看起来不错,如果它实现了全系列的postgres类型,它会很有用。我的代码已合并,因此您可以使用该库。或者,只需使用以下代码:

import org.postgresql.util.PGobject
import anorm._
object LTree {
  implicit def rowToStringSeq: Column[Seq[String]] = Column.nonNull { (value, meta) =>
    val MetaDataItem(qualified, nullable, clazz) = meta
      value match {
        case pgo:PGobject => {
          val seq = pgo.getValue().split('.')
          Right(seq.toSeq)
        }
        case x => Left(TypeDoesNotMatch(x.getClass.toString))
      }
    }
    implicit def stringSeqToStatement = new ToStatement[Seq[String]] {
      def set(s: java.sql.PreparedStatement, index: Int, aValue: Seq[String]) {
      val stringRepresentation = aValue.mkString(".")
      val pgo:org.postgresql.util.PGobject = new org.postgresql.util.PGobject()
      pgo.setType("ltree");
      pgo.setValue( stringRepresentation );
      s.setObject(index, pgo)
    }
  }
}

然后,您可以将ltree映射到Seq[String]。请注意,它是路径元素序列顺序的序列,因此它是Seq[String],而不是StringSet[String]。如果你想要一个字符串,只需说path.mkString(".")。用法如下:

import LTree._

SQL("""select * from "queue"""")()
.map(
    row =>
        {
            val queue =
                Queue(
                    row[Seq[String]]("path"),
                    row[String]("email_recipients"),
                    new DateTime(row[java.util.Date]("created_at")),
                    row[Boolean]("template_required")
                )
            queue
        }
).toList