groovy databases

Paul King
Paul KingSoftware Engineer, Entrepreneur, Director at ASERT
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
1 of 44

Recommended

concurrency with GPars by
concurrency with GParsconcurrency with GPars
concurrency with GParsPaul King
7.6K views105 slides
اسلاید اول جلسه چهارم کلاس پایتون برای هکرهای قانونی by
اسلاید اول جلسه چهارم کلاس پایتون برای هکرهای قانونیاسلاید اول جلسه چهارم کلاس پایتون برای هکرهای قانونی
اسلاید اول جلسه چهارم کلاس پایتون برای هکرهای قانونیMohammad Reza Kamalifard
413 views17 slides
CodeCamp Iasi 10 march 2012 - Practical Groovy by
CodeCamp Iasi 10 march 2012 - Practical GroovyCodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical GroovyCodecamp Romania
585 views18 slides
Swing database(mysql) by
Swing database(mysql)Swing database(mysql)
Swing database(mysql)vishal choudhary
50 views19 slides
Nantes Jug - Java 7 by
Nantes Jug - Java 7Nantes Jug - Java 7
Nantes Jug - Java 7Sébastien Prunier
803 views32 slides

More Related Content

What's hot

Five by
FiveFive
FiveŁukasz Langa
407 views52 slides
Fun Teaching MongoDB New Tricks by
Fun Teaching MongoDB New TricksFun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksMongoDB
2.5K views27 slides
BDD - Behavior Driven Development Webapps mit Groovy Spock und Geb by
BDD - Behavior Driven Development Webapps mit Groovy Spock und GebBDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
BDD - Behavior Driven Development Webapps mit Groovy Spock und GebChristian Baranowski
2.4K views29 slides
Scala introduction by
Scala introductionScala introduction
Scala introductionAlf Kristian Støyle
2K views62 slides
Python dictionary : past, present, future by
Python dictionary: past, present, futurePython dictionary: past, present, future
Python dictionary : past, present, futuredelimitry
2.8K views58 slides
What I learned from Seven Languages in Seven Weeks (IPRUG) by
What I learned from Seven Languages in Seven Weeks (IPRUG)What I learned from Seven Languages in Seven Weeks (IPRUG)
What I learned from Seven Languages in Seven Weeks (IPRUG)Kerry Buckley
1.1K views126 slides

What's hot(20)

Fun Teaching MongoDB New Tricks by MongoDB
Fun Teaching MongoDB New TricksFun Teaching MongoDB New Tricks
Fun Teaching MongoDB New Tricks
MongoDB2.5K views
BDD - Behavior Driven Development Webapps mit Groovy Spock und Geb by Christian Baranowski
BDD - Behavior Driven Development Webapps mit Groovy Spock und GebBDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
BDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
Python dictionary : past, present, future by delimitry
Python dictionary: past, present, futurePython dictionary: past, present, future
Python dictionary : past, present, future
delimitry2.8K views
What I learned from Seven Languages in Seven Weeks (IPRUG) by Kerry Buckley
What I learned from Seven Languages in Seven Weeks (IPRUG)What I learned from Seven Languages in Seven Weeks (IPRUG)
What I learned from Seven Languages in Seven Weeks (IPRUG)
Kerry Buckley1.1K views
JPoint 2016 - Валеев Тагир - Странности Stream API by tvaleev
JPoint 2016 - Валеев Тагир - Странности Stream APIJPoint 2016 - Валеев Тагир - Странности Stream API
JPoint 2016 - Валеев Тагир - Странности Stream API
tvaleev2K views
Implementing a many-to-many Relationship with Slick by Hermann Hueck
Implementing a many-to-many Relationship with SlickImplementing a many-to-many Relationship with Slick
Implementing a many-to-many Relationship with Slick
Hermann Hueck4.6K views
Python 표준 라이브러리 by 용 최
Python 표준 라이브러리Python 표준 라이브러리
Python 표준 라이브러리
용 최6.9K views
Обзор фреймворка Twisted by Maxim Kulsha
Обзор фреймворка TwistedОбзор фреймворка Twisted
Обзор фреймворка Twisted
Maxim Kulsha357 views
Programming Java - Lection 07 - Puzzlers - Lavrentyev Fedor by Fedor Lavrentyev
Programming Java - Lection 07 - Puzzlers - Lavrentyev FedorProgramming Java - Lection 07 - Puzzlers - Lavrentyev Fedor
Programming Java - Lection 07 - Puzzlers - Lavrentyev Fedor
Fedor Lavrentyev234 views
Optimizing Slow Queries with Indexes and Creativity by MongoDB
Optimizing Slow Queries with Indexes and CreativityOptimizing Slow Queries with Indexes and Creativity
Optimizing Slow Queries with Indexes and Creativity
MongoDB4.2K views
엘라스틱서치 적합성 이해하기 20160630 by Yong Joon Moon
엘라스틱서치 적합성 이해하기 20160630엘라스틱서치 적합성 이해하기 20160630
엘라스틱서치 적합성 이해하기 20160630
Yong Joon Moon1.7K views
JJUG CCC 2011 Spring by Kiyotaka Oku
JJUG CCC 2011 SpringJJUG CCC 2011 Spring
JJUG CCC 2011 Spring
Kiyotaka Oku1.7K views
Building DSLs with Groovy by Sten Anderson
Building DSLs with GroovyBuilding DSLs with Groovy
Building DSLs with Groovy
Sten Anderson542 views
Understanding Source Code Differences by Separating Refactoring Effects by Shinpei Hayashi
Understanding Source Code Differences by Separating Refactoring EffectsUnderstanding Source Code Differences by Separating Refactoring Effects
Understanding Source Code Differences by Separating Refactoring Effects
Shinpei Hayashi18.9K views

