Determine Data Type - grails

I have this code in my controller:
def cols = grailsApplication.getDomainClass('com.archie.Build').persistentProperties.collect {it.name}
The code above will allow me to list all the property names I have in Build class. Now, I would like to include also the properties data type, ie. boolean, String etc...
Somewhat like the output is:
[floorType:String, floorWidth:Float, ......]
Maybe not exactly like that, or maybe similar, but as long as I can return their data type. Can someone help? Thank you.

Each entry in persistentProperties is a GrailsDomainClassProperty, and this provides access to the type of the property as a Class object:
def props = [:]
grailsApplication.getDomainClass('com.archie.Build'
).persistentProperties.each {
props[it.name] = it.type.name
}
Or just pass the persistentProperties array itself through to the GSP, then extract .name and .type there.
You may also wish to consider using constrainedProperties instead of/in addition to the persistentProperties. The constrainedProperties map lists only those properties that are mentioned in the domain class constraints block, but the iterator over this map is guaranteed to return the properties in the order they are listed in the constraints. This is how the default scaffolding operates, as I'm not aware of any way to control the order of the persistentProperties array.

Related

How to access map keys through index? Dart

dartques = {'Color':[], 'Fruits':[], 'Hobbies':[]};
How to access the values using index in map?
I need to access only key or value using index.
Just like we do in list
=>list[1]
you can get it like this
var element = dartques.values.elementAt(0);
also for Dart 2.7+ you can write extension function
extension GetByKeyIndex on Map {
elementAt(int index) => this.values.elementAt(index);
}
var element = dartques.elementAt(1);
For accessing the values by index, there are two approaches:
Get Key by index and value using the key:
final key = dartques.keys.elementAt(index);
final value = dartques[key];
Get value by index:
final value = dartques.values.elementAt(index);
You may choose the approach based on how and what data are stored on the map.
For example if your map consists of data in which there are duplicate values, I would recommend using the first approach as it allows you to get key at the index first and then the value so you can know if the value is the wanted one or not.
But if you do not care about duplication and only want to find a value based on Index then you should use the second approach, as it gives you the value directly.
Note: As per this Answer By Genchi Genbutsu, you can also use Extension methods for your convenience.
Important:
Since the default implementation for Map in dart is LinkedHashmap you are in great luck. Otherwise Generic Map is known for not maintaining order in many programming languages.
If this was asked for any other language for which the default was HashMap, it might have been impossible to answer.
You can convert it to two lists using keys and values methods:
var ques = {'Color':['a'], 'Fruits':['b'], 'Hobbies':['c']};
List keys = ques.keys.toList();
List values = ques.values.toList();
print (keys);
print (values);
The output:
[Color, Fruits, Hobbies]
[[a], [b], [c]]
So you can access it normally by using keys[0], for example.

Is it possible to refresh a property in Grails?

In order to refresh a domain object i.e to re-read the data from database we do refresh().
def b = Book.get(1)
…
b.refresh()
I am wondering whether we can refresh a property of the domain.
Suppose i have bound params to Book object and suppose i want to unbind the author property from the book object then is it possible to achieve that?
Let's consider the Book is defined as
class Book {
String title
String author
String category
}
Suppose I do bindData(bookInstance, params). This will bind to all properties. I want to unbind the author after bindData. Is this possible?
It sounds like you just want to exclude binding a particular property.
bindData(bookInstance, params, [exclude: 'author'])
will bind all of the Book properties except for those listed.
You can conversely use include to explicitly list which properties to bind from params.
bindData(bookInstance, params, [include: 'title', 'category'])
I solved this by using bookInstance.author = bookInstance.getPersistentValue('author').

How to dynamically add a property / field to a domain class in Grails?

