Giter Site home page Giter Site logo

jdub's Introduction

jdub

A damn simple JDBC wrapper. Y'know. For databases.

Requirements

  • Java SE 8 or above
  • Scala 2.12.x

How To Use

First, specify Jdub as a dependency:

<dependencies>
  <dependency>
    <groupId>com.simple</groupId>
    <artifactId>jdub_${scala.major.version}</artifactId>
    <version>${jdub.version}</version>
  </dependency>
</dependencies>

(Don't forget to include your JDBC driver!)

Second, connect to a database:

val db = Database.connect("jdbc:postgresql://localhost/wait_what", "myaccount", "mypassword")

Third, run some queries:

// Query returning an optional single result.
case class GetAge(name: String) extends FlatSingleRowQuery[Int] {

  val sql = trim("""
      SELECT age /* Use C-style comments in trimmed queries */
      FROM people
      WHERE name = ?
      """)

  val values = Seq(name)

  def flatMap(row: Row) = {
    // Returns Option[Int]
    row.int(0) // 0 gets the first column
  }

}

val age = db(GetAge("Old Guy")).getOrElse(-1) // 402
// Query returning a Person object for each row.
case object GetPeople extends CollectionQuery[Seq, Person] {

  val sql = trim("""
      SELECT name, email, age
      FROM people
      """)

  val values = Seq()

  def map(row: Row) = {
    val name = row.string("name").get
    val email = row.string("email").getOrElse("")
    val age = row.int("age").getOrElse(0)
    Person(name, email, age)
  }

}

val person = db(GetPeople).head // Person(Coda Hale,[email protected],29)

You can also use the sql string interpolator:

class PersonQueries(val database: Database) {
  // Query returning an optional single result.
  def getAge(name: String): Option[Int] = database {
    sql"""
      SELECT age
      FROM people
      WHERE name = ${name}
    """.map { row =>
      row.int("age")
    }
  }.headOption
}

val personQueries = new PersonQueries(database)
val age = personQueries.getAge("Old Guy").getOrElse(-1) // 402
object PersonQueries {
  def mapper(row: Row): String = {
    Person(
      name = row.string("name").get
      email = row.string("email").getOrElse("")
      age = row.int("age").getOrElse(0)
    )
  }
}

class PersonQueries(val database: Database) {
  // Query returning Person objects for each row.
  def getPeople(): Seq[Person] = database {
    sql"""
      SELECT name, email, age
      FROM people
    """.map(PersonQueries.mapper)
  }
}

val personQueries = new PersonQueries(database)
val people = personQueries.getPeople.head // Person(Coda Hale,[email protected],29)

Fourth, execute some statements:

case class UpdateEmail(name: String, newEmail: String) extends Statement {
  val sql = trim("""
      UPDATE people
      SET email = ?
      WHERE name = ?
      """)
  val values = Seq(newEmail, name)
}

// Execute the statement.
db.execute(UpdateEmail("Old Guy", "[email protected]"))

// Or return the number of rows updated.
val count = db.update(UpdateEmail("Old Guy", "[email protected]")) // 1

You can also use the sql string interpolator:

object PersonQueries {
  def mapper(row: Row): String = {
    Person(
      name = row.string("name").get
      email = row.string("email").getOrElse("")
      age = row.int("age").getOrElse(0)
    )
  }
}

class PersonQueries(val database: Database) {
  // Update a Person's email
  def updateEmail(name: String, newEmail: String): Option[Person] = database {
    sql"""
      UPDATE people
      SET email = ${newEmail}
      WHERE name = ${name}
      RETURNING people.*
    """.map(PersonQueries.mapper)
  }.headOption
}


val personQueries = new PersonQueries(database)
val updatedPerson = personQueries.updateEmail("Old Guy", "[email protected]")

Fifth, read up on all the details in the Jdub tour.

License

Copyright (c) 2011-2012 Coda Hale Copyright (c) 2012-2017 Simple Finance Technology Corp. All rights reserved.

Published under The MIT License, see LICENSE.md

jdub's People

Contributors

codahale avatar emilyst avatar ieure avatar jarreds avatar jklukas avatar parsnips avatar stevensurgnier avatar swenson avatar vanvlack avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jdub's Issues

Error in example: usage of trim() with a Statememt

The example from the README has:

case class UpdateUserEmail(userId: Long, oldEmail: String, newEmail: String) extends Statement {
  val sql = trim("""...""")

However, trim is not on Statement, only on RawQuery.

Database pool metrics

Would be nice if the database connection pool was wrapped and provided some metrics about the size, etc.

ReadOnlyDatabase

Would be nice if Database were split into Database and ReadOnlyDatabase so that we can create an instance of ReadOnlyDatabase and only be able to execute queries against it.

Column Metadata not exposed

Was there a particular reason the column metadata was not exposed like the ResultSet object does? Since the Row object does not expose any column metadata, the code becomes tightly-coupled with the database schema. I have a use-case where the code just needs to emit all the columns and values as a Seq[Map[String, Any]], but as I said, with the current support, I need to know all the column names and types.
I am working on implementing a couple of functions in the Row class (in my fork) that will expose the column list and the column types. If this sounds like something that is a good feature to have, I can raise a pull request.

Freshen metrics dep to BETA15?

We use jdub and metrics ... and with one of the changes that went into BETA15, stuff compiled against BETA14 no longer works with stuff compiled against BETA15.

Could you update 0.0.5-SNAPSHOT to BETA15?

Thanks!

JDUB fails silently on missing stored procedure

I've encountered a situation using jdub 0.0.6 where postgresql will generate an error (a missing stored procedure), but jdub fails to report the problem. We had to dig deep to find the cause of our database problems earlier, and having jdub throw an exception would have led us straight to it. This library is wonderful, hopefully this is something you can track down.

Thanks!

Additional metrics: Timer around getting connection from pool

Would be nice to track the time it takes to get a connection from the pool to let us know what a reasonable budget is for maxWaitForConnectionInMS might be.

Seems like it would just be some timers around each call to source.getConnection in Database.scala?

Value doesn't check for NULL column values

Value uses the ResultSet to access the column values but doesn't follow up with the call to ResultSet.wasNull. Not sure if the best way to model result cells is to wrap the Value in an Option or wrap the toX result in an Option.

Allow passing in a Properties object to Database.connect()

DriverManagerConnectionFactory has constructors:
(String connectUri,
String uname,
String passwd)

as well as

(String connectUri,
Properties props)

Database.connect() could accept a Properties object, allowing for the specification of SSL support, in addition to just the URI, username and password.

Array support?

I'm not sure what the best way to do this, but to work with arrays in Postgres, we need access to the connection object to call a method on it:

val sqlArray = connection.createArrayOf("uuid", products.toArray.asInstanceOf[Array[AnyRef]])

When products was an Iterable...

It'd be nice if this could be folded into prepare in Utils.scala somehow, but not sure how given the type name parameter...

Thoughts?

Transactions

Would be pretty useful to be able to execute stuff within a transaction.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.