grails database-migration - can it generate for 'not null with default'? - grails

What seems to me to be a common requirement for database changes, is the addition of a column that can't be null. One way round the problem of populating this column in some circumstances would be to define it as 'not null with default' in the DDL.
Grails doesn't appear to support 'NNWD' directly in constraints. I tested an idea that seems to work as an equivalent:
String name = default
...
name nullable:false
I wondered if dbm-gorm-diff changleog-n.xml would be able to detect this as being a null with a default. But it didn't. That's with version 1.2.2. I see that Liquibase supports this via its <addNotNullConstraint.
Are there any plans to introduce this support? Any suggestions as to how I might work round this, perhaps via a user-written script that makes use of dbm scripts.
Problem:
I tried using 1.3.2, but I get a MissingMethodException when running the script. The actual error line is:
groovy.lang.MissingMethodException: No signature of method: static grails.plugin.databasemigration.ScriptUtils.executeAndWrite() is applicable for argument types: (java.lang.String, java.lang.Boolean, DbmGormDiff$_run_closure1_closure2) values: [changelog-with-data.xml, false, DbmGormDiff$_run_closure1_closure2#2f673724]
Which I don't understand since the args seem to match the signature of the executeAndWrite() method in the plugin's code.
Regards, John

I have done some investigation on this topic and realised that the solution is more complicated, and trying to solve by adding a column using 'not null with default' is not the way to go. As I am planning to use Liquibase and Ant to update the database in test, uat and live environments, I refer to using xml files below.
If the table doesn't have any data, then you can add a column that is 'not null'. This seems to me to be an unlikely situation for a live database.
When the table contains data a new column must be defined as null. There is 3-step process, which requires manual updates to the xml file generated by the plugin:
define the new domain attribute as 'nullable:true', and generate the diff xml file.
update the xml file to add a new changeset using the < SQL> tag:
< sql>update [table] set [column]='dflt value' where [column] is null< /sql>
Now you can define the new column as not-null. Could use more raw sql, or look up Liquibase's < addNotNullConstraint>.
I don't think there is really a need for a default value for the column, since Grails will ensure that nulls don't get through from the browser. I say this since I haven't found a way to alter the definition of the added column so it has a default value.
John

If you're using 1.4.0 version of plugin it doesn't generate the changelog xmls for default values but you can edit the generated files to add the defaultValue & value attributes where it'll add the non-null columns without errors by updating the existing records with the value attribute.
Here's a small example for what it'd look like after modification:
<changeSet author="anybody (generated)" id="1467324956xxx-xx">
<addColumn tableName="table1">
<column name="col1" type="varchar(10)" defaultValue="value1" value="value1">
<constraints nullable="false"/>
</column>
</addColumn>
</changeSet>
More info you can find on liquibase docs http://www.liquibase.org/documentation/column.html
http://www.liquibase.org/documentation/changes/add_column.html

Related

Delete Bigtable row in Apache Beam 2.2.0

In Dataflow 1.x versions, we could use CloudBigtableIO.writeToTable(TABLE_ID) to create, update, and delete Bigtable rows. As long as a DoFn was configured to output a Mutation object, it could output either a Put or a Delete, and CloudBigtableIO.writeToTable() successfully created, updated, or deleted a row for the given RowID.
It seems that the new Beam 2.2.0 API uses BigtableIO.write() function, which works with KV<RowID, Iterable<Mutation>>, where the Iterable contains a set of row-level operations. I have found how to use that to work on Cell-level data, so it's OK to create new rows and create/delete columns, but how do we delete rows now, given an existing RowID?
Any help appreciated!
** Some further clarification:
From this document: https://cloud.google.com/bigtable/docs/dataflow-hbase I understand that changing the dependency ArtifactID from bigtable-hbase-dataflow to bigtable-hbase-beam should be compatible with Beam version 2.2.0 and the article suggests doing Bigtble writes (and hence Deletes) in the old way by using CloudBigtableIO.writeToTable(). However that requires imports from the com.google.cloud.bigtable.dataflow family of dependencies, which the Release Notes suggest is deprecated and shouldn't be used (and indeed it seems incompatible with the new Configuration classes/etc.)
** Further Update:
It looks like my pom.xml didn't refresh properly after the change from bigtable-hbase-dataflow to bigtable-hbase-beam ArtifactID. Once the project got updated, I am able to import from the
com.google.cloud.bigtable.beam.* branch, which seems to be working at least for the minimal test.
HOWEVER: It looks like now there are two different Mutation classes:
com.google.bigtable.v2.Mutation and
org.apache.hadoop.hbase.client.Mutation ?
And in order to get everything to work together, it has to be specified properly which Mutation is used for which operation?
Is there a better way to do this?
Unfortunately, Apache Beam 2.2.0 doesn't provide a native interface for deleting an entire row (including the row key) in Bigtable. The only full solution would be to continue using the CloudBigtableIO class as you already mentioned.
A different solution would be to just delete all the cells from the row. This way, you can fully move forward with using the BigtableIO class. However, this solution does NOT delete the row key itself, so the cost of storing the row key remains. If your application requires deleting many rows, this solution may not be ideal.
import com.google.bigtable.v2.Mutation
import com.google.bigtable.v2.Mutation.DeleteFromRow
// mutation to delete all cells from a row
Mutation.newBuilder().setDeleteFromRow(DeleteFromRow.getDefaultInstance()).build()
I would suggest that you should continue using CloudBigtableIO and bigtable-hbase-beam. It shouldn't be too different from CloudBigtableIO in bigtable-hbase-dataflow.
CloudBigtableIO uses the HBase org.apache.hadoop.hbase.client.Mutation and translates them into the Bigtable equivalent values under the covers

Access process i18n property files before compilation

I have a following situation: in some of my i18n property files there are properties containing a special word:
prop.example=specialword just for example
prop.test=just for test specialword
I want to have a possibility of having a property somewhere in my Config.groovy that would contain a specific value for this specialword so that if I specify:
specialword=Value of special word
in a Config.groovy then I want my i18n properties to be resolved like:
prop.example=Value of special word just for example
prop.test=just for test Value of special word
for that purpose, when building the project, I want to access property files in order to look for occurences of specialword and to replace them with value of specialwordvalue from Config.groovy.
Is that possible somehow? Perhaps, someone faced similar situation? I would really appreciate any help.
Thanks, Cheers
Instead of trying to change the way the properties are compiled, you would be better off passing the special value as an argument to your message code (as discussed in the comments to your question).
For instance:
<g:message code="my.key.code" args="[someVariableWithAValueFromConfig]" />
If your message code doesn't use the argument it will simply be ignored. This seems like the best approach to the problem you are trying to solve.

Easiest way to render an Integer without thousands separator when using Fields plugin 2.0.2

I'm building a very basic app using Grails 3.0.2.
I have a domain class called Unit which contains, among others, a field called season, whose type is Integer and represents a year.
I have used the command generate-views to generate the scaffolded views.
Once running the application, when an existing instance is shown, the season is displayed using "," as thousands separator, and I want to remove it.
What is the easiest way to override (only) the format of the season?
For testing purposes, I have modified the show.gsp of the Unit class in the following manner:
<f:with bean="unit">
<f:display />
<f:display property="season" />
</f:with>
The <f:display property="season" /> displays simply "1,975", but ignores the label.
I've tried to understand the documentation of the Fields plugin, but I do not achieve what I want so it's obvious that I do not understand it.
I have added _displayWidget.gsp under views/_fields/unit/season (I have also tried under views/unit/season), but the outcome is exactly the same than before, so I assume the plugin is not taking them into account.
<g:formatNumber groupingUsed="false" number="${value}" />
I am not familiar with the _displayWidget.gsp convention, but a simpler approach might be to override the display of the unit.season property by adding a _display.gsp under views/_fields/unit/season containing just the following:
${value}
Diego, you can format any given number using the taglib formatNumber:
https://grails.github.io/grails-doc/latest/ref/Tags/formatNumber.html
Use the param 'format' and check the DecimalFormat patterns to find the one that suits fine for you.
Hope it helps!
I was able to get this working in Grails 3.1.14 by creating views/_fields/myDomainClass/myFieldName/_displayWrapper.gsp and containing a single line of ${value}

How to get grails to assign Id to a legacy Java object

I have a java annotized domain object that I want to use in grails, this works fine, however all the generated templates use Id as the primary key. I tried to create a XxxConstraints.groovy file in the same package as my domain object, and added
mapping = {
id type:'assigned', name:<name of java field>, type: string
}
but that does not seem to work.
The error I get when trying to render the gsp is "class XYZ does not contain field id"
By the way I am using grails 2.1.0.
Thanks for the help in advance.
If you're talking about scaffolding views, they just have id field hardcoded, like: <g:hiddenField name="id" value="\${${propertyName}?.id}" /> (sample from edit.gsp).
Just modify your GSPs by hand to use your key field.
If it's more than one class and you don't want to generate all the views, you can install the templates into your project sources with grails install-templates and modify those to use your PK field. Maybe Groovy wrappers for Java classes will have ident() method, though not sure.
After looking at the doc, I'm in doubt if mapping{} DSL will work at all. Looks like only constraints section will work, and I believe you only need #Id annotation.

Can I compile 2 build templates in the same solution?

I've got a class library project set up to do template editing and wanted to drop in another copy and customize it. However I get
The type 'TfsBuild.Process' already contains a definition for '_contentLoaded'
and 22 more of the same with the other _ names.
Also Type 'TfsBuild.Process' already defines a member called 'Process' with the same parameter types C:\Projects\MSBuild.Tasks\TechnicalDebtTaskLib\BuildProcessTemplate\obj\Release\CodeMetric.g.cs 62 16 BuildProcessTemplate
i've tried hand editing different parts of the xaml to try to find what key might need to be more unique, but no luck.
How do I work on multiple build process templates in the same solution or copy a process template that makes it unique?
Summary:
<activity mc:ignorable="sap" x:class="Tfs2008Template.Process" ... xmlns:this="clr-namespace:Tfs2008Template">
two tags must be changed for example:
<activity mc:ignorable="sap" x:class="Tfs2008Template2.Process" ... xmlns:this="clr-namespace:Tfs2008Template2">
For whatever reasoning the two tags that are related and need to be in sync are usually at the beginning and end of a very long list of attributes.
Full Article on my blog

Resources