2016-07-18 32 views
1

Ich verwende scala, play, sclick; und postgres. Ich habe eine Tabelle mit dem Namen order & gemacht, die ein Feld mit dem Namen created im Zeitstempelformat mit Zone enthält. Nun möchte Ich mag auf order basierend auf created mit Parametern suchen year & month wie folgt: -Wie filtere ich das Datum in Play-SLICK, das als Instant gespeichert wird?

SELECT * FROM "order" 
WHERE created::text LIKE '2016-07%'; 

Die obige Abfrage funktioniert in Postgres in Ordnung.


Das scala Code, den ich für Order geschrieben ist: -

case class Order(id: Option[Int], 
       customerId: Int, 
       amount: Double, 
       created: Option[Instant], 
       updated: Option[Instant]) extends GenericEntity { 
     def this(customerId: Int, 
       amount: Double,) = this(None, customerId, amount, None, None) 
} 

class OrderTable(tag: Tag) extends GenericTable[Order](tag, "order") { 
     override def id = column[Option[Int]]("id", O.PrimaryKey, O.AutoInc)  
     def customerId = column[Int]("customer_id") 
     def amount = column[Dount]("amount") 

     def customer = foreignKey("fk_order_customer", customerId, Customers.table)(_.id.getOrElse(1), onUpdate = ForeignKeyAction.Restrict, onDelete = ForeignKeyAction.Cascade) 

     def * = (id, customerId, amount, created, updated) <> ((Order.apply _).tupled, Order.unapply) 
} 

object Orders extends GenericService[Order, OrderTable] { 
     override val table = TableQuery[OrderTable] 

     override def copyEntityFields(entity: Order, id: Option[Int], created: Option[Instant], updated: Option[Instant]): Order = { 
      entity.copy(id = id, created = created, updated = updated) 
     } 

     def getMonthlyOrder(year:Int, month: Int) = { 
      // execute LIKE query for the following query 
      // SELECT * FROM "order" 
      // WHERE created::text LIKE '2016-07%'; 
     }  
} 

Wo GenericEntity definiert id, created, updated.


Also, welchen Code sollte ich für getMonthlyOrder Funktion schreiben, mit year und month?.

+1

Haben Sie versucht, https://github.com/tminglei/ glatt-pg? – OlivierBlanvillain

Antwort

1

Sie müssen zwei Dinge:

1) A-Säule Typ Slick wissen lassen, wie Instant-zu-Datenbank bestehen bleiben. In diesem Fall möchten Sie Instant zu java.sql.Timestamp zuordnen, was Slick nativ verwenden kann.

implicit val instantColumnType: BaseColumnType[Instant] = 
    MappedColumnType.base[Instant, Timestamp](
     instant => Timestamp.from(instant), 
     ts => ts.toInstant 
    ) 

2) Funktionen zum Extrahieren von Jahr und Monat aus Ihrem Zeitstempel. Hier habe ich einen anderen Ansatz als Ihre LIKE-Abfrage verwendet. Sie könnten auch eine Zuordnung von Instant zu String definieren und etwas wie startsWith verwenden.

val yearFn = SimpleFunction.unary[Instant, Int]("year") 
val monthFn = SimpleFunction.unary[Instant, Int]("month") 

Dann würden Sie sie in getMonthlyOrder verwenden wie dieses

def getMonthlyOrder(year: Int, month: Int): Future[Seq[Order]] = { 
    val query = table.filter(_.created.map((created) => yearFn(created) === year && monthFn(created) === month)) 
    db.run(query.result) 
} 

Der vollständige Code gültig für Slick 3.1:

import java.sql.Timestamp 
import java.time.Instant 
import javax.inject.{Inject, Singleton} 

import play.api.db.slick.{DatabaseConfigProvider, HasDatabaseConfigProvider} 
import slick.driver.JdbcProfile 
import slick.lifted.TableQuery 

import scala.concurrent.Future 

case class Order(id: Int, 
       customerId: Int, 
       amount: Double, 
       created: Option[Instant], 
       updated: Option[Instant]) 
@Singleton 
class Orders @Inject()(val dbConfigProvider: DatabaseConfigProvider) extends HasDatabaseConfigProvider[JdbcProfile] { 
    val table = TableQuery[OrderTable] 

    import driver.api._ 

    implicit val instantColumnType: BaseColumnType[Instant] = 
     MappedColumnType.base[Instant, Timestamp](
      instant => Timestamp.from(instant), 
      ts => ts.toInstant 
     ) 

    val yearFn = SimpleFunction.unary[Instant, Int]("year") 
    val monthFn = SimpleFunction.unary[Instant, Int]("month") 

    def getMonthlyOrder(year: Int, month: Int): Future[Seq[Order]] = { 
     val query = table.filter(_.created.map((created) => yearFn(created) === year && monthFn(created) === month)) 
     db.run(query.result) 
    } 

    class OrderTable(tag: Tag) extends Table[Order](tag, "ORDERS") { 

     def * = (id, customerId, amount, created, updated) <> ((Order.apply _).tupled, Order.unapply) 

     def id = column[Int]("ID", O.PrimaryKey, O.AutoInc) 

     def customerId = column[Int]("CUSTOMER_ID") 

     def amount = column[Double]("AMOUNT") 

     def created = column[Option[Instant]]("CREATED") 

     def updated = column[Option[Instant]]("UPDATED") 
    } 

}