Viewers also liked

awesome groovy by
awesome groovyawesome groovy
awesome groovyPaul King
19.7K views151 slides
groovy transforms by
groovy transformsgroovy transforms
groovy transformsPaul King
3.5K views113 slides
Make Your Testing Groovy by
Make Your Testing GroovyMake Your Testing Groovy
Make Your Testing GroovyPaul King
4.2K views74 slides
concurrency gpars by
concurrency gparsconcurrency gpars
concurrency gparsPaul King
18.9K views103 slides
Vert.X like Node.js but polyglot and reactive on JVM by
Vert.X like Node.js but polyglot and reactive on JVMVert.X like Node.js but polyglot and reactive on JVM
Vert.X like Node.js but polyglot and reactive on JVMMassimiliano Dessì
8.2K views66 slides
Oredev 2015 - Taming Java Agents by
Oredev 2015 - Taming Java AgentsOredev 2015 - Taming Java Agents
Oredev 2015 - Taming Java AgentsAnton Arhipov
1.7K views40 slides

Viewers also liked(8)

awesome groovy by Paul King
awesome groovyawesome groovy
awesome groovy
Paul King19.7K views
groovy transforms by Paul King
groovy transformsgroovy transforms
groovy transforms
Paul King3.5K views
Make Your Testing Groovy by Paul King
Make Your Testing GroovyMake Your Testing Groovy
Make Your Testing Groovy
Paul King4.2K views
concurrency gpars by Paul King
concurrency gparsconcurrency gpars
concurrency gpars
Paul King18.9K views
Vert.X like Node.js but polyglot and reactive on JVM by Massimiliano Dessì
Vert.X like Node.js but polyglot and reactive on JVMVert.X like Node.js but polyglot and reactive on JVM
Vert.X like Node.js but polyglot and reactive on JVM
Massimiliano Dessì8.2K views
Oredev 2015 - Taming Java Agents by Anton Arhipov
Oredev 2015 - Taming Java AgentsOredev 2015 - Taming Java Agents
Oredev 2015 - Taming Java Agents
Anton Arhipov1.7K views
Patterns of Cloud Native Architecture by Andrew Shafer
Patterns of Cloud Native ArchitecturePatterns of Cloud Native Architecture
Patterns of Cloud Native Architecture
Andrew Shafer7.3K views
groovy rules by Paul King
groovy rulesgroovy rules
groovy rules
Paul King11.6K views

Similar to groovy databases

3 database-jdbc(1) by
3 database-jdbc(1)3 database-jdbc(1)
3 database-jdbc(1)hameedkhan2017
344 views75 slides
Ruby on Rails: Tasty Burgers by
Ruby on Rails: Tasty BurgersRuby on Rails: Tasty Burgers
Ruby on Rails: Tasty BurgersAaron Patterson
7.7K views244 slides
MySQL flexible schema and JSON for Internet of Things by
MySQL flexible schema and JSON for Internet of ThingsMySQL flexible schema and JSON for Internet of Things
MySQL flexible schema and JSON for Internet of ThingsAlexander Rubin
468 views35 slides
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow) by
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)MongoSF
2.9K views133 slides
Having Fun Programming! by
Having Fun Programming!Having Fun Programming!
Having Fun Programming!Aaron Patterson
863 views175 slides
Marrow: A Meta-Framework for Python 2.6+ and 3.1+ by
Marrow: A Meta-Framework for Python 2.6+ and 3.1+Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+ConFoo
2.7K views281 slides

Similar to groovy databases(20)

MySQL flexible schema and JSON for Internet of Things by Alexander Rubin
MySQL flexible schema and JSON for Internet of ThingsMySQL flexible schema and JSON for Internet of Things
MySQL flexible schema and JSON for Internet of Things
Alexander Rubin468 views
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow) by MongoSF
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
MongoSF2.9K views
Marrow: A Meta-Framework for Python 2.6+ and 3.1+ by ConFoo
Marrow: A Meta-Framework for Python 2.6+ and 3.1+Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+
ConFoo2.7K views
Imugi: Compiler made with Python by Han Lee
Imugi: Compiler made with PythonImugi: Compiler made with Python
Imugi: Compiler made with Python
Han Lee932 views
ES6 patterns in the wild by Joe Morgan
ES6 patterns in the wildES6 patterns in the wild
ES6 patterns in the wild
Joe Morgan1.5K views
Notes for SQLite3 Usage by William Lee
Notes for SQLite3 UsageNotes for SQLite3 Usage
Notes for SQLite3 Usage
William Lee1.6K views
The Ring programming language version 1.9 book - Part 53 of 210 by Mahmoud Samir Fayed
The Ring programming language version 1.9 book - Part 53 of 210The Ring programming language version 1.9 book - Part 53 of 210
The Ring programming language version 1.9 book - Part 53 of 210
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6 by Dmitry Soshnikov
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
Dmitry Soshnikov8.7K views
Refactoring to Macros with Clojure by Dmitry Buzdin
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
Dmitry Buzdin3.5K views
The Ring programming language version 1.4.1 book - Part 13 of 31 by Mahmoud Samir Fayed
The Ring programming language version 1.4.1 book - Part 13 of 31The Ring programming language version 1.4.1 book - Part 13 of 31
The Ring programming language version 1.4.1 book - Part 13 of 31
Utilizing Powerful Extensions for Analytics and Operations by Neo4j
Utilizing Powerful Extensions for Analytics and OperationsUtilizing Powerful Extensions for Analytics and Operations
Utilizing Powerful Extensions for Analytics and Operations
Neo4j378 views
node.js and the AR.Drone: building a real-time dashboard using socket.io by Steven Beeckman
node.js and the AR.Drone: building a real-time dashboard using socket.ionode.js and the AR.Drone: building a real-time dashboard using socket.io
node.js and the AR.Drone: building a real-time dashboard using socket.io
Steven Beeckman15.9K views
Owasp Indy Q2 2012 Advanced SQLi by owaspindy
Owasp Indy Q2 2012 Advanced SQLiOwasp Indy Q2 2012 Advanced SQLi
Owasp Indy Q2 2012 Advanced SQLi
owaspindy2K views
From mysql to MongoDB(MongoDB2011北京交流会) by Night Sailer
From mysql to MongoDB(MongoDB2011北京交流会)From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)
Night Sailer1.5K views

More from Paul King

