groovy script having access to domain classes - grails

I would like to have a groovy script that can access my domain classes and extract all properties from there.
I have not written any groovy-scripts so far within my Grails application.
How do I do this?
I am thinking of something like
run-script <scriptname>
In the script I would like to
For all Domain classes
For all Fields
println (<database-table-name>.<database-field-name>)
What would be the easiest approach to achieve this.

Below I'm including a script code using which you can list down all the domain classes with their properties. This script generates a Map that contains the db mapping for domain and its properties. If you have a different requirement, you can achieve that using the same approach.
import org.codehaus.groovy.grails.commons.DefaultGrailsDomainClass
import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler
import org.codehaus.groovy.grails.orm.hibernate.persister.entity.GroovyAwareSingleTableEntityPersister as GASTEP
import org.hibernate.SessionFactory
//Include script dependencies required for task dependencies
includeTargets << grailsScript("Bootstrap")
target(grailsDomianMappings: "List down field details for all grails domain classes") {
//Task dependencies required for initialization of app. eg: initialization of sessionFactory bean
depends(compile, bootstrap)
System.out.println("Running script...")
//Fetch session factory from application context
SessionFactory sessionFactory = appCtx.getBean("sessionFactory")
//Fetch all domain classes
def domains = grailsApp.getArtefacts(DomainClassArtefactHandler.TYPE)
GASTEP persister
List<String> propertyMappings = []
Map<String, List<String>> mappings = [:]
//Iterate over domain classes
for (DefaultGrailsDomainClass domainClass in domains) {
//Get class meta data
persister = sessionFactory.getClassMetadata(domainClass.clazz) as GASTEP
propertyMappings = []
//fetch table name mapping
String mappedTable = persister.tableName
//fetch all properties for domain
String[] propertyNames = persister.propertyNames
propertyNames += persister.identifierPropertyName
//fetch column name mappings for properties
propertyNames.each {
propertyMappings += persister.getPropertyColumnNames(it).first()
}
mappings.put(mappedTable, propertyMappings)
}
//Print data
mappings.each { String table, List<String> properties ->
properties.each { String property ->
System.out.println("${table}.${property}")
}
System.out.println("++++++++++++++++++++++++++++++++++++++++++++++")
}
}
setDefaultTarget(grailsDomianMappings)

Related

How to generate sql file from Liquibase without DATABASECHANGELOG inserts?

