Sunday, June 24, 2012

Week 4 / Day 2: Last Chance for CouchDB

Never give up, never surrender.

I give CouchDB another chance. When you experience problems with open source software, you should at least create some bug entries in order to tell the developer that something does not work.

So I searched for the grom-couchdb bugtracker and stumbled upon the code base on git. Hm. It looks like some files are newer than what I've got... And there seems to be even a patch for the 2.0 problem!

https://github.com/coryhacking/gorm-couchdb
=> https://github.com/MalteJ/gorm-couchdb/tree/

but now that I've take a look at the issue tracker, I see that it would be too much work to do in order to get it up and running: this issue explains inderectly, that the plugin needs a js-view in order to work and it is not generated if you do a generate-all on a no-couch domain.

It seems that you may use the plugin if you already have a better knoledge of couchDB, but for me, that's it. No couchDB for my grails project!

Friday, June 15, 2012

Week 4 / Day 1 CouchDB

Today I did some experiments with CouchDB. The daabase is easy to install, has a clean web interface and makes jsut a good expression.

So I searched for a Grails plugin and found a 2 years old one: Grom-CouchDB.

Installing the plugin wasn't easy. I first tried my Grails 2.0.x installation - it easily picks up the plugin, but when I try to run it, I get a strange compilation error:

