Created DB CRUD interface.
This commit is contained in:
		
										
											Binary file not shown.
										
									
								
							@@ -3,9 +3,9 @@ package com.jdbernard.nlsongs.db
 | 
			
		||||
import java.sql.Connection
 | 
			
		||||
import java.sql.PreparedStatement
 | 
			
		||||
import java.sql.ResultSet
 | 
			
		||||
import java.text.SimpleDateFormat
 | 
			
		||||
import com.zaxxer.hikari.HikariDataSource
 | 
			
		||||
 | 
			
		||||
import groovy.sql.GroovyRowResult
 | 
			
		||||
import groovy.sql.Sql
 | 
			
		||||
import groovy.transform.CompileStatic
 | 
			
		||||
 | 
			
		||||
@@ -24,39 +24,216 @@ public class NLSongsDB {
 | 
			
		||||
 | 
			
		||||
    public void shutdown() { dataSource.shutdown() }
 | 
			
		||||
 | 
			
		||||
    // ### Services
 | 
			
		||||
    public Service findService(int id) {
 | 
			
		||||
        GroovyRowResult row = sql.firstRow(
 | 
			
		||||
            "SELECT * FROM services WHERE id = ?", [id] as List<Object>)
 | 
			
		||||
        if (row) return (Service) recordToModel(row, Service)
 | 
			
		||||
        else return null }
 | 
			
		||||
    /// ### Common
 | 
			
		||||
    public def save(def model) {
 | 
			
		||||
        if (model.id > 0) return update(model)
 | 
			
		||||
        else {
 | 
			
		||||
            if (create(model) > 0) return model
 | 
			
		||||
            else return null } }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /// ### Services
 | 
			
		||||
    public Service findService(int id) {
 | 
			
		||||
        def row = sql.firstRow("SELECT * FROM services WHERE id = ?", [id])
 | 
			
		||||
        recordToModel(row, Service) }
 | 
			
		||||
 | 
			
		||||
    public List<Service> findAllServices() {
 | 
			
		||||
        return sql.rows("SELECT * FROM services").
 | 
			
		||||
            collect { recordToModel(it, Service) } }
 | 
			
		||||
 | 
			
		||||
    public List<Service> findServicesForSongId(int songId) {
 | 
			
		||||
        return sql.rows("SELECT svc.* " +
 | 
			
		||||
                        "FROM services svc JOIN " +
 | 
			
		||||
                             "performances prf ON " +
 | 
			
		||||
                                "svc.id = prf.service_id " +
 | 
			
		||||
                        "WHERE prf.song_id = ?", [songId]).
 | 
			
		||||
            collect { recordToModel(it, Service) } }
 | 
			
		||||
 | 
			
		||||
    public List<Service> findServicesAfter(Date d) {
 | 
			
		||||
        def sdf = new SimpleDateFormat("YYYY-MM-dd")
 | 
			
		||||
        return sql.rows('SELECT * FROM services WHERE "date" > ?',
 | 
			
		||||
            [sdf.format(d)]).  collect { recordToModel(it, Service) } }
 | 
			
		||||
 | 
			
		||||
    public List<Service> findServicesBefore(Date d) {
 | 
			
		||||
        def sdf = new SimpleDateFormat("YYYY-MM-dd")
 | 
			
		||||
        return sql.rows('SELECT * FROM services WHERE "date" < ?',
 | 
			
		||||
            [sdf.format(d)]).collect { recordToModel(it, Service) } }
 | 
			
		||||
 | 
			
		||||
    public List<Service> findServicesBetween(Date b, Date e) {
 | 
			
		||||
        def sdf = new SimpleDateFormat("YYYY-MM-dd")
 | 
			
		||||
        return sql.rows('SELECT * FROM services WHERE "date" BETWEEN ? AND ?',
 | 
			
		||||
            [sdf.format(b),sdf.format(e)]).
 | 
			
		||||
            collect { recordToModel(it, Service) } }
 | 
			
		||||
 | 
			
		||||
    public Service create(Service service) {
 | 
			
		||||
        def sdf = new SimpleDateFormat("YYYY-MM-dd")
 | 
			
		||||
        int newId = sql.executeInsert(
 | 
			
		||||
            'INSERT INTO services ("date", service_type) VALUES (?, ?)',
 | 
			
		||||
            [sdf.format(service.date), service.serviceType])[0][0]
 | 
			
		||||
 | 
			
		||||
        service.id = newId
 | 
			
		||||
        return service }
 | 
			
		||||
 | 
			
		||||
    public int update(Service service) {
 | 
			
		||||
        def sdf = new SimpleDateFormat("YYYY-MM-dd")
 | 
			
		||||
        return sql.executeUpdate(
 | 
			
		||||
            'UPDATE services SET "date" = ?, service_type = ? WHERE id = ?',
 | 
			
		||||
            [sdf.format(service.date), service.serviceType, service.id] ) }
 | 
			
		||||
 | 
			
		||||
    /// ### Songs
 | 
			
		||||
    public Song findSong(int id) {
 | 
			
		||||
        def row = sql.firstRow("SELECT * FROM songs WHERE id = ?", [id])
 | 
			
		||||
        return recordToModel(row, Song) }
 | 
			
		||||
 | 
			
		||||
    public List<Song> findAllSongs() {
 | 
			
		||||
        return sql.rows("SELECT * FROM songs").
 | 
			
		||||
            collect { recordToModel(it, Song) } }
 | 
			
		||||
 | 
			
		||||
    public List<Song> findSongsForServiceId(int serviceId) {
 | 
			
		||||
        return sql.rows("SELECT sng.* " +
 | 
			
		||||
                        "FROM songs sng JOIN " +
 | 
			
		||||
                             "performances prf ON " +
 | 
			
		||||
                                "sng.id = prf.song_id " +
 | 
			
		||||
                        "WHERE prf.service_id = ?", [serviceId]).
 | 
			
		||||
            collect { recordToModel(it, Song) } }
 | 
			
		||||
 | 
			
		||||
    public List<Song> findSongsByName(String name) {
 | 
			
		||||
        return sql.rows("SELECT * FROM songs WHERE name = ?", [name]).
 | 
			
		||||
            collect { recordToModel(it, Song) } }
 | 
			
		||||
 | 
			
		||||
    public List<Song> findSongsLikeName(String name) {
 | 
			
		||||
        return sql.rows("SELECT * FROM songs WHERE name LIKE ?", ["%$name%"]).
 | 
			
		||||
            collect { recordToModel(it, Song) } }
 | 
			
		||||
 | 
			
		||||
    public List<Song> findSongsByArtist(String artist) {
 | 
			
		||||
        return sql.rows("SELECT * FROM songs WHERE artists LIKE ?", ["%$artist%"]).
 | 
			
		||||
            collect { recordToModel(it, Song) } }
 | 
			
		||||
 | 
			
		||||
    public List<Song> findSongsByNameAndArtist(String name, String artist) {
 | 
			
		||||
        return sql.rows("SELECT * FROM songs WHERE name = ? AND artists LIKE ?",
 | 
			
		||||
            [name,"%$artist%"]).collect { recordToModel(it, Song) } }
 | 
			
		||||
 | 
			
		||||
    public Song create(Song song) {
 | 
			
		||||
        int newId = sql.executeInsert(
 | 
			
		||||
            "INSERT INTO songs (name, artists) VALUES (?, ?)",
 | 
			
		||||
            [song.name, wrapArtists(song.artists)])[0][0]
 | 
			
		||||
 | 
			
		||||
        song.id = newId
 | 
			
		||||
        return song }
 | 
			
		||||
 | 
			
		||||
    public int update(Song song) {
 | 
			
		||||
        return sql.executeUpdate(
 | 
			
		||||
            "UPDATE songs SET name = ?, artists = ? WHERE id = ?",
 | 
			
		||||
            [song.name, wrapArtists(song.artists), song.id] ) }
 | 
			
		||||
 | 
			
		||||
    /// ### Performances
 | 
			
		||||
    public Performance findPerformance(int serviceId, int songId) {
 | 
			
		||||
        def perf = sql.firstRow(
 | 
			
		||||
            "SELECT * FROM performances WHERE service_id = ? AND song_id = ?",
 | 
			
		||||
            [serviceId, songId])
 | 
			
		||||
        return recordToModel(perf, Performance) }
 | 
			
		||||
 | 
			
		||||
    public List<Performance> findPerformancesForServiceId(int serviceId) {
 | 
			
		||||
        return sql.rows("SELECT * FROM performances WHERE service_id = ?",
 | 
			
		||||
            [serviceId]).collect { recordToModel(it, Performance) } }
 | 
			
		||||
 | 
			
		||||
    public List<Performance> findPerformancesForSongId(int songId) {
 | 
			
		||||
        return sql.rows("SELECT * FROM performances WHERE song_id = ?",
 | 
			
		||||
            [songId]).collect { recordToModel(it, Performance) } }
 | 
			
		||||
 | 
			
		||||
    public Performance create(Performance perf) {
 | 
			
		||||
        // TODO: handle constraint violation (same service and song ids)
 | 
			
		||||
        sql.executeInsert(
 | 
			
		||||
            "INSERT INTO performances (service_id, song_id, pianist, " +
 | 
			
		||||
            "organist, bassist, drummer, guitarist, leader) VALUES " +
 | 
			
		||||
            "(?, ?, ?, ?, ?, ?, ?, ?)", [perf.serviceId, perf.songId,
 | 
			
		||||
            perf.pianist, perf.organist, perf.bassist, perf.drummer,
 | 
			
		||||
            perf.guitarist, perf.leader])
 | 
			
		||||
        return perf }
 | 
			
		||||
 | 
			
		||||
    public int update(Performance perf) {
 | 
			
		||||
        // TODO: handle constraint violation (same service and song ids)
 | 
			
		||||
        return sql.executeUpdate(
 | 
			
		||||
            "UPDATE performances SET pianist = ?, organist = ?, " +
 | 
			
		||||
            "bassist = ?, drummer = ?, guitarist = ?, leader = ? " +
 | 
			
		||||
            "WHERE service_id = ? AND song_id = ?",
 | 
			
		||||
            [perf.pianist, perf.organist, perf.bassist, perf.drummer,
 | 
			
		||||
            perf.guitarist, perf.leader, perf.serviceId, perf.songId]) }
 | 
			
		||||
 | 
			
		||||
    public int delete(Performance perf) {
 | 
			
		||||
        sql.execute(
 | 
			
		||||
            "DELETE FROM performances WHERE service_id = ? AND song_id = ?")
 | 
			
		||||
        return sql.getUpdateCount() }
 | 
			
		||||
 | 
			
		||||
    /// ### API Keys
 | 
			
		||||
    public ApiKey findKey(String key) {
 | 
			
		||||
        def row = sql.firstRow("SELECT * FROM api_keys WHERE key = ?", [key])
 | 
			
		||||
        return recordToModel(row, ApiKey) }
 | 
			
		||||
 | 
			
		||||
    public ApiKey save(ApiKey apiKey) {
 | 
			
		||||
        if (findKey(apiKey.key)) {
 | 
			
		||||
            update(apiKey)
 | 
			
		||||
            return apiKey }
 | 
			
		||||
        else return create(apiKey) }
 | 
			
		||||
 | 
			
		||||
    public ApiKey create(ApiKey apiKey) {
 | 
			
		||||
        sql.executeInsert(
 | 
			
		||||
            "INSERT INTO api_keys (key, description) VALUES (?, ?)",
 | 
			
		||||
            [apiKey.key, apiKey.description] )
 | 
			
		||||
 | 
			
		||||
        return apiKey }
 | 
			
		||||
 | 
			
		||||
    public int update(ApiKey apiKey) {
 | 
			
		||||
        return sql.executeUpdate(
 | 
			
		||||
            "UPDATE api_keys SET description = ? WHERE key = ?",
 | 
			
		||||
            [apiKey.description, apiKey.key]) }
 | 
			
		||||
 | 
			
		||||
    /// ### User management
 | 
			
		||||
    // TODO
 | 
			
		||||
 | 
			
		||||
    /// ### Utility functions
 | 
			
		||||
    static def recordToModel(def record, Class clazz) {
 | 
			
		||||
        if (record == null) return null
 | 
			
		||||
 | 
			
		||||
    // #### Utility functions
 | 
			
		||||
    static def recordToModel(def row, Class clazz) {
 | 
			
		||||
        def model = clazz.newInstance()
 | 
			
		||||
 | 
			
		||||
        row.each { recordKey, v ->
 | 
			
		||||
        record.each { recordKey, v ->
 | 
			
		||||
            def pts = recordKey.split('_')
 | 
			
		||||
            def modelKey = pts.length == 1 ? pts[0] :
 | 
			
		||||
                pts[0] + pts[1..-1].collect { it.capitalize() }.join()
 | 
			
		||||
 | 
			
		||||
            // Hacky, there should be a better way
 | 
			
		||||
            if (recordKey == "artists") v = unwrapArtists(v);
 | 
			
		||||
 | 
			
		||||
            model[modelKey] = v }
 | 
			
		||||
        return model }
 | 
			
		||||
 | 
			
		||||
    static def modelToRecord(def model) {
 | 
			
		||||
        if (model == null) return null
 | 
			
		||||
 | 
			
		||||
        def record = [:]
 | 
			
		||||
 | 
			
		||||
        model.properties.each { modelKey, v ->
 | 
			
		||||
            if (modelKey == "class") return
 | 
			
		||||
            def recordKey = modelKey.
 | 
			
		||||
                replaceAll(/(\p{javaUpperCase})/, /_$1/).toLowerCase()
 | 
			
		||||
 | 
			
		||||
            // Hack
 | 
			
		||||
            if (modelKey == "artists") v = wrapArtists(v)
 | 
			
		||||
 | 
			
		||||
            record[recordKey] = v }
 | 
			
		||||
        return record }
 | 
			
		||||
 | 
			
		||||
    public static List<String> unwrapArtists(String artists) {
 | 
			
		||||
        return artists.split(';') as List<String> }
 | 
			
		||||
 | 
			
		||||
    public static String wrapArtists(List<String> artists) {
 | 
			
		||||
        return artists.join(':') }
 | 
			
		||||
    /*
 | 
			
		||||
    static Object recordToModel(GroovyRowResult row, Class clazz) {
 | 
			
		||||
        Object model = clazz.newInstance()
 | 
			
		||||
 | 
			
		||||
        row.each { recordKey, v -> 
 | 
			
		||||
        row.each { recordKey, v ->
 | 
			
		||||
            String[] pts = ((String) recordKey).split('_')
 | 
			
		||||
            String modelKey = pts[0] +
 | 
			
		||||
                pts[1..-1].collect { it.capitalize() }.join()
 | 
			
		||||
 
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -12,31 +12,26 @@ import com.zaxxer.hikari.HikariDataSource
 | 
			
		||||
public final class NLSongsContextListener implements ServletContextListener {
 | 
			
		||||
 | 
			
		||||
    public void contextInitialized(ServletContextEvent event) {
 | 
			
		||||
        context = event.servletContext
 | 
			
		||||
        def context = event.servletContext
 | 
			
		||||
 | 
			
		||||
        // Create the pooled data source
 | 
			
		||||
        HikariConfig hcfg = new HikariConfig()
 | 
			
		||||
        hcfg.username = 'TODO'
 | 
			
		||||
        hcfg.password = 'TODO'
 | 
			
		||||
        hcfg.dataSourceClassName = 'TODO'
 | 
			
		||||
        hcfg.addDataSourceProperty('cachePrepStmts', 'true')
 | 
			
		||||
        hcfg.addDataSourceProperty('prepStmtCacheSize', '250')
 | 
			
		||||
        hcfg.addDataSourceProperty('prepStmtCacheSqlLimit', '2048')
 | 
			
		||||
        hcfg.addDataSourceProperty('useServerPrepStmts', 'true')
 | 
			
		||||
        HikariConfig hcfg = new HikariConfig(
 | 
			
		||||
            context.getInitParameter("context.config.file"))
 | 
			
		||||
 | 
			
		||||
        HikariDataSource hds = new HikariDataSource(hcfg)
 | 
			
		||||
 | 
			
		||||
        // Create the NLSonsDB instance.
 | 
			
		||||
        NLSongsDB songsDB = new NLSongsDB(hds)
 | 
			
		||||
 | 
			
		||||
        context.setAttribute('songsDB', songsDB) }
 | 
			
		||||
        context.setAttribute('songsDB', songsDB)
 | 
			
		||||
        NLSongsContext.songsDB = songsDB }
 | 
			
		||||
 | 
			
		||||
    public void contextDestroyed(ServletContextEvent event) {
 | 
			
		||||
        context = event.servletContext
 | 
			
		||||
        def context = event.servletContext
 | 
			
		||||
 | 
			
		||||
        // Shutdown the Songs DB instance (it will shut down the data source).
 | 
			
		||||
        NLSongsDB songsDB = context.getAttribute('songsDB')
 | 
			
		||||
        songsDB.shutdown()
 | 
			
		||||
        if (songsDB) songsDB.shutdown()
 | 
			
		||||
        
 | 
			
		||||
        context.removeAttribute('songsDB') }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user