tictactoe groovy by
tictactoe groovytictactoe groovy
tictactoe groovyPaul King
19.2K views35 slides
functional groovy by
functional groovyfunctional groovy
functional groovyPaul King
3K views99 slides
Make Testing Groovy by
Make Testing GroovyMake Testing Groovy
Make Testing GroovyPaul King
1.7K views102 slides
Agile Testing Practices by
Agile Testing PracticesAgile Testing Practices
Agile Testing PracticesPaul King
2.7K views82 slides
groovy DSLs from beginner to expert by
groovy DSLs from beginner to expertgroovy DSLs from beginner to expert
groovy DSLs from beginner to expertPaul King
9.8K views194 slides
groovy and concurrency by
groovy and concurrencygroovy and concurrency
groovy and concurrencyPaul King
10.2K views114 slides

More from Paul King(16)

tictactoe groovy by Paul King
tictactoe groovytictactoe groovy
tictactoe groovy
Paul King19.2K views
functional groovy by Paul King
functional groovyfunctional groovy
functional groovy
Paul King3K views
Make Testing Groovy by Paul King
Make Testing GroovyMake Testing Groovy
Make Testing Groovy
Paul King1.7K views
Agile Testing Practices by Paul King
Agile Testing PracticesAgile Testing Practices
Agile Testing Practices
Paul King2.7K views
groovy DSLs from beginner to expert by Paul King
groovy DSLs from beginner to expertgroovy DSLs from beginner to expert
groovy DSLs from beginner to expert
Paul King9.8K views
groovy and concurrency by Paul King
groovy and concurrencygroovy and concurrency
groovy and concurrency
Paul King10.2K views
GroovyDSLs by Paul King
GroovyDSLsGroovyDSLs
GroovyDSLs
Paul King4.8K views
Atlassian Groovy Plugins by Paul King
Atlassian Groovy PluginsAtlassian Groovy Plugins
Atlassian Groovy Plugins
Paul King2.3K views
Dynamic Language Practices by Paul King
Dynamic Language PracticesDynamic Language Practices
Dynamic Language Practices
Paul King4.6K views
Make Your Builds More Groovy by Paul King
Make Your Builds More GroovyMake Your Builds More Groovy
Make Your Builds More Groovy
Paul King2.1K views
Groovy Power Features by Paul King
Groovy Power FeaturesGroovy Power Features
Groovy Power Features
Paul King3.8K views
Groovy Testing Sep2009 by Paul King
Groovy Testing Sep2009Groovy Testing Sep2009
Groovy Testing Sep2009
Paul King8.6K views
Craig Smith & Paul King Agile Tool Hacking Taking Your Agile Development ... by Paul King
Craig Smith & Paul King   Agile Tool Hacking   Taking Your Agile Development ...Craig Smith & Paul King   Agile Tool Hacking   Taking Your Agile Development ...
Craig Smith & Paul King Agile Tool Hacking Taking Your Agile Development ...
Paul King4.3K views
Groovy Tutorial by Paul King
Groovy TutorialGroovy Tutorial
Groovy Tutorial
Paul King6.2K views
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau... by Paul King
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Paul King2.4K views
XML and Web Services with Groovy by Paul King
XML and Web Services with GroovyXML and Web Services with Groovy
XML and Web Services with Groovy
Paul King3.8K views

Recently uploaded

aATP - New Correlation Confirmation Feature.pptx by
aATP - New Correlation Confirmation Feature.pptxaATP - New Correlation Confirmation Feature.pptx
aATP - New Correlation Confirmation Feature.pptxEsatEsenek1
146 views6 slides
The Path to DevOps by
The Path to DevOpsThe Path to DevOps
The Path to DevOpsJohn Valentino
5 views6 slides
Ports-and-Adapters Architecture for Embedded HMI by
Ports-and-Adapters Architecture for Embedded HMIPorts-and-Adapters Architecture for Embedded HMI
Ports-and-Adapters Architecture for Embedded HMIBurkhard Stubert
29 views19 slides
Programming Field by
Programming FieldProgramming Field
Programming Fieldthehardtechnology
6 views9 slides
Top-5-production-devconMunich-2023-v2.pptx by
Top-5-production-devconMunich-2023-v2.pptxTop-5-production-devconMunich-2023-v2.pptx
Top-5-production-devconMunich-2023-v2.pptxTier1 app
6 views42 slides
How To Make Your Plans Suck Less — Maarten Dalmijn at the 57th Hands-on Agile... by
How To Make Your Plans Suck Less — Maarten Dalmijn at the 57th Hands-on Agile...How To Make Your Plans Suck Less — Maarten Dalmijn at the 57th Hands-on Agile...
How To Make Your Plans Suck Less — Maarten Dalmijn at the 57th Hands-on Agile...Stefan Wolpers
33 views38 slides

