Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

SF Scala meet up, lighting talk: SPA -- Scala JDBC wrapper

776 views

Published on

Talk on Nov. 14, 2013 SF Scala Meet up lighting talk.
Presented SPA --- Scala Persistence API (spa), a JDBC wrapper. A simple query API with out ORM or functional to relational mapping. It supports batch update, transaction and query return list or single objects

Published in: Technology
  • Be the first to comment

  • Be the first to like this

SF Scala meet up, lighting talk: SPA -- Scala JDBC wrapper

  1. 1. SPA A JDBC Wrapper Chester Chen 11/14/2013 ALPINE DATA LABS, A machine Learning Startup
  2. 2. What is SPA about ? A JDBC wrapper to make query database easier S F T P L • Simple and Resource safe • Flexible: handle results via toList, toSingle, Iterator as well as customized row extractor • Support Transaction and batch update • Plain SQL: SQL is enough • Failure SQL logging
  3. 3. What SPA is not? OR • Not a Object Relation mapping tool FR • Not a Function Relation mapping Tool Pool • Not Supporting Connection Pool
  4. 4. Rest of SPA talk •API examples •SPA implementations
  5. 5. SPA Select Query Show me the code def getConnection : Connection = ... val qm = QueryManager(open = getConnection ) val table = "dummy" //mySQL table val parsedSql = sql"select count(*) from information_schema.tables where table_name=$table" val count = qm.selectQuery(parsedSql).toSingle[Int]
  6. 6. SPA Select Query: Simple Data Type Show me the code val parsedSql = sql"select table_name from information_schema.tables” val r = qm.selectQuery(parsedSql).toList[String] val tuple4Value = qm.selectQuery(sql" select 1,2,3,4 from dual").toSingle[(Int,Int, Int,Int )] assert(tuple4Value.get === ( 1,2,3,4 ))
  7. 7. SPA Select Query: Class Structure Coffee again case class Coffee( @Column("COF_NAME") name: String, @Column("SUP_ID") supId: Int, @Column("PRICE") price: Double)
  8. 8. SPA Select Query: Class Structure Show me the code val qm = QueryManager(open = geConnection) val results1 = qm.selectQuery(sql" select * from COFFEES ").toList[Coffee] val q = qm.selectQuery(sql" select * from mytest.COFFEES ") val results2 = q.withIterator { it: Iterator[Option[Coffee]] => it.foldLeft(List[Coffee]())( (acc, a) => a.get :: acc).reverse }
  9. 9. SPA Update Query Show me the code valcreateTableSql= sql"createtable test( id MEDIUMINT NOT NULL AUTO_INCREMENT primary key, x Integer)” qm.updateQuery(createTableSql).executeUpdate //return the generated id. valid1 = qm.updateQuery(sql" INSERT INTO test(x) values (1) ").executeUpdate assert(id1 == 1) valid2 = qm.updateQuery(sql" INSERT INTO test(x) values (2) ").executeUpdate assert(id2 == 2)
  10. 10. SPA Update Query: transaction Show me the code Update the value to 2 in the table, assume it was 1, After update, throw exception within the same transaction. the exception should cause transaction rollback the database table should still have the value before transaction : i.e. 1 intercept[ExecuteQueryException] { qm.transaction() { implicit trans => qm.updateQuery(sql"updatemytest.testset x = 2").executeUpdate //simulate some code cause it to throw exception throw new ExecuteQueryException("see if I can rollback") } } //verify that the database table still have value 1 valvalue2 = qm.selectQuery(sql"selectx from mytest.test").toSingle[Long] assert(value2 === Some(1))
  11. 11. SPA Update Query: batch update Show me the code valq = qm.batchUpdateQuery(sql"insertinto mytest.test(x, y) values(?, ?) ") //index is zero-based val size = 10 for (i<-0 until size ) { val pa = Map(0 -> i, 1 -> i*20) // x is 0, y is 1 q.addBatch(pa) //use JDBC add batch } q.executeBatchUpdate
  12. 12. SPA: Logging Show me the code Automatically logs the SQL statement as well corresponding parameters to stdout, One can use sqllogging to debug on individual SQL For example, val q = qm.updateQuery(....) .logSql(true) .executeUpdate
  13. 13. SPA Implementation val a = “c” val s= sql”select * from table where colume1 = $a” • How is this implemented ? • How does SPA ensure resource safe ?
  14. 14. SPA: Parse SQL with String Interpolation Show me the code case class ParsedSql(sql: String, parameterPositions: Map[Int, SQLParameter]) implicit class SqlContext(sc: StringContext) { def sql( args:Any*): ParsedSql = { val parameters = (args.indiceszip args).foldLeft(Map[Int, SQLParameter]())( (acc, a) => acc + (a._1 -> toSqlParameter(a._2))) val placeHolders= args.map( a=> "?") val sql = sc.s(placeHolders:_*) ParsedSql(sql, parameters) } }
  15. 15. SPA: Transaction The original transaction construct is borrowed from Querulous. def transaction[T](transaction : Option[Transaction] = None) (f: Option[Transaction] => T):T = { withTransaction(transaction) { tran => try { tran.begin() val value = f(Some(tran)) tran.commit() value } catch { case e: Throwable=> tran.rollback() throw e } } }
  16. 16. SPA: Select Query Show me the code class SelectQuery(queryManager : QueryManager, /* skip other args*/ (transaction: Option[Transaction] = None) extends CoreQuery[SelectQuery](parsedSql, /* skip others */) { deftoList[A : ClassTag : TypeTag]: List[A] = { definnerToList(trans: Transaction)= withQuery(trans, forwardOnly= true) { rs=> valprocessor = new SeqResultSetProcessor() valextractor = rowProcessor.getOrElse( new ClassRowProcessor[A]) .asInstanceOf[RowExtractor[A]] processor.processResultSet[A](rs, extractor).toList } transactionmatch { case None => queryManager.transaction() { trans => innerToList(trans.get)} case Some(trans) => innerToList(trans) } }
  17. 17. Questions https://github.com/chesterxgchen/spa Alpine Data Labs is hiring Scala developers

×