I have the following problem : I need to produce migration file for a database in production. Currently I'm using ant and following ant task :
<liquibase:updateDatabase changeLogFile=db.changelog-master.xml" databaseRef="oracle-database" outputFile="out_ora.sql" />
But my file includes insert statements for DATABASECHANGELOG table. How can I produce output file without this statements ? (I wouldn't like to delete this statements manually or by some script later).
You can use this extension: https://github.com/liquibase/liquibase-nochangelogupdate
Just add the jar to your classpath and liquibase will not output any databasechangelog SQL
If you want to filter the insert/update from ChangeSets irrespective of Liquibase Insert/update statements retaining only the Create, Alter scripts.
Define a property with list of classes to be excluded
sqlgenerator.exclude=liquibase.statement.core.InsertOrUpdateStatement,liquibase.statement.core.InsertStatement,liquibase.statement.core.UpdateStatement,liquibase.statement.core.GetNextChangeSetSequenceValueStatement,liquibase.statement.core.MarkChangeSetRanStatement,liquibase.statement.core.RemoveChangeSetRanStatusStatement,liquibase.statement.core.UpdateChangeSetChecksumStatement
Implement a SQL Generator class that filters all the SQL statements falls into the class category listed above.
Spring injects the property into the class. Be sure to create the class under the package "liquibase.sqlgenerator.ext".
#Component
public class FilteredSQLGenerator extends AbstractSqlGenerator<AbstractSqlStatement> {
private static final Logger LOGGER = Logger.getLogger(FilteredSQLGenerator.class);
private static String[] excludeArr = new String[0];
#Value("${sqlgenerator.exclude}")
private String exclude;
#PostConstruct
public void init() {
LOGGER.debug(" Exclude List set to : " + exclude);
if (StringUtils.isNotBlank(exclude)) {
excludeArr = StringUtils.split(exclude, ',');
}
}
#Override
public ValidationErrors validate(AbstractSqlStatement statement, Database database, SqlGeneratorChain sqlGeneratorChain) {
return sqlGeneratorChain.validate(statement, database);
}
#Override
public int getPriority() {
return 1000;
}
#Override
public Sql[] generateSql(AbstractSqlStatement statement, Database database, SqlGeneratorChain sqlGeneratorChain) {
String clazzName = statement.getClass().getName();
for (String exclude : excludeArr) {
if (exclude.equals(clazzName)) {
return new Sql[0];
}
}
return sqlGeneratorChain.generateSql(statement, database);
}
}

How can Grails domain object members have default names based on a computed value?

This is what I'm trying to do:
class Test {
String name
static mapping = {
name defaultValue: "test_${Test.count()}"
}
}
So when a new "test" object is created the name is test_1, test_2, test_3 etc. depending on how many test objects already exist. The above does not work because "test.count was used outside of a Grails application"
You could initialize the property instead of specifying the value via the mapping closure.
class Test {
String name = "test_${Test.count()}"
}
or
class Test {
String name = initName()
private static String initName() {
def count = Test.count()
return "test_" + count
}
}

Grails GORM query multiple cascading one to many relationship levels

In Grails I have these 4 domain classes:
package com.whatever.ts4
class A_class {
String aName
static hasMany = [b_class: B_class]
}
package com.whatever.ts4
class B_class {
String bName
A_class a_class
static hasMany = [c_class: C_class]
static belongsTo = [A_class]
}
package com.whatever.ts4
class C_class {
String cName
B_class b_class
static hasMany = [d_class: D_class]
static belongsTo = [B_class]
}
package com.whatever.ts4
class D_class {
Long rowNumber
String dataValue
C_class c_class
static belongsTo = [C_class]
}
Simple ER diagram:
A_class 1=>many B_class 1=>many C_class 1=>many D_class
I'm successfully populating them in BootStrap.groovy
Now,given an single A_class id, I need to obtain a set with these columns:
aName, bName, cName, rowNumber, dataValue
Can I do that using namedQueries?
I’ve tried putting this in the A_class domain class:
static namedQueries = {
myNamedQuery { aid ->
createAlias b_class,'b'
createAlias 'b.c_class','c'
createAlias 'c.d_class','d'
eq 'id',aid
}
}
I like the idea of a named query, because this result set will need to be returned for different A_class id’s. I can utilize a Service to prep the data and call it via the Controller which will render it as JSON (I digress). But, perhaps there is a Groovier way?
You don't need named query for this kind of action. You will obtain all information that you need just by taking it from A_class entity. For example:
def a_class_entity = A_class.get(id)
def b_names = a_class_entity.b_class.bName // set of all bNames
//<-- Not sure if flatten() works with spread collection fields, but it should -->
def c_names = a_class_entity.b_class.c_class.flatten().cName // collection of all cNames
def rowNumbers = a_class_entity.b_class.c_class.d_class.flatten().rowNumber // collection of all rowNumbers
def dataValues = a_class_entity.b_class.c_class.d_class.flatten().dataValue // collection of all dataValues

Grails: How do I create a static array

I'm new to grails. I need to create a static array which needs to be filled with certain items on startup. i.e
public class kingUtil {
public static String[] overlordArray = new String[]
static def init() {
overlordArray[0] = "foos"
overlordArray[1] = "roh"
overlordArray[2] = "dah"
}
}
So I put the utility groovy class in sources and I intended to call init() from bootstrap.
However, bootstrap cannot recognize the class name, like it can't reach it or something. What's the best way to establish implement application-scope statics in grails.

Grails domain class properties from properties file

In my grails application I want to read some values from properties file and set it to Grails Domain class static property at startup.
Example
Class A{
static myValues="1,2";
}
class B{
static myValues="2,3";
}
In the above example I have directly given the inputs..Instead of that I want to read it from one config.properties file which will have the following
A=1,2
B=2,3
Is it possible to do that in grails.Help me please.
If you put config.properties in grails-app/conf then it'll be in the classpath and this code in grails-app/conf/BootStrap.groovy will load the properties and set the values:
class BootStrap {
def init = { servletContext ->
def props = new Properties()
def cl = Thread.currentThread().contextClassLoader
props.load cl.getResourceAsStream('config.properties')
props.each { key, value ->
def clazz = Class.forName(key, true, cl)
clazz.myValues = value
}
}
}
Obviously you'll need to check that the properties file is available, that the classes, exist, etc.

Resources