Recently uploaded(20)

aATP - New Correlation Confirmation Feature.pptx by EsatEsenek1
aATP - New Correlation Confirmation Feature.pptxaATP - New Correlation Confirmation Feature.pptx
aATP - New Correlation Confirmation Feature.pptx
EsatEsenek1146 views
Ports-and-Adapters Architecture for Embedded HMI by Burkhard Stubert
Ports-and-Adapters Architecture for Embedded HMIPorts-and-Adapters Architecture for Embedded HMI
Ports-and-Adapters Architecture for Embedded HMI
Burkhard Stubert29 views
Top-5-production-devconMunich-2023-v2.pptx by Tier1 app
Top-5-production-devconMunich-2023-v2.pptxTop-5-production-devconMunich-2023-v2.pptx
Top-5-production-devconMunich-2023-v2.pptx
Tier1 app6 views
How To Make Your Plans Suck Less — Maarten Dalmijn at the 57th Hands-on Agile... by Stefan Wolpers
How To Make Your Plans Suck Less — Maarten Dalmijn at the 57th Hands-on Agile...How To Make Your Plans Suck Less — Maarten Dalmijn at the 57th Hands-on Agile...
How To Make Your Plans Suck Less — Maarten Dalmijn at the 57th Hands-on Agile...
Stefan Wolpers33 views
Understanding HTML terminology by artembondar5
Understanding HTML terminologyUnderstanding HTML terminology
Understanding HTML terminology
artembondar57 views
Top-5-production-devconMunich-2023.pptx by Tier1 app
Top-5-production-devconMunich-2023.pptxTop-5-production-devconMunich-2023.pptx
Top-5-production-devconMunich-2023.pptx
Tier1 app9 views
Team Transformation Tactics for Holistic Testing and Quality (Japan Symposium... by Lisi Hocke
Team Transformation Tactics for Holistic Testing and Quality (Japan Symposium...Team Transformation Tactics for Holistic Testing and Quality (Japan Symposium...
Team Transformation Tactics for Holistic Testing and Quality (Japan Symposium...
Lisi Hocke35 views
Electronic AWB - Electronic Air Waybill by Freightoscope
Electronic AWB - Electronic Air Waybill Electronic AWB - Electronic Air Waybill
Electronic AWB - Electronic Air Waybill
Freightoscope 5 views
Quality Engineer: A Day in the Life by John Valentino
Quality Engineer: A Day in the LifeQuality Engineer: A Day in the Life
Quality Engineer: A Day in the Life
John Valentino7 views
FOSSLight Community Day 2023-11-30 by Shane Coughlan
FOSSLight Community Day 2023-11-30FOSSLight Community Day 2023-11-30
FOSSLight Community Day 2023-11-30
Shane Coughlan6 views
Bootstrapping vs Venture Capital.pptx by Zeljko Svedic
Bootstrapping vs Venture Capital.pptxBootstrapping vs Venture Capital.pptx
Bootstrapping vs Venture Capital.pptx
Zeljko Svedic15 views
Automated Testing of Microsoft Power BI Reports by RTTS
Automated Testing of Microsoft Power BI ReportsAutomated Testing of Microsoft Power BI Reports
Automated Testing of Microsoft Power BI Reports
RTTS8 views
Generic or specific? Making sensible software design decisions by Bert Jan Schrijver
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisions

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