For a project I'm currently working on I need to dynamically add properties to a domain class and persist them later in the database. In general, I need a key/value store attached to a "normal" domain class. Sadly I cannot use a NoSQL database (e.g. Redis).
My approach would be to handle the additional properties on a save() by identifying them within afterInsert or afterUpdate and writing them to another table - I would prefer not to use a map property within the domain class but an additional "Field" table (to better support searches).
I tried to add properties using the metaClass approach:
person.metaClass.middlename = "Biterius"
assert person.middlename == "Biterius" // OK
This works and I can identify the additional properties in the afterInsert/afterUpdate methods but it seems that I cannot change the value thereafter - i.e., the following does not work:
person.middlename = "Tiberius"
assert person.middlename == "Tiberius" // FAIL
Then I tried an Expando approach by extending the Person class by the Expando class (directly ("Person extends Expando") and via an abstract intermediate class ("Person extends AbstractPerson" and "AbstractPerson extends Expando")).
def person = new Person()
assert person in Person // OK
assert person in AbstractPerson // OK
assert person in Expando // OK
Both variants did not work - I could assign values to arbitrary "properties" but the values were not stored!
person.mynewproperty = "Tiberius" // no MissingPropertyException is thrown
println person.mynewproperty // returns null
So how can I add properties to a domain class programmatically during runtime, change them and retrieve them during afterInsert or afterUpdate in order to "manually" store them in a "Fields" table?
Or am I doing something completely wrong? Are there other / simpler ways to do this?
What about turning your DB into a "NoSQL" one?
In one of my projects, I just used a String-property to store a map as JSON-Object.
For Groovy it's not a big problem to convert between a map and a JSON-Object. And since you can access a map just like an object with properties, I found this solution very convenient.
Only drawback: you have to plan the size of your String-property in advance...
Update: sorry, just read that you want to support searches...
what about
class Person {
...
static hasMany = [extProperties:KeyValue]
...
def invokeMethod(String name, args) {
if (name.startsWith('get')) {
//an unknown properties's getter is called
}
//add same for setter
}
}
class KeyValue {
String key
String value
}
I guess such a schema would give you all freedom you need. Even without the hasMany, you can make use of invokeMethod to handle your external tables...
The getter and setter can save your values in a transient string propertie (static transients = ['myTransientProperty']). This property should be available in the afterInsert / `afterUpdate´ events.
Why don't you just create a map of strings on the domain object and store your extra data there manually? Unless you're storing complex data you should be able to cast anything you need to/from a string.

Language-specific value in grails inList constraint

Users of my application have the possibility of choosing some values from list. The values for that list are in simple domain class, Foo, which looks like that:
class Foo{
String name
static mapping = {
id name: 'name', generator: 'assigned'
version: false
}
}
Foo looks the same for every language my app uses. In another class I have a constraint saying that Bar must be in list of Foo. Sometimes user doesn't know what to choose, so he may choose something like "I'm not sure" (so this option should be in list to to meet the inList constraint). Thing is, "I'm not sure" is written differently in different languages. How can I append this value based on current messages to inList constraint?
In your controller you could do:
def theList = foo.list().name // Get any array of strings.
// If you actually need > 1 field then you probably need to
// put the g.message below in a map
theList << g.message(code:"im.not.sure")
I don't believe inList constraint will help you here - it's designed for a simpler use case than yours.
I'd add a method to the class getLanguages() that handles this, and then since you seem to be interested in validation, write a custom validator to make sure right values are saved.

Lazy fetching of objects using FindAllBy , for the first time

When I use criteria queries, the result contains array list of lazy initialized objects. that is, the list has values with handler org.codehaus.groovy.grails.orm.hibernate.proxy.GroovyAwareJavassistLazyInitializer.
This prevent me from doing any array operation (minus, remove etc) in it. When I use, GORM methods, I get array list of actual object types. How can I get the actual objects in criteria query?
The code is listed below.
availableTypes = Type.withCriteria() {
'in'("roleFrom", from)
'in'("roleTo", to)
}
availableTypes (an array list) has one value , but not actual object but value with a handler of GroovyAwareJavassistLazyInitializer
availableTypes (an array list) has values with type Type
availableTypes = Type.findByRoleFrom(from)
---------- Update ----------
I did further troubleshooting, and this is what I found. Probably the above description might be misleading, but I kept it in case it helps.
When using findAllBy for the first time, I get proxy objects rather than the actual instance. Then, I invoke the method through an ajax call, the actual instance is loaded (anything to do with cache loading??). When I refresh the page, it again loads the proxy
def typeFrom = Type.findAllByParty(partyFrom)
there is another use of findAllBy in the same method, which always returns actual instances.
def relFrom = Relation.findAllByParty(partyFrom)
When compared the two classes, the attribute 'party' of class Roles is part of a 1-m relation. like
class Role {
RoleType roleType
LocalDate validFrom
LocalDate validTo
static belongsTo = [party : Party ]
...
}
I know if I do statement like Party.findAll(), the role instances would be proxy till they access. But, when using gorm directly on the class (Role), why I am getting the proxy objects ???
thanks for the help.
thanks.
Turns out are a couple of possible solutions which I came across but didn't try, such as
Overloading the equals method so that the proxy and the domain
object use a primary key instead of the hashCode for equality
Using a join query so that you get actual instances back and not proxies
GrailsHibernateUtil.unwrapProxy(o)
HibernateProxyHelper.getClassWithoutInitializingProxy(object)
One solution that worked for me was to specify lazy loading to be false in the domain object mapping.
History of this problem seems to be discussed here: GRAILS-4614
See also: eager load

Resources