user@ubuntu:~/grails/couch3$ grails run-app
| Compiling 53 source files.
| Error Compilation error: startup failed:
Compile error during compilation with javac.
/home/user/.grails/2.0.4/projects/couch3/plugins/gorm-couchdb-0.9.2/
src/java/org/codehaus/groovy/grails/plugins/couchdb/domain
/CouchDomainClass.java:49: 
error: CouchDomainClass is not abstract and does not override 
abstract method getPersistentProperty(String) in GrailsDomainClass
public class CouchDomainClass extends AbstractGrailsClass implements
ExternalGrailsDomainClass {
       ^
/home/user/.grails/2.0.4/projects/couch3/plugins/gorm-couchdb-0.9.2/
src/java/org/codehaus/groovy/grails/plugins/couchdb/domain
/CouchDomainClassProperty.java:37: 
error: CouchDomainClassProperty is not abstract and does not 
override abstract method isDerived() in GrailsDomainClassProperty
public class CouchDomainClassProperty implements 
GrailsDomainClassProperty {
       ^
Note: /home/user/.grails/2.0.4/projects/couch3/plugins/
gorm-couchdb-0.9.2/src/java/org/codehaus/groovy/grails/plugins/
couchdb/domain/CouchDomainClass.java uses or overrides a 
deprecated API.

Not a good start. Especially when I can't imagine that Grails 1.3.x should not bring up the same exception. Nevertheless, I'll give it a try.

Somehow, I really ran into problem when I even just tried to install the plugin with Grails 1.3.x. The plugin is in the list when I do a <pre>grails install-plugin gorm-couchdb</pre> but when the script runs, it tells me that it can't find the plugin.

So I tried to download and install it but I've got the same result. So I made use of my last special trick: I copied and renamed the downloaded zip:
cp gorm-couchdb-0.9.2.zip grails-gorm-couchdb-0.9.2.zip
and tried to install it:
grails install-plugin grails-gorm-couchdb-0.9.2.zip
It is very interesting, that if you try to install it with the grails-prefix, it seems to pick up the file without the prefix. But it does not work the other way around. Another interesting thing is that I only ran into this problem on my linux machine. Netbeans managed to install it without any problem. I guess that this is fixed in Grails 2.0.x

Ok. So now, we have an installed plugin. If you read through the documentation, you'll find that you don't have to remove the hibernate plugin. Even better, you can configure that plugin to use anotation in order to mix hibernate and couchDB. But beware: if you want to make use of
grails generate-all domain
You first have to execute this script and only afterwards anotate your domain class - otherwise it will tell you that it can't map your domain:
Running script /usr/share/grails/1.3.8/scripts/GenerateAll.groovy
Environment set to development
Domain class not found in grails-app/domain, trying hibernate 
mapped classes...
No domain class found for name sevendatabases.DataTypes. Please 
try again and enter a valid domain class name
Application context shutting down...
Application context shutdown.
By working around this, I managed to setup my test project, but unfortunately, as soon as I try to access the list controller, I get the following Exception:
org.jcouchdb.exception.DataAccessException: error querying view: code 404
 at org.jcouchdb.db.Database.queryViewInternal(Database.java:848)
 at org.jcouchdb.db.Database.queryView(Database.java:656)
 at org.jcouchdb.db.Database$queryView.call(Unknown Source)
 at org.jcouchdb.db.Database$queryView.call(Unknown Source)
 at sevendatabases.DataTypesController$_closure2.doCall(DataTypesController.groovy:13)
 at sevendatabases.DataTypesController$_closure2.doCall(DataTypesController.groovy)
 at java.lang.Thread.run(Thread.java:722)
So, that's it for now. I guess this problem is beacuse I use the current version of CouchDB, but it makes no sense for me to downgrade to a 2 year old version just to make the plugin work.
For me, CouchDB seems to be great, but there is no easy way to use it with a standard Grails CRUD application... :-(

Sunday, June 10, 2012

Transactions

I knew that it would take more than 7 weeks to write this blog :-)

Today I would like to focus on another aspect of those databases - how do they handle transactions?

For an RDBMS it is quite common to support transactions, but I haven't read about transactions in the 7db7w book yet that those key-value databases support them.

Let's write a test for transactions:

package sevendatabases

import static org.junit.Assert.*
import org.junit.*

class TransactionTests extends GroovyTestCase {

    static transactional = false; // 1
   
    void setUp() {
    }
   
    @Test
    void testSomething() {
        def numBooks = Book.count()
        Book.withTransaction { status ->
            new Book (name:'test',isbn:'test').save(flush:true,failOnError:true)
        }
        assert Book.count() == numBooks+1
        Book.withTransaction { status ->
            new Book (name:'test',isbn:'test').save(flush:true,failOnError:true)
            status.setRollbackOnly()
        }
        assert Book.count() == numBooks+1
    }
}


Have you noticed the line marked with "// 1"? In grails, integration tests are executed in a transactional context by default. This causes some problems while testing the transaction itself. So I disabled the default transactional context.

Now I run this test against all of my configured databases:

MS SQL Server: works
MySQL: works
Oracle Express: works
Riak: fail! No transactionManager bean configured

...ok. I could have used the overview chart from the book to get the same results. But this way I had to figure out how to test transactiosn ins Grails :-)

Saturday, June 2, 2012

MS SQL Server Express

Shame on me! I forgot to include the MS SQL Server Express in my comparison!

But as any RDMS, MS SQL Server Express seems to be no problem. Installing it is easy, getting the jdbc-driver is easy, too. Connecting is a little bit hards, but you'll find enough resources on the web. Hint: I had to activate the TCP-Connection and h ad to disable the dynamic ports.

After getting the connection ready, the reast was easy - everything works as expected. Here is the updated comparison table:


PropertyMySQLPostgreSQLOracle EXMS SQL
myBigString varchar(4000) character varying(4000) VARCHAR2(4000)varchar(4000)
myBigString2 varchar(4000) character varying(4000) VARCHAR2(4000)varchar(4000)
myBigdecimal decimal(19,2) numeric(19,2) DECIMAL(19)nummeric(19,2)
myBinaryData tinyblob bytea LONGVARBINARYimage
myBoolean bit(1) boolean DECIMAL(1)tinyint
myDate datetime timestamp without time zoneTIMESTAMP(7)datetime
myDouble double double precision FLOAT(126)float
myFloat float real FLOAT(126)float
myInList varchar(5) character varying(5) VARCHAR2(5)varchar(5)
myInteger int(11) integer DECIMAL(10)int
myString varchar(255) character varying(255) VARCHAR2(255)varchar(255)
myString80 varchar(80) character varying(80) VARCHAR2(80)varchar(80)