SlideShare a Scribd company logo
Working with Databases and Groovy
Dr Paul King
Groovy Lead for Object Computing Inc.
@paulk_asert
http://slideshare.net/paulk_asert/groovy-databases
https://github.com/paulk-asert/groovy-databases
Contents
• groovy.sql.Sql
• Connecting to a database
• Writing to a database
• Reading from a database
• Stored Procedures
• Advanced Reading/Writing
• groovy.sql.DataSet
• MongoDB
• Neo4j
2
groovy.sql.Sql
• Groovy-friendly higher-level API sitting over JDBC
3
Connecting to a database…
• Sql.newInstance
• assumes driver is on the classpath
• other newInstance variants available
4
import groovy.sql.Sql
def url = 'jdbc:hsqldb:mem:marathon'
def user = 'sa'
def password = ''
def driver = 'org.hsqldb.jdbcDriver'
def sql = Sql.newInstance(url, user, password, driver)
// use 'sql' instance
sql.close()
…Connecting to a database…
• Some variations
5
Advanced
def sql = Sql.newInstance(
url: 'jdbc:hsqldb:mem:marathon',
user: 'sa',
password: '',
driver: 'org.hsqldb.jdbcDriver',
cacheStatements: true,
resultSetConcurrency: CONCUR_READ_ONLY
)
Sql.withInstance(url, user, password, driver) {
// use 'sql' instance
}
// no close() required
@Grab('org.hsqldb:hsqldb:2.3.3')
@GrabConfig(systemClassLoader=true)
import groovy.sql.Sql
// ...
…Connecting to a database…
• new Sql() constructor
• if you have a DataSource or existing Connection or Sql instance
• Likely to be the preferred approach with JDK9 Jigsaw
6
import groovy.sql.Sql
import org.hsqldb.jdbc.JDBCDataSource
def dataSource = new JDBCDataSource(
database: 'jdbc:hsqldb:mem:marathon',
user: 'sa', password: '')
def sql = new Sql(dataSource)
// use 'sql' instance
sql.close()
…Connecting to a database
• new Sql() constructor (cont'd)
7
@Grab('org.hsqldb:hsqldb:2.3.3')
@Grab('commons-dbcp:commons-dbcp:1.4')
import groovy.sql.Sql
import org.apache.commons.dbcp.BasicDataSource
def url = 'jdbc:hsqldb:mem:marathon'
def driver = 'org.hsqldb.jdbcDriver'
def dataSource = new BasicDataSource(
driverClassName: driver, url: url,
username: 'sa', password: '')
def sql = new Sql(dataSource)
// use 'sql' instance
sql.close()
Advanced
Writing to a database…
8
def DDL = '''
DROP TABLE Athlete IF EXISTS;
CREATE TABLE Athlete (
athleteId INTEGER GENERATED BY DEFAULT AS IDENTITY,
firstname VARCHAR(64),
lastname VARCHAR(64),
dateOfBirth DATE,
);
'''
sql.execute(DDL)
sql.execute '''
INSERT INTO Athlete (firstname, lastname, dateOfBirth)
VALUES ('Paul', 'Tergat', '1969-06-17')
'''
…Writing to a database
9
def data = [first: 'Khalid', last: 'Khannouchi', birth: '1971-12-22']
sql.execute """
INSERT INTO Athlete (firstname, lastname, dateOfBirth)
VALUES (${data.first},${data.last},${data.birth})
"""
String athleteInsert = 'INSERT INTO Athlete (firstname, lastname) VALUES (?,?)'
def keys = sql.executeInsert athleteInsert, ['Ronaldo', 'da Costa']
assert keys[0] == [2]
def rowsUpdated = sql.executeUpdate '''
UPDATE Athlete SET dateOfBirth='1970-06-07' where lastname='da Costa'
'''
assert rowsUpdated == 1
sql.execute "delete from Athlete where lastname = 'Tergat'"
Advanced
Reading from a database…
10
sql.query('SELECT firstname, lastname FROM Athlete') { resultSet ->
while (resultSet.next()) {
print resultSet.getString(1)
print ' '
println resultSet.getString('lastname')
}
}
sql.eachRow('SELECT firstname, lastname FROM Athlete') { row ->
println row[0] + ' ' + row.lastname
}
…Reading from a database
11
def first = sql.firstRow('SELECT lastname, dateOfBirth FROM Athlete')
def firstString = first.toMapString().toLowerCase()
assert firstString == '[lastname:tergat, dateofbirth:1969-06-17]'
List athletes = sql.rows('SELECT firstname, lastname FROM Athlete')
println "There are ${athletes.size()} Athletes:"
println athletes.collect { "$it.FIRSTNAME ${it[-1]}" }.join(", ")
assert sql.firstRow('SELECT COUNT(*) as num FROM Athlete').num == 3
Invoking Stored Procedures…
12
def FULL_DLL = '''
DROP TABLE Athlete IF EXISTS;
CREATE TABLE Athlete (
athleteId INTEGER GENERATED BY DEFAULT AS IDENTITY,
firstname VARCHAR(64),
lastname VARCHAR(64),
dateOfBirth DATE
);
DROP INDEX idx IF EXISTS;
CREATE INDEX idx ON Athlete (athleteId);
DROP TABLE Run IF EXISTS;
CREATE TABLE Run (
runId INTEGER GENERATED BY DEFAULT AS IDENTITY,
distance INTEGER, -- in meters
time INTEGER, -- in seconds
venue VARCHAR(64),
when TIMESTAMP,
fkAthlete INTEGER,
CONSTRAINT fk FOREIGN KEY (fkAthlete)
REFERENCES Athlete (athleteId) ON DELETE CASCADE
);
'''
sql.execute FULL_DLL
Advanced
Athlete
athleteId
firstname
lastname
dateOfBirth
Run
runId
distance
time
venue
when
fkAthlete
…Invoking Stored Procedures…
• And assume some data has been populated …
• We've refactored our previous insert code into some helper methods.
13
insertAthlete('Paul', 'Tergat', '1969-06-17')
insertAthlete('Khalid', 'Khannouchi', '1971-12-22')
insertAthlete('Ronaldo', 'da Costa', '1970-06-07')
insertRun(2, 4, 55, 'Berlin', '2003-09-28', 'Tergat')
insertRun(2, 5, 38, 'London', '2002-04-14', 'Khannouchi')
insertRun(2, 5, 42, 'Chicago', '1999-10-24', 'Khannouchi')
insertRun(2, 6, 05, 'Berlin', '1998-09-20', 'da Costa')
…Invoking Stored Procedures…
14
db.execute '''
CREATE FUNCTION SELECT_ATHLETE_RUN ()
RETURNS TABLE (lastname VARCHAR(64), venue VARCHAR(64), whenRun DATE)
READS SQL DATA
RETURN TABLE (
select Athlete.lastname, Run.venue, Run.whenRun
from Athlete, Run
where Athlete.athleteId = Run.fkAthlete
order by whenRun
)
'''
db.eachRow('CALL SELECT_ATHLETE_RUN()') {
println "$it.lastname $it.venue $it.whenRun"
} da Costa Berlin 1998-09-20
Khannouchi Chicago 1999-10-24
Khannouchi London 2002-04-14
Tergat Berlin 2003-09-28
…Invoking Stored Procedures…
15
db.execute '''
CREATE FUNCTION FULL_NAME (p_lastname VARCHAR(64))
RETURNS VARCHAR(100)
READS SQL DATA
BEGIN ATOMIC
declare ans VARCHAR(100);
SELECT CONCAT(firstname, ' ', lastname) INTO ans
FROM Athlete WHERE lastname = p_lastname;
return ans;
END
'''
assert db.firstRow("{? = call FULL_NAME(?)}", ['Tergat'])[0] == 'Paul Tergat'
…Invoking Stored Procedures
16
db.execute '''
CREATE PROCEDURE CONCAT_NAME (OUT fullname VARCHAR(100),
IN first VARCHAR(50), IN last VARCHAR(50))
BEGIN ATOMIC
SET fullname = CONCAT(first, ' ', last);
END
'''
db.call("{call CONCAT_NAME(?, ?, ?)}", [Sql.VARCHAR, 'Paul', 'Tergat']) {
fullname -> assert fullname == 'Paul Tergat'
}
Advanced Reading…
• Rowset metadata
17
def dump(sql, tablename) {
println " CONTENT OF TABLE ${tablename} ".center(40, '-')
sql.eachRow('SELECT * FROM ' + tablename) { rs ->
def meta = rs.getMetaData()
if (meta.columnCount <= 0) return
for (i in 0..<meta.columnCount) {
print "${i}: ${meta.getColumnLabel(i + 1)}".padRight(20) // counts from 1
print rs[i]?.toString() // counts from 0
print "n"
}
println '-' * 40
}
}
…Advanced Reading…
18
def dump(sql, tablename) {
println " CONTENT OF TABLE ${tablename} ".center(40, '-')
sql.eachRow('SELECT * FROM ' + tablename) { rs ->
def meta = rs.getMetaData()
if (meta.columnCount <= 0) return
for (i in 0..<meta.columnCount) {
print "${i}: ${meta.getColumnLabel(i + 1)}".padRight(20) // counts from 1
print rs[i]?.toString() // counts from 0
print "n"
}
println '-' * 40
}
} ----------------------- CONTENT OF TABLE Athlete -----------------------
ATHLETEID FIRSTNAME LASTNAME DATEOFBIRTH
------------------------------------------------------------------------
1 Paul Tergat 1969-06-17
2 Khalid Khannouchi 1971-12-22
3 Ronaldo da Costa 1970-06-07
…Advanced Reading…
19
def dump2(sql, tablename) {
def printColNames = { meta ->
def width = meta.columnCount * 18
println " CONTENT OF TABLE ${tablename} ".center(width, '-')
(1..meta.columnCount).each {
print meta.getColumnLabel(it).padRight(18)
}
println()
println '-' * width
}
def printRow = { row ->
row.toRowResult().values().each {
print it.toString().padRight(18) }
println()
}
sql.eachRow('SELECT * FROM ' + tablename, printColNames, printRow)
}
metadata
closure
…Advanced Reading
• Pagination
20
qry = 'SELECT * FROM Athlete'
assert sql.rows(qry, 1, 4)*.lastname ==
['Tergat', 'Khannouchi', 'da Costa', 'Gebrselassie']
assert sql.rows(qry, 5, 4)*.lastname ==
['Makau', 'Radcliffe', 'Ndereba', 'Takahashi']
assert sql.rows(qry, 9, 4)*.lastname ==
['Loroupe', 'Kristiansen']
Advanced Writing…
• Simple transaction support
21
sql.withTransaction {
insertAthlete('Haile', 'Gebrselassie', '1973-04-18')
insertAthlete('Patrick', 'Makau', '1985-03-02')
}
Advanced
…Advanced Writing…
• Batching of ad-hoc SQL statements
22
sql.execute "delete from Athlete where lastname = 'Tergat'"
sql.withBatch { stmt ->
stmt.addBatch '''
INSERT INTO Athlete (firstname, lastname, dateOfBirth)
VALUES ('Paul', 'Tergat', '1969-06-17')'''
stmt.addBatch """
INSERT INTO Run (distance, time, venue, when, fkAthlete)
SELECT 42195, ${2*60*60+4*60+55}, 'Berlin', '2003-09-28',
athleteId FROM Athlete WHERE lastname='Tergat'"""
}
//22/04/2013 6:34:59 AM groovy.sql.BatchingStatementWrapper processResult
//FINE: Successfully executed batch with 2 command(s)
…Advanced Writing…
• Batching with a prepared statement
23
def qry = 'INSERT INTO Athlete (firstname, lastname, dateOfBirth) VALUES (?,?,?);'
sql.withBatch(3, qry) { ps ->
ps.addBatch('Paula', 'Radcliffe', '1973-12-17')
ps.addBatch('Catherine', 'Ndereba', '1972-07-21')
ps.addBatch('Naoko', 'Takahashi', '1972-05-06')
ps.addBatch('Tegla', 'Loroupe', '1973-05-09')
ps.addBatch('Ingrid', 'Kristiansen', '1956-03-21')
}
// If logging is turned on:
// 20/04/2013 2:18:10 AM groovy.sql.BatchingStatementWrapper processResult
// FINE: Successfully executed batch with 3 command(s)
// 20/04/2013 2:18:10 AM groovy.sql.BatchingStatementWrapper processResult
// FINE: Successfully executed batch with 2 command(s)
…Advanced Writing
• Named parameters (two variants) and named-ordinal parameters
24
@Canonical class Athlete { String first, last, dob }
def ndereba = new Athlete('Catherine', 'Ndereba', '1972-07-21')
def takahashi = new Athlete('Naoko', 'Takahashi')
def takahashiExtra = [dob: '1972-05-06']
def loroupe = [first: 'Tegla', last: 'Loroupe', dob: '1973-05-09']
def insertPrefix = 'INSERT INTO Athlete (firstname, lastname, dateOfBirth) VALUES '
sql.execute insertPrefix + ' (?.first,?.last,?.dob)', ndereba
sql.execute insertPrefix + ' (?1.first,?1.last,?2.dob)', takahashi, takahashiExtra
sql.execute insertPrefix + ' (:first,:last,:dob)', loroupe
sql.execute insertPrefix + ' (:first,:last,:dob)', first: 'Ingrid',
last: 'Kristiansen', dob: '1956-03-21'
Topics
• groovy.sql.Sql
• Connecting to a database
• Writing to a database
• Reading from a database
• Stored Procedures
• Advanced Reading/Writing
 groovy.sql.DataSet
• MongoDB
• Neo4j
groovy.sql.DataSet
• Allows any table within an RDBMS to appear as if it
was a Java-like collection of POGOs
• Can be thought of as a poor man's object-relational
mapping system
• Has some smarts for lazy execution of database
queries
• Not meant to be as sophisticated as hibernate
26
DataSet example…
27
def athletes = sql.dataSet('Athlete')
athletes.each { println it.firstname }
athletes.add(
firstname: 'Paula',
lastname: 'Radcliffe',
dateOfBirth: '1973-12-17'
)
athletes.each { println it.firstname }
def runs = sql.dataSet('AthleteRun').findAll { it.firstname == 'Khalid' }
runs.each { println "$it.lastname $it.venue" }
Paul
Khalid
Ronaldo
Paul
Khalid
Ronaldo
Paula
Khannouchi London
Khannouchi Chicago
…DataSet example
28
def query = athletes.findAll { it.firstname >= 'P' }
query = query.findAll { it.dateOfBirth > '1970-01-01' }
query = query.sort { it.dateOfBirth }
query = query.reverse()
println query.sql
println query.parameters
println query.rows()*.firstname // One SQL query here!
select * from Athlete where firstname >= ? and dateOfBirth > ? order by dateOfBirth DESC
[P, 1970-01-01]
[Paula, Ronaldo]
Overcoming groovy.sql.DataSet limitations
29
def DLL_WITH_VIEW = '''
DROP TABLE Athlete IF EXISTS;
CREATE TABLE Athlete (
athleteId INTEGER GENERATED BY DEFAULT AS IDENTITY,
firstname VARCHAR(64),
lastname VARCHAR(64),
dateOfBirth DATE
);
DROP INDEX idx IF EXISTS;
CREATE INDEX idx ON Athlete (athleteId);
DROP TABLE Run IF EXISTS;
CREATE TABLE Run (
runId INTEGER GENERATED BY DEFAULT AS IDENTITY,
distance INTEGER, -- in meters
time INTEGER, -- in seconds
venue VARCHAR(64),
when TIMESTAMP,
fkAthlete INTEGER,
CONSTRAINT fk FOREIGN KEY (fkAthlete)
REFERENCES Athlete (athleteId) ON DELETE CASCADE
);
DROP VIEW AthleteRun IF EXISTS;
CREATE VIEW AthleteRun AS
SELECT * FROM Athlete LEFT OUTER JOIN Run
ON fkAthlete=athleteId;
'''
db.execute DLL_WITH_VIEW
Topics
• groovy.sql.Sql
• Connecting to a database
• Writing to a database
• Reading from a database
• Stored Procedures
• Advanced Reading/Writing
• groovy.sql.DataSet
 MongoDB
• Neo4j
MongoDB…
31
@Grab('com.gmongo:gmongo:1.3')
import com.gmongo.GMongo
import com.mongodb.util.JSON
import groovy.transform.Field
@Field db = new GMongo().getDB('athletes')
db.athletes.drop()
db.athletes << [first: 'Paul', last: 'Tergat', dob: '1969-06-17', runs: [
[distance: 42195, time: 2 * 60 * 60 + 4 * 60 + 55,
venue: 'Berlin', when: '2003-09-28']
]]
def insertAthlete(first, last, dob) {
db.athletes << [first: first, last: last, dob: dob]
}
…MongoDB…
32
def insertRun(h, m, s, venue, date, lastname) {
db.athletes.update(
[last: lastname],
[$addToSet: [runs: [distance: 42195,
time: h * 60 * 60 + m * 60 + s,
venue: venue, when: date]]]
)
}
insertAthlete('Khalid', 'Khannouchi', '1971-12-22')
insertAthlete('Ronaldo', 'da Costa', '1970-06-07')
insertRun(2, 5, 38, 'London', '2002-04-14', 'Khannouchi')
insertRun(2, 5, 42, 'Chicago', '1999-10-24', 'Khannouchi')
insertRun(2, 6, 05, 'Berlin', '1998-09-20', 'da Costa')
…MongoDB…
33
def radcliffe = """{
first: 'Paula',
last: 'Radcliffe',
dob: '1973-12-17',
runs: [
{distance: 42195, time: ${2 * 60 * 60 + 15 * 60 + 25},
venue: 'London', when: '2003-04-13'}
]
}"""
db.athletes << JSON.parse(radcliffe)
assert db.athletes.count == 4
db.athletes.find().each {
println "$it._id $it.last ${it.runs.size()}"
}
516b15fc2b10a15fa09331f2 Tergat 1
516b15fc2b10a15fa09331f3 Khannouchi 2
516b15fc2b10a15fa09331f4 da Costa 1
516b15fc2b10a15fa09331f5 Radcliffe 1
…MongoDB
34
def londonAthletes = db.athletes.find('runs.venue': 'London')*.first
assert londonAthletes == ['Khalid', 'Paula']
def youngAthletes = db.athletes.aggregate(
[$project: [first: 1, dob: 1]],
[$match: [dob: [$gte: '1970-01-01']]],
[$sort: [dob: -1]]
)
assert youngAthletes.results()*.first == ['Paula', 'Khalid', 'Ronaldo']
Topics
• groovy.sql.Sql
• Connecting to a database
• Writing to a database
• Reading from a database
• Stored Procedures
• Advanced Reading/Writing
• groovy.sql.DataSet
• MongoDB
 Neo4j
Neo4j…
36
…Neo4j…
37
@Grab('org.neo4j:neo4j-kernel:2.1.4')
@Grab('com.tinkerpop.gremlin:gremlin-groovy:2.5.0')
//@Grab('com.tinkerpop.blueprints:blueprints-neo4j-graph:2.5.0')
@Grab('com.tinkerpop.blueprints:blueprints-neo4j-graph:2.5.0;transitive=false')
@Grab('com.tinkerpop.blueprints:blueprints-core:2.5.0')
//@Grab('codehaus-stax:stax:1.1.1')
//@GrabResolver('https://repository.jboss.org/nexus/content/repositories/thirdparty-releases')
@GrabExclude('org.codehaus.groovy:groovy')
import com.tinkerpop.blueprints.Graph
import com.tinkerpop.blueprints.impls.neo4j.Neo4jGraph
//import com.tinkerpop.blueprints.util.io.graphml.GraphMLWriter
import com.tinkerpop.gremlin.groovy.Gremlin
import groovy.transform.Field
import org.neo4j.graphdb.traversal.Evaluators
import org.neo4j.kernel.EmbeddedGraphDatabase
import org.neo4j.graphdb.*
import org.neo4j.kernel.Traversal
import org.neo4j.kernel.Uniqueness
@Field graphDb = new EmbeddedGraphDatabase("athletes")
enum MyRelationshipTypes implements RelationshipType { ran, supercedes }
…Neo4j…
38
// some optional metaclass syntactic sugar
EmbeddedGraphDatabase.metaClass {
createNode { Map properties ->
def n = delegate.createNode()
properties.each { k, v -> n[k] = v }
n
}
}
Node.metaClass {
propertyMissing { String name, val -> delegate.setProperty(name, val) }
propertyMissing { String name -> delegate.getProperty(name) }
methodMissing { String name, args ->
delegate.createRelationshipTo(args[0], MyRelationshipTypes."$name")
}
}
Relationship.metaClass {
propertyMissing { String name, val -> delegate.setProperty(name, val) }
propertyMissing { String name -> delegate.getProperty(name) }
}
…Neo4j…
39
def insertAthlete(first, last, dob) {
graphDb.createNode(first: first, last: last, dob: dob)
}
def insertRecord(h, m, s, venue, when, athlete) {
def record = graphDb.createNode(distance: 42195,
time: h * 60 * 60 + m * 60 + s, venue: venue, when: when)
athlete.won(record)
record
}
Gremlin.load()
def tx = graphDb.beginTx()
def athlete1, athlete2, athlete3, athlete4
def marathon1, marathon2a, marathon2b, marathon3, marathon4a, marathon4b
…Neo4j…
40
try {
athlete1 = graphDb.createNode()
athlete1.first = 'Paul'
athlete1.last = 'Tergat'
athlete1.dob = '1969-06-17'
marathon1 = graphDb.createNode()
marathon1.distance = 42195
marathon1.time = 2 * 60 * 60 + 4 * 60 + 55
marathon1.venue = 'Berlin'
marathon1.when = '2003-09-28'
athlete1.won(marathon1)
athlete2 = insertAthlete('Khalid', 'Khannouchi', '1971-12-22')
marathon2a = insertRecord(2, 5, 38, 'London', '2002-04-14', athlete2)
marathon2b = insertRecord(2, 5, 42, 'Chicago', '1999-10-24', athlete2)
athlete3 = insertAthlete('Ronaldo', 'da Costa', '1970-06-07')
marathon3 = insertRecord(2, 6, 5, 'Berlin', '1998-09-20', athlete3)
athlete4 = insertAthlete('Paula', 'Radcliffe', '1973-12-17')
marathon4a = insertRecord(2, 17, 18, 'Chicago', '2002-10-13', athlete4)
marathon4b = insertRecord(2, 15, 25, 'London', '2003-04-13', athlete4)
…Neo4j…
41
def venue = marathon1.venue
def when = marathon1.when
println "$athlete1.first $athlete1.last won the $venue marathon on $when"
def allAthletes = [athlete1, athlete2, athlete3, athlete4]
def wonInLondon = allAthletes.findAll { athlete ->
athlete.getRelationships(MyRelationshipTypes.won).any { record ->
record.getOtherNode(athlete).venue == 'London'
}
}
assert wonInLondon*.last == ['Khannouchi', 'Radcliffe']
marathon2b.supercedes(marathon3)
marathon2a.supercedes(marathon2b)
marathon1.supercedes(marathon2a)
marathon4b.supercedes(marathon4a)
…Neo4j…
42
println "World records following $marathon3.venue $marathon3.when:"
def t = new Traversal()
for (Path p in t.description().breadthFirst().
relationships(MyRelationshipTypes.supercedes).
evaluator(Evaluators.fromDepth(1)).
uniqueness(Uniqueness.NONE).
traverse(marathon3)) {
def newRecord = p.endNode()
println "$newRecord.venue $newRecord.when"
}
Graph g = new Neo4jGraph(graphDb)
def pretty = { it.collect { "$it.venue $it.when" }.join(', ') }
def results = []
g.V('venue', 'London').fill(results)
println 'London world records: ' + pretty(results)
results = []
g.V('venue', 'London').in('supercedes').fill(results)
println 'World records after London: ' + pretty(results)
…Neo4j
43
results = []
def emitAll = { true }
def forever = { true }
def berlin98 = { it.venue == 'Berlin' && it.when.startsWith('1998') }
g.V.filter(berlin98).in('supercedes').loop(1, forever, emitAll).fill(results)
println 'World records after Berlin 1998: ' + pretty(results)
// def writer = new GraphMLWriter(g)
// def out = new FileOutputStream("c:/temp/athletes.graphml")
// writer.outputGraph(out)
// writer.setNormalize(true)
// out.close()
tx.success()
} finally {
tx.finish()
graphDb.shutdown()
}
More Information: Groovy in Action, 2ed
44

More Related Content

What's hot (20)

PPTX
Five
Łukasz Langa
 
PDF
Fun Teaching MongoDB New Tricks
MongoDB
 
PDF
BDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
Christian Baranowski
 
ODP
Scala introduction
Alf Kristian Støyle
 
PDF
Python dictionary : past, present, future
delimitry
 
PDF
What I learned from Seven Languages in Seven Weeks (IPRUG)
Kerry Buckley
 
PPTX
Poly-paradigm Java
Pavel Tcholakov
 
PPTX
JPoint 2016 - Валеев Тагир - Странности Stream API
tvaleev
 
DOCX
WOTC_Import
Luther Quinn
 
PDF
Functional es6
Natalia Zaslavskaya
 
PPTX
Python 표준 라이브러리
용 최
 
PDF
Обзор фреймворка Twisted
Maxim Kulsha
 
KEY
Why Learn Python?
Christine Cheung
 
PPTX
Programming Java - Lection 07 - Puzzlers - Lavrentyev Fedor
Fedor Lavrentyev
 
PDF
Optimizing Slow Queries with Indexes and Creativity
MongoDB
 
PPTX
엘라스틱서치 적합성 이해하기 20160630
Yong Joon Moon
 
PDF
JJUG CCC 2011 Spring
Kiyotaka Oku
 
PDF
Building DSLs with Groovy
Sten Anderson
 
PDF
Understanding Source Code Differences by Separating Refactoring Effects
Institute of Science Tokyo
 
ODP
Jersey Guice AOP
Domenico Briganti
 
Fun Teaching MongoDB New Tricks
MongoDB
 
BDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
Christian Baranowski
 
Scala introduction
Alf Kristian Støyle
 
Python dictionary : past, present, future
delimitry
 
What I learned from Seven Languages in Seven Weeks (IPRUG)
Kerry Buckley
 
Poly-paradigm Java
Pavel Tcholakov
 
JPoint 2016 - Валеев Тагир - Странности Stream API
tvaleev
 
WOTC_Import
Luther Quinn
 
Functional es6
Natalia Zaslavskaya
 
Python 표준 라이브러리
용 최
 
Обзор фреймворка Twisted
Maxim Kulsha
 
Why Learn Python?
Christine Cheung
 
Programming Java - Lection 07 - Puzzlers - Lavrentyev Fedor
Fedor Lavrentyev
 
Optimizing Slow Queries with Indexes and Creativity
MongoDB
 
엘라스틱서치 적합성 이해하기 20160630
Yong Joon Moon
 
JJUG CCC 2011 Spring
Kiyotaka Oku
 
Building DSLs with Groovy
Sten Anderson
 
Understanding Source Code Differences by Separating Refactoring Effects
Institute of Science Tokyo
 
Jersey Guice AOP
Domenico Briganti
 

Viewers also liked (8)

PDF
awesome groovy
Paul King
 
PPTX
groovy transforms
Paul King
 
PDF
Make Your Testing Groovy
Paul King
 
PPTX
concurrency gpars
Paul King
 
PDF
Vert.X like Node.js but polyglot and reactive on JVM
Massimiliano Dessì
 
PDF
Oredev 2015 - Taming Java Agents
Anton Arhipov
 
PDF
Patterns of Cloud Native Architecture
Andrew Shafer
 
PDF
groovy rules
Paul King
 
awesome groovy
Paul King
 
groovy transforms
Paul King
 
Make Your Testing Groovy
Paul King
 
concurrency gpars
Paul King
 
Vert.X like Node.js but polyglot and reactive on JVM
Massimiliano Dessì
 
Oredev 2015 - Taming Java Agents
Anton Arhipov
 
Patterns of Cloud Native Architecture
Andrew Shafer
 
groovy rules
Paul King
 
Ad

Similar to groovy databases (20)

PDF
Java 1-contd
Mukesh Tekwani
 
PDF
Java JDBC
Jussi Pohjolainen
 
PPT
3 database-jdbc(1)
hameedkhan2017
 
PDF
java4th.pdf bilgisayar mühendisliği bölümü
Smeyyeztrk10
 
PPTX
Chapter Seven- JDBC.pptx
BlenKassahun1
 
DOCX
Db examples
ABDUmomo
 
ODP
Slickdemo
Knoldus Inc.
 
PPTX
JDBC
Balwinder Kumar
 
PPT
30 5 Database Jdbc
phanleson
 
PDF
This is the official tutorial from Oracle.httpdocs.oracle.comj.pdf
jillisacebi75827
 
PDF
Jdbc[1]
Fulvio Corno
 
PDF
JDBC programming
Fulvio Corno
 
PDF
ScalikeJDBC Tutorial for Beginners
Kazuhiro Sera
 
PPTX
OOP Lecture 18-DB Connectivity-Part2.pptx
Tanzila Kehkashan
 
PPTX
My sql with java
oly07104
 
PDF
spring-tutorial
Arjun Shanka
 
PDF
Introduction to JDBC and database access in web applications
Fulvio Corno
 
Java 1-contd
Mukesh Tekwani
 
3 database-jdbc(1)
hameedkhan2017
 
java4th.pdf bilgisayar mühendisliği bölümü
Smeyyeztrk10
 
Chapter Seven- JDBC.pptx
BlenKassahun1
 
Db examples
ABDUmomo
 
Slickdemo
Knoldus Inc.
 
30 5 Database Jdbc
phanleson
 
This is the official tutorial from Oracle.httpdocs.oracle.comj.pdf
jillisacebi75827
 
Jdbc[1]
Fulvio Corno
 
JDBC programming
Fulvio Corno
 
ScalikeJDBC Tutorial for Beginners
Kazuhiro Sera
 
OOP Lecture 18-DB Connectivity-Part2.pptx
Tanzila Kehkashan
 
My sql with java
oly07104
 
spring-tutorial
Arjun Shanka
 
Introduction to JDBC and database access in web applications
Fulvio Corno
 
Ad

More from Paul King (16)

PDF
tictactoe groovy
Paul King
 
PDF
functional groovy
Paul King
 
PDF
Make Testing Groovy
Paul King
 
PDF
Agile Testing Practices
Paul King
 
PDF
groovy DSLs from beginner to expert
Paul King
 
PDF
groovy and concurrency
Paul King
 
PDF
GroovyDSLs
Paul King
 
PDF
Atlassian Groovy Plugins
Paul King
 
PDF
Dynamic Language Practices
Paul King
 
PDF
Make Your Builds More Groovy
Paul King
 
PDF
Groovy Power Features
Paul King
 
PDF
Groovy Testing Sep2009
Paul King
 
PDF
Craig Smith & Paul King Agile Tool Hacking Taking Your Agile Development ...
Paul King
 
PDF
Groovy Tutorial
Paul King
 
PDF
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Paul King
 
PDF
XML and Web Services with Groovy
Paul King
 
tictactoe groovy
Paul King
 
functional groovy
Paul King
 
Make Testing Groovy
Paul King
 
Agile Testing Practices
Paul King
 
groovy DSLs from beginner to expert
Paul King
 
groovy and concurrency
Paul King
 
GroovyDSLs
Paul King
 
Atlassian Groovy Plugins
Paul King
 
Dynamic Language Practices
Paul King
 
Make Your Builds More Groovy
Paul King
 
Groovy Power Features
Paul King
 
Groovy Testing Sep2009
Paul King
 
Craig Smith & Paul King Agile Tool Hacking Taking Your Agile Development ...
Paul King
 
Groovy Tutorial
Paul King
 
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Paul King
 
XML and Web Services with Groovy
Paul King
 

Recently uploaded (20)

PPTX
AEM User Group: India Chapter Kickoff Meeting
jennaf3
 
PPTX
Transforming Mining & Engineering Operations with Odoo ERP | Streamline Proje...
SatishKumar2651
 
PPTX
Why Businesses Are Switching to Open Source Alternatives to Crystal Reports.pptx
Varsha Nayak
 
PDF
유니티에서 Burst Compiler+ThreadedJobs+SIMD 적용사례
Seongdae Kim
 
PPTX
Hardware(Central Processing Unit ) CU and ALU
RizwanaKalsoom2
 
PDF
SAP Firmaya İade ABAB Kodları - ABAB ile yazılmıl hazır kod örneği
Salih Küçük
 
PDF
MiniTool Partition Wizard Free Crack + Full Free Download 2025
bashirkhan333g
 
PDF
vMix Pro 28.0.0.42 Download vMix Registration key Bundle
kulindacore
 
PPTX
Help for Correlations in IBM SPSS Statistics.pptx
Version 1 Analytics
 
PPTX
Foundations of Marketo Engage - Powering Campaigns with Marketo Personalization
bbedford2
 
PPTX
Empowering Asian Contributions: The Rise of Regional User Groups in Open Sour...
Shane Coughlan
 
PPTX
Agentic Automation Journey Series Day 2 – Prompt Engineering for UiPath Agents
klpathrudu
 
PPTX
Agentic Automation Journey Session 1/5: Context Grounding and Autopilot for E...
klpathrudu
 
PDF
Top Agile Project Management Tools for Teams in 2025
Orangescrum
 
PDF
[Solution] Why Choose the VeryPDF DRM Protector Custom-Built Solution for You...
Lingwen1998
 
PDF
The 5 Reasons for IT Maintenance - Arna Softech
Arna Softech
 
PDF
Odoo CRM vs Zoho CRM: Honest Comparison 2025
Odiware Technologies Private Limited
 
PDF
Unlock Efficiency with Insurance Policy Administration Systems
Insurance Tech Services
 
PDF
MiniTool Partition Wizard 12.8 Crack License Key LATEST
hashhshs786
 
PDF
Download Canva Pro 2025 PC Crack Full Latest Version
bashirkhan333g
 
AEM User Group: India Chapter Kickoff Meeting
jennaf3
 
Transforming Mining & Engineering Operations with Odoo ERP | Streamline Proje...
SatishKumar2651
 
Why Businesses Are Switching to Open Source Alternatives to Crystal Reports.pptx
Varsha Nayak
 
유니티에서 Burst Compiler+ThreadedJobs+SIMD 적용사례
Seongdae Kim
 
Hardware(Central Processing Unit ) CU and ALU
RizwanaKalsoom2
 
SAP Firmaya İade ABAB Kodları - ABAB ile yazılmıl hazır kod örneği
Salih Küçük
 
MiniTool Partition Wizard Free Crack + Full Free Download 2025
bashirkhan333g
 
vMix Pro 28.0.0.42 Download vMix Registration key Bundle
kulindacore
 
Help for Correlations in IBM SPSS Statistics.pptx
Version 1 Analytics
 
Foundations of Marketo Engage - Powering Campaigns with Marketo Personalization
bbedford2
 
Empowering Asian Contributions: The Rise of Regional User Groups in Open Sour...
Shane Coughlan
 
Agentic Automation Journey Series Day 2 – Prompt Engineering for UiPath Agents
klpathrudu
 
Agentic Automation Journey Session 1/5: Context Grounding and Autopilot for E...
klpathrudu
 
Top Agile Project Management Tools for Teams in 2025
Orangescrum
 
[Solution] Why Choose the VeryPDF DRM Protector Custom-Built Solution for You...
Lingwen1998
 
The 5 Reasons for IT Maintenance - Arna Softech
Arna Softech
 
Odoo CRM vs Zoho CRM: Honest Comparison 2025
Odiware Technologies Private Limited
 
Unlock Efficiency with Insurance Policy Administration Systems
Insurance Tech Services
 
MiniTool Partition Wizard 12.8 Crack License Key LATEST
hashhshs786
 
Download Canva Pro 2025 PC Crack Full Latest Version
bashirkhan333g
 

groovy databases

  • 1. Working with Databases and Groovy Dr Paul King Groovy Lead for Object Computing Inc. @paulk_asert http://slideshare.net/paulk_asert/groovy-databases https://github.com/paulk-asert/groovy-databases
  • 2. Contents • groovy.sql.Sql • Connecting to a database • Writing to a database • Reading from a database • Stored Procedures • Advanced Reading/Writing • groovy.sql.DataSet • MongoDB • Neo4j 2
  • 4. Connecting to a database… • Sql.newInstance • assumes driver is on the classpath • other newInstance variants available 4 import groovy.sql.Sql def url = 'jdbc:hsqldb:mem:marathon' def user = 'sa' def password = '' def driver = 'org.hsqldb.jdbcDriver' def sql = Sql.newInstance(url, user, password, driver) // use 'sql' instance sql.close()
  • 5. …Connecting to a database… • Some variations 5 Advanced def sql = Sql.newInstance( url: 'jdbc:hsqldb:mem:marathon', user: 'sa', password: '', driver: 'org.hsqldb.jdbcDriver', cacheStatements: true, resultSetConcurrency: CONCUR_READ_ONLY ) Sql.withInstance(url, user, password, driver) { // use 'sql' instance } // no close() required @Grab('org.hsqldb:hsqldb:2.3.3') @GrabConfig(systemClassLoader=true) import groovy.sql.Sql // ...
  • 6. …Connecting to a database… • new Sql() constructor • if you have a DataSource or existing Connection or Sql instance • Likely to be the preferred approach with JDK9 Jigsaw 6 import groovy.sql.Sql import org.hsqldb.jdbc.JDBCDataSource def dataSource = new JDBCDataSource( database: 'jdbc:hsqldb:mem:marathon', user: 'sa', password: '') def sql = new Sql(dataSource) // use 'sql' instance sql.close()
  • 7. …Connecting to a database • new Sql() constructor (cont'd) 7 @Grab('org.hsqldb:hsqldb:2.3.3') @Grab('commons-dbcp:commons-dbcp:1.4') import groovy.sql.Sql import org.apache.commons.dbcp.BasicDataSource def url = 'jdbc:hsqldb:mem:marathon' def driver = 'org.hsqldb.jdbcDriver' def dataSource = new BasicDataSource( driverClassName: driver, url: url, username: 'sa', password: '') def sql = new Sql(dataSource) // use 'sql' instance sql.close() Advanced
  • 8. Writing to a database… 8 def DDL = ''' DROP TABLE Athlete IF EXISTS; CREATE TABLE Athlete ( athleteId INTEGER GENERATED BY DEFAULT AS IDENTITY, firstname VARCHAR(64), lastname VARCHAR(64), dateOfBirth DATE, ); ''' sql.execute(DDL) sql.execute ''' INSERT INTO Athlete (firstname, lastname, dateOfBirth) VALUES ('Paul', 'Tergat', '1969-06-17') '''
  • 9. …Writing to a database 9 def data = [first: 'Khalid', last: 'Khannouchi', birth: '1971-12-22'] sql.execute """ INSERT INTO Athlete (firstname, lastname, dateOfBirth) VALUES (${data.first},${data.last},${data.birth}) """ String athleteInsert = 'INSERT INTO Athlete (firstname, lastname) VALUES (?,?)' def keys = sql.executeInsert athleteInsert, ['Ronaldo', 'da Costa'] assert keys[0] == [2] def rowsUpdated = sql.executeUpdate ''' UPDATE Athlete SET dateOfBirth='1970-06-07' where lastname='da Costa' ''' assert rowsUpdated == 1 sql.execute "delete from Athlete where lastname = 'Tergat'" Advanced
  • 10. Reading from a database… 10 sql.query('SELECT firstname, lastname FROM Athlete') { resultSet -> while (resultSet.next()) { print resultSet.getString(1) print ' ' println resultSet.getString('lastname') } } sql.eachRow('SELECT firstname, lastname FROM Athlete') { row -> println row[0] + ' ' + row.lastname }
  • 11. …Reading from a database 11 def first = sql.firstRow('SELECT lastname, dateOfBirth FROM Athlete') def firstString = first.toMapString().toLowerCase() assert firstString == '[lastname:tergat, dateofbirth:1969-06-17]' List athletes = sql.rows('SELECT firstname, lastname FROM Athlete') println "There are ${athletes.size()} Athletes:" println athletes.collect { "$it.FIRSTNAME ${it[-1]}" }.join(", ") assert sql.firstRow('SELECT COUNT(*) as num FROM Athlete').num == 3
  • 12. Invoking Stored Procedures… 12 def FULL_DLL = ''' DROP TABLE Athlete IF EXISTS; CREATE TABLE Athlete ( athleteId INTEGER GENERATED BY DEFAULT AS IDENTITY, firstname VARCHAR(64), lastname VARCHAR(64), dateOfBirth DATE ); DROP INDEX idx IF EXISTS; CREATE INDEX idx ON Athlete (athleteId); DROP TABLE Run IF EXISTS; CREATE TABLE Run ( runId INTEGER GENERATED BY DEFAULT AS IDENTITY, distance INTEGER, -- in meters time INTEGER, -- in seconds venue VARCHAR(64), when TIMESTAMP, fkAthlete INTEGER, CONSTRAINT fk FOREIGN KEY (fkAthlete) REFERENCES Athlete (athleteId) ON DELETE CASCADE ); ''' sql.execute FULL_DLL Advanced Athlete athleteId firstname lastname dateOfBirth Run runId distance time venue when fkAthlete
  • 13. …Invoking Stored Procedures… • And assume some data has been populated … • We've refactored our previous insert code into some helper methods. 13 insertAthlete('Paul', 'Tergat', '1969-06-17') insertAthlete('Khalid', 'Khannouchi', '1971-12-22') insertAthlete('Ronaldo', 'da Costa', '1970-06-07') insertRun(2, 4, 55, 'Berlin', '2003-09-28', 'Tergat') insertRun(2, 5, 38, 'London', '2002-04-14', 'Khannouchi') insertRun(2, 5, 42, 'Chicago', '1999-10-24', 'Khannouchi') insertRun(2, 6, 05, 'Berlin', '1998-09-20', 'da Costa')
  • 14. …Invoking Stored Procedures… 14 db.execute ''' CREATE FUNCTION SELECT_ATHLETE_RUN () RETURNS TABLE (lastname VARCHAR(64), venue VARCHAR(64), whenRun DATE) READS SQL DATA RETURN TABLE ( select Athlete.lastname, Run.venue, Run.whenRun from Athlete, Run where Athlete.athleteId = Run.fkAthlete order by whenRun ) ''' db.eachRow('CALL SELECT_ATHLETE_RUN()') { println "$it.lastname $it.venue $it.whenRun" } da Costa Berlin 1998-09-20 Khannouchi Chicago 1999-10-24 Khannouchi London 2002-04-14 Tergat Berlin 2003-09-28
  • 15. …Invoking Stored Procedures… 15 db.execute ''' CREATE FUNCTION FULL_NAME (p_lastname VARCHAR(64)) RETURNS VARCHAR(100) READS SQL DATA BEGIN ATOMIC declare ans VARCHAR(100); SELECT CONCAT(firstname, ' ', lastname) INTO ans FROM Athlete WHERE lastname = p_lastname; return ans; END ''' assert db.firstRow("{? = call FULL_NAME(?)}", ['Tergat'])[0] == 'Paul Tergat'
  • 16. …Invoking Stored Procedures 16 db.execute ''' CREATE PROCEDURE CONCAT_NAME (OUT fullname VARCHAR(100), IN first VARCHAR(50), IN last VARCHAR(50)) BEGIN ATOMIC SET fullname = CONCAT(first, ' ', last); END ''' db.call("{call CONCAT_NAME(?, ?, ?)}", [Sql.VARCHAR, 'Paul', 'Tergat']) { fullname -> assert fullname == 'Paul Tergat' }
  • 17. Advanced Reading… • Rowset metadata 17 def dump(sql, tablename) { println " CONTENT OF TABLE ${tablename} ".center(40, '-') sql.eachRow('SELECT * FROM ' + tablename) { rs -> def meta = rs.getMetaData() if (meta.columnCount <= 0) return for (i in 0..<meta.columnCount) { print "${i}: ${meta.getColumnLabel(i + 1)}".padRight(20) // counts from 1 print rs[i]?.toString() // counts from 0 print "n" } println '-' * 40 } }
  • 18. …Advanced Reading… 18 def dump(sql, tablename) { println " CONTENT OF TABLE ${tablename} ".center(40, '-') sql.eachRow('SELECT * FROM ' + tablename) { rs -> def meta = rs.getMetaData() if (meta.columnCount <= 0) return for (i in 0..<meta.columnCount) { print "${i}: ${meta.getColumnLabel(i + 1)}".padRight(20) // counts from 1 print rs[i]?.toString() // counts from 0 print "n" } println '-' * 40 } } ----------------------- CONTENT OF TABLE Athlete ----------------------- ATHLETEID FIRSTNAME LASTNAME DATEOFBIRTH ------------------------------------------------------------------------ 1 Paul Tergat 1969-06-17 2 Khalid Khannouchi 1971-12-22 3 Ronaldo da Costa 1970-06-07
  • 19. …Advanced Reading… 19 def dump2(sql, tablename) { def printColNames = { meta -> def width = meta.columnCount * 18 println " CONTENT OF TABLE ${tablename} ".center(width, '-') (1..meta.columnCount).each { print meta.getColumnLabel(it).padRight(18) } println() println '-' * width } def printRow = { row -> row.toRowResult().values().each { print it.toString().padRight(18) } println() } sql.eachRow('SELECT * FROM ' + tablename, printColNames, printRow) } metadata closure
  • 20. …Advanced Reading • Pagination 20 qry = 'SELECT * FROM Athlete' assert sql.rows(qry, 1, 4)*.lastname == ['Tergat', 'Khannouchi', 'da Costa', 'Gebrselassie'] assert sql.rows(qry, 5, 4)*.lastname == ['Makau', 'Radcliffe', 'Ndereba', 'Takahashi'] assert sql.rows(qry, 9, 4)*.lastname == ['Loroupe', 'Kristiansen']
  • 21. Advanced Writing… • Simple transaction support 21 sql.withTransaction { insertAthlete('Haile', 'Gebrselassie', '1973-04-18') insertAthlete('Patrick', 'Makau', '1985-03-02') } Advanced
  • 22. …Advanced Writing… • Batching of ad-hoc SQL statements 22 sql.execute "delete from Athlete where lastname = 'Tergat'" sql.withBatch { stmt -> stmt.addBatch ''' INSERT INTO Athlete (firstname, lastname, dateOfBirth) VALUES ('Paul', 'Tergat', '1969-06-17')''' stmt.addBatch """ INSERT INTO Run (distance, time, venue, when, fkAthlete) SELECT 42195, ${2*60*60+4*60+55}, 'Berlin', '2003-09-28', athleteId FROM Athlete WHERE lastname='Tergat'""" } //22/04/2013 6:34:59 AM groovy.sql.BatchingStatementWrapper processResult //FINE: Successfully executed batch with 2 command(s)
  • 23. …Advanced Writing… • Batching with a prepared statement 23 def qry = 'INSERT INTO Athlete (firstname, lastname, dateOfBirth) VALUES (?,?,?);' sql.withBatch(3, qry) { ps -> ps.addBatch('Paula', 'Radcliffe', '1973-12-17') ps.addBatch('Catherine', 'Ndereba', '1972-07-21') ps.addBatch('Naoko', 'Takahashi', '1972-05-06') ps.addBatch('Tegla', 'Loroupe', '1973-05-09') ps.addBatch('Ingrid', 'Kristiansen', '1956-03-21') } // If logging is turned on: // 20/04/2013 2:18:10 AM groovy.sql.BatchingStatementWrapper processResult // FINE: Successfully executed batch with 3 command(s) // 20/04/2013 2:18:10 AM groovy.sql.BatchingStatementWrapper processResult // FINE: Successfully executed batch with 2 command(s)
  • 24. …Advanced Writing • Named parameters (two variants) and named-ordinal parameters 24 @Canonical class Athlete { String first, last, dob } def ndereba = new Athlete('Catherine', 'Ndereba', '1972-07-21') def takahashi = new Athlete('Naoko', 'Takahashi') def takahashiExtra = [dob: '1972-05-06'] def loroupe = [first: 'Tegla', last: 'Loroupe', dob: '1973-05-09'] def insertPrefix = 'INSERT INTO Athlete (firstname, lastname, dateOfBirth) VALUES ' sql.execute insertPrefix + ' (?.first,?.last,?.dob)', ndereba sql.execute insertPrefix + ' (?1.first,?1.last,?2.dob)', takahashi, takahashiExtra sql.execute insertPrefix + ' (:first,:last,:dob)', loroupe sql.execute insertPrefix + ' (:first,:last,:dob)', first: 'Ingrid', last: 'Kristiansen', dob: '1956-03-21'
  • 25. Topics • groovy.sql.Sql • Connecting to a database • Writing to a database • Reading from a database • Stored Procedures • Advanced Reading/Writing  groovy.sql.DataSet • MongoDB • Neo4j
  • 26. groovy.sql.DataSet • Allows any table within an RDBMS to appear as if it was a Java-like collection of POGOs • Can be thought of as a poor man's object-relational mapping system • Has some smarts for lazy execution of database queries • Not meant to be as sophisticated as hibernate 26
  • 27. DataSet example… 27 def athletes = sql.dataSet('Athlete') athletes.each { println it.firstname } athletes.add( firstname: 'Paula', lastname: 'Radcliffe', dateOfBirth: '1973-12-17' ) athletes.each { println it.firstname } def runs = sql.dataSet('AthleteRun').findAll { it.firstname == 'Khalid' } runs.each { println "$it.lastname $it.venue" } Paul Khalid Ronaldo Paul Khalid Ronaldo Paula Khannouchi London Khannouchi Chicago
  • 28. …DataSet example 28 def query = athletes.findAll { it.firstname >= 'P' } query = query.findAll { it.dateOfBirth > '1970-01-01' } query = query.sort { it.dateOfBirth } query = query.reverse() println query.sql println query.parameters println query.rows()*.firstname // One SQL query here! select * from Athlete where firstname >= ? and dateOfBirth > ? order by dateOfBirth DESC [P, 1970-01-01] [Paula, Ronaldo]
  • 29. Overcoming groovy.sql.DataSet limitations 29 def DLL_WITH_VIEW = ''' DROP TABLE Athlete IF EXISTS; CREATE TABLE Athlete ( athleteId INTEGER GENERATED BY DEFAULT AS IDENTITY, firstname VARCHAR(64), lastname VARCHAR(64), dateOfBirth DATE ); DROP INDEX idx IF EXISTS; CREATE INDEX idx ON Athlete (athleteId); DROP TABLE Run IF EXISTS; CREATE TABLE Run ( runId INTEGER GENERATED BY DEFAULT AS IDENTITY, distance INTEGER, -- in meters time INTEGER, -- in seconds venue VARCHAR(64), when TIMESTAMP, fkAthlete INTEGER, CONSTRAINT fk FOREIGN KEY (fkAthlete) REFERENCES Athlete (athleteId) ON DELETE CASCADE ); DROP VIEW AthleteRun IF EXISTS; CREATE VIEW AthleteRun AS SELECT * FROM Athlete LEFT OUTER JOIN Run ON fkAthlete=athleteId; ''' db.execute DLL_WITH_VIEW
  • 30. Topics • groovy.sql.Sql • Connecting to a database • Writing to a database • Reading from a database • Stored Procedures • Advanced Reading/Writing • groovy.sql.DataSet  MongoDB • Neo4j
  • 31. MongoDB… 31 @Grab('com.gmongo:gmongo:1.3') import com.gmongo.GMongo import com.mongodb.util.JSON import groovy.transform.Field @Field db = new GMongo().getDB('athletes') db.athletes.drop() db.athletes << [first: 'Paul', last: 'Tergat', dob: '1969-06-17', runs: [ [distance: 42195, time: 2 * 60 * 60 + 4 * 60 + 55, venue: 'Berlin', when: '2003-09-28'] ]] def insertAthlete(first, last, dob) { db.athletes << [first: first, last: last, dob: dob] }
  • 32. …MongoDB… 32 def insertRun(h, m, s, venue, date, lastname) { db.athletes.update( [last: lastname], [$addToSet: [runs: [distance: 42195, time: h * 60 * 60 + m * 60 + s, venue: venue, when: date]]] ) } insertAthlete('Khalid', 'Khannouchi', '1971-12-22') insertAthlete('Ronaldo', 'da Costa', '1970-06-07') insertRun(2, 5, 38, 'London', '2002-04-14', 'Khannouchi') insertRun(2, 5, 42, 'Chicago', '1999-10-24', 'Khannouchi') insertRun(2, 6, 05, 'Berlin', '1998-09-20', 'da Costa')
  • 33. …MongoDB… 33 def radcliffe = """{ first: 'Paula', last: 'Radcliffe', dob: '1973-12-17', runs: [ {distance: 42195, time: ${2 * 60 * 60 + 15 * 60 + 25}, venue: 'London', when: '2003-04-13'} ] }""" db.athletes << JSON.parse(radcliffe) assert db.athletes.count == 4 db.athletes.find().each { println "$it._id $it.last ${it.runs.size()}" } 516b15fc2b10a15fa09331f2 Tergat 1 516b15fc2b10a15fa09331f3 Khannouchi 2 516b15fc2b10a15fa09331f4 da Costa 1 516b15fc2b10a15fa09331f5 Radcliffe 1
  • 34. …MongoDB 34 def londonAthletes = db.athletes.find('runs.venue': 'London')*.first assert londonAthletes == ['Khalid', 'Paula'] def youngAthletes = db.athletes.aggregate( [$project: [first: 1, dob: 1]], [$match: [dob: [$gte: '1970-01-01']]], [$sort: [dob: -1]] ) assert youngAthletes.results()*.first == ['Paula', 'Khalid', 'Ronaldo']
  • 35. Topics • groovy.sql.Sql • Connecting to a database • Writing to a database • Reading from a database • Stored Procedures • Advanced Reading/Writing • groovy.sql.DataSet • MongoDB  Neo4j
  • 37. …Neo4j… 37 @Grab('org.neo4j:neo4j-kernel:2.1.4') @Grab('com.tinkerpop.gremlin:gremlin-groovy:2.5.0') //@Grab('com.tinkerpop.blueprints:blueprints-neo4j-graph:2.5.0') @Grab('com.tinkerpop.blueprints:blueprints-neo4j-graph:2.5.0;transitive=false') @Grab('com.tinkerpop.blueprints:blueprints-core:2.5.0') //@Grab('codehaus-stax:stax:1.1.1') //@GrabResolver('https://repository.jboss.org/nexus/content/repositories/thirdparty-releases') @GrabExclude('org.codehaus.groovy:groovy') import com.tinkerpop.blueprints.Graph import com.tinkerpop.blueprints.impls.neo4j.Neo4jGraph //import com.tinkerpop.blueprints.util.io.graphml.GraphMLWriter import com.tinkerpop.gremlin.groovy.Gremlin import groovy.transform.Field import org.neo4j.graphdb.traversal.Evaluators import org.neo4j.kernel.EmbeddedGraphDatabase import org.neo4j.graphdb.* import org.neo4j.kernel.Traversal import org.neo4j.kernel.Uniqueness @Field graphDb = new EmbeddedGraphDatabase("athletes") enum MyRelationshipTypes implements RelationshipType { ran, supercedes }
  • 38. …Neo4j… 38 // some optional metaclass syntactic sugar EmbeddedGraphDatabase.metaClass { createNode { Map properties -> def n = delegate.createNode() properties.each { k, v -> n[k] = v } n } } Node.metaClass { propertyMissing { String name, val -> delegate.setProperty(name, val) } propertyMissing { String name -> delegate.getProperty(name) } methodMissing { String name, args -> delegate.createRelationshipTo(args[0], MyRelationshipTypes."$name") } } Relationship.metaClass { propertyMissing { String name, val -> delegate.setProperty(name, val) } propertyMissing { String name -> delegate.getProperty(name) } }
  • 39. …Neo4j… 39 def insertAthlete(first, last, dob) { graphDb.createNode(first: first, last: last, dob: dob) } def insertRecord(h, m, s, venue, when, athlete) { def record = graphDb.createNode(distance: 42195, time: h * 60 * 60 + m * 60 + s, venue: venue, when: when) athlete.won(record) record } Gremlin.load() def tx = graphDb.beginTx() def athlete1, athlete2, athlete3, athlete4 def marathon1, marathon2a, marathon2b, marathon3, marathon4a, marathon4b
  • 40. …Neo4j… 40 try { athlete1 = graphDb.createNode() athlete1.first = 'Paul' athlete1.last = 'Tergat' athlete1.dob = '1969-06-17' marathon1 = graphDb.createNode() marathon1.distance = 42195 marathon1.time = 2 * 60 * 60 + 4 * 60 + 55 marathon1.venue = 'Berlin' marathon1.when = '2003-09-28' athlete1.won(marathon1) athlete2 = insertAthlete('Khalid', 'Khannouchi', '1971-12-22') marathon2a = insertRecord(2, 5, 38, 'London', '2002-04-14', athlete2) marathon2b = insertRecord(2, 5, 42, 'Chicago', '1999-10-24', athlete2) athlete3 = insertAthlete('Ronaldo', 'da Costa', '1970-06-07') marathon3 = insertRecord(2, 6, 5, 'Berlin', '1998-09-20', athlete3) athlete4 = insertAthlete('Paula', 'Radcliffe', '1973-12-17') marathon4a = insertRecord(2, 17, 18, 'Chicago', '2002-10-13', athlete4) marathon4b = insertRecord(2, 15, 25, 'London', '2003-04-13', athlete4)
  • 41. …Neo4j… 41 def venue = marathon1.venue def when = marathon1.when println "$athlete1.first $athlete1.last won the $venue marathon on $when" def allAthletes = [athlete1, athlete2, athlete3, athlete4] def wonInLondon = allAthletes.findAll { athlete -> athlete.getRelationships(MyRelationshipTypes.won).any { record -> record.getOtherNode(athlete).venue == 'London' } } assert wonInLondon*.last == ['Khannouchi', 'Radcliffe'] marathon2b.supercedes(marathon3) marathon2a.supercedes(marathon2b) marathon1.supercedes(marathon2a) marathon4b.supercedes(marathon4a)
  • 42. …Neo4j… 42 println "World records following $marathon3.venue $marathon3.when:" def t = new Traversal() for (Path p in t.description().breadthFirst(). relationships(MyRelationshipTypes.supercedes). evaluator(Evaluators.fromDepth(1)). uniqueness(Uniqueness.NONE). traverse(marathon3)) { def newRecord = p.endNode() println "$newRecord.venue $newRecord.when" } Graph g = new Neo4jGraph(graphDb) def pretty = { it.collect { "$it.venue $it.when" }.join(', ') } def results = [] g.V('venue', 'London').fill(results) println 'London world records: ' + pretty(results) results = [] g.V('venue', 'London').in('supercedes').fill(results) println 'World records after London: ' + pretty(results)
  • 43. …Neo4j 43 results = [] def emitAll = { true } def forever = { true } def berlin98 = { it.venue == 'Berlin' && it.when.startsWith('1998') } g.V.filter(berlin98).in('supercedes').loop(1, forever, emitAll).fill(results) println 'World records after Berlin 1998: ' + pretty(results) // def writer = new GraphMLWriter(g) // def out = new FileOutputStream("c:/temp/athletes.graphml") // writer.outputGraph(out) // writer.setNormalize(true) // out.close() tx.success() } finally { tx.finish() graphDb.shutdown() }
  • 44. More Information: Groovy in Action, 2ed 44