All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gorm.tools.idgen.JdbcIdGenerator.groovy Maven / Gradle / Ivy

There is a newer version: 7.3.74
Show newest version
/*
* Copyright 2019 Yak.Works - Licensed under the Apache License, Version 2.0 (the "License")
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
package gorm.tools.idgen

import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.dao.EmptyResultDataAccessException
import org.springframework.jdbc.BadSqlGrammarException
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.transaction.annotation.Propagation

import grails.gorm.transactions.Transactional
import yakworks.commons.lang.Validate
import yakworks.gorm.config.IdGeneratorConfig

//import grails.gorm.transactions.Transactional
/**
 * A Jdbc implementation of the IdGenerator. Will query a central table for new ids.
 * defaults to the following but can be set accordingly:
 *  table - "NEWOBJECTID"
 *  keyColumn - "KeyName"
 *  idColumn - "NextId"
 *  seedValue - "1000" this is the starting ID fi the row does not exist and is created by this object.
 *
 *  setCreateIdRow = false to not create the row automatically if it does not exist
 *
 * @author Joshua Burnett (@basejump)
 * @since 1.0
 */
@Slf4j
@CompileStatic
class JdbcIdGenerator implements IdGenerator {
    @Autowired JdbcTemplate jdbcTemplate
    @Autowired IdGeneratorConfig idGenConfig

    //if true then will not automatically create a row for the key and will throw an error if row does not exist
    boolean requireKeyRow = false

    String table = "NewObjectId"
    String keyColumn = "KeyName"
    String idColumn = "NextId"

    long getNextId(String keyName) {
        throw new IllegalAccessException("Use the pooledIdGenerator with this backing it for fetching single IDs")
    }

    @SuppressWarnings('SynchronizedMethod')
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    synchronized long getNextId(String keyName, long increment) {
        return updateIncrement(keyName, increment)
    }

    // Transactional!  The annotation only works on public methods, so this method should only be called by transactional
    // methods.
    private long updateIncrement(String name, long increment) {
        //println "updateIncrement $name $increment"
        Validate.notEmpty(idColumn, 'idColumn')
        Validate.notEmpty(keyColumn, 'keyColumn')
        Validate.notEmpty(table, 'table')
        Validate.notEmpty(name, 'name argument')

        String query = "Select " + idColumn + " from " + table + " where " + keyColumn + " ='" + name + "'"
        long oid = 0
        try {
            oid = jdbcTemplate.queryForObject(query, Long)
        } catch (EmptyResultDataAccessException erdax) {
            if (requireKeyRow) {
                throw erdax
            } else {
                oid = createRow(table, keyColumn, idColumn, name)
            }
        } catch (BadSqlGrammarException bge) {
            log.info("Looks like the idgen table is not found. This will do a automatically setup for the table for the JdbcIdGenerator "+
                "suggested to set it up properly with something like db-migration"+
                "or another tools as no indexes or optimization are taken into account")
            createTable(table, keyColumn, idColumn)
            oid = createRow(table, keyColumn, idColumn, name)
            //throw new IllegalArgumentException("The key '" + name + "' does not exist in the object ID table.");
        }

        if (oid > 0) { //found it
            if (oid < idGenConfig.startValue) {
                oid = idGenConfig.startValue
            }
            long newValue = oid + increment
            jdbcTemplate.update("Update " + table + " set " + idColumn + " = " + newValue + " where " + keyColumn
                + " ='" + name + "'")
        }
        if (log.isDebugEnabled()) {
            log.debug("Returning id " + oid + " for key '" + name + "'")
        }
        return oid
    }

    private long createRow(String table, String keyColumn, String idColumn, String name) {
        Long maxId = idGenConfig.startValue
        String[] tableInfo = name.split("\\.")
        if (tableInfo.length > 1) {
            try {
                String maxSql = "select max(" + tableInfo[1] + ") from " + tableInfo[0]
                Long currentMax = jdbcTemplate.queryForObject(maxSql, Long)
                if (currentMax != null) maxId = currentMax + 1
            } catch (EmptyResultDataAccessException ex) {
                log.debug("No rows yet so just leave it as seed. TableInfo=${tableInfo}")
                //now rows yet so just leave it as  seed
            }
        }
        jdbcTemplate.update("insert into " + table + " (" + keyColumn + "," + idColumn + ") " + "Values('" + name + "'," + maxId + ")")
        return maxId
    }

    private void createTable(String table, String keyColumn, String idColumn) {
        String query = """
            create table $table
                (
                    $keyColumn varchar(255) not null,
                    $idColumn bigint not null,
                    CONSTRAINT PK_$table PRIMARY KEY ($keyColumn)
                )
                """
        //println "creating with $query"
        jdbcTemplate.execute(query)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy