Nagrand
Nagrand is a lightweight groovy orm
How To Use
Maven dependency
<dependency>
<groupId>io.github.noahshen</groupId>
<artifactId>nagrand</artifactId>
<version>0.0.2</version>
</dependency>You need to register classes through Nagrand on app start.
Nagrand nagrand = ...
nagrand.register(Person)or init as a Spring Framework bean
<bean id="entityInitializer" class="io.github.noahshen.nagrand.spring.EntityInitializer"
init-method="init">
<property name="entityPackage" value="io.github.noahshen.nagrand.spring.entity"/>
<property name="dataSource" ref="dataSource"/>
<property name="createTable" value="true"/>
<property name="sqlLog" value="true"/>
</bean>Basic Samples
Entity defination
@Entity
class Person {
def name
int age
}Create
def person = new Person(name: 'Spiderman', age: 30)
person.save()Update
def person = new Person(name: 'Spiderman', age: 30)
person.save()
person.name = 'Batman'
person.save()Delete
def person = new Person(name: 'Spiderman', age: 30)
//...
person.delete()Query
Get entity by ID
Integer id = 1
Person p = Person.get(id)
if (!p) {
//... not found
}Dynamic Finders
Dynamic finder looks like a static method invocation. The method is auto-generated using code synthesis at runtime, based on the properties of a entity class.
new Person(name: 'Spiderman', age: 30).save()
new Person(name: 'Batman', age: 31).save()
new Person(name: 'Superman', age: 32).save()
new Person(name: 'Ironman', age: 32).save()
def persons = Person.findByAge(32)
assert persons.size() == 2
assert persons*.name == ["Superman", "Ironman"]
def batman = Person.findFirstByName("Batman")
assert batman.name == "Batman"Find by multi properties
List<Person> persons = Person.findByNameAndAge('Superman', 32)
assert persons.size() == 1
assert persons*.name == ["Superman"]Find by more options
List<Person> persons = Person.findByAge(32) {
order("name", "desc")
}
assert persons.size() == 2
assert persons[0].name == "Superman"Where Query
The where method is more flexible than dynamic finders
by using the following methods:
.find {}.findWhere {}.where {}.findFirst {}.findFirstWhere {}
new Person(name: 'Spiderman', age: 30).save()
new Person(name: 'Batman', age: 31).save()
new Person(name: 'Superman', age: 32).save()
new Person(name: 'Ironman', age: 32).save()
List<Person> persons = Person.find {
eq "name", "Superman"
eq "age", 32
}
assert persons.size() == 1
assert persons*.name == ["Superman"]More condition:
def results = Account.find {
between("balance", 500, 1000)
eq("bankName", "boc")
or {
like("firstName", "Noah%")
like("firstName", "Sara%")
}
maxResults(10)
order("balance", "desc")
}Groovy-style query
Nagrand supports groovy-style query by providing an enhanced, compile-time checked query DSL for common queries
def person = Person.where {
firstName == "Ironman"
}def person = Person.where {
(lastName != "Shen" && firstName != "Noah") || (firstName == "Sara" && age > 20)
}Groovy operator maps onto a where method. The following table provides a map of Groovy operators to methods:
| Operator | where method | description |
|---|---|---|
| == | eq | Equal to |
| != | nq | Not equal to |
| > | gt | Greater than |
| < | lt | Less than |
| >= | ge | Greater than or equal to |
| <= | le | Less than or equal to |
| in | inList | Contained within the given list |
Events
.beforeInsert
.afterInsert
Called before/after first save
class Item {
void beforeInsert() {
...
}
void afterInsert() {
...
}
}.beforeUpdate
.afterUpdate
Called before/after object update
class Item {
void beforeUpdate() {
...
}
void afterUpdate() {
...
}
}.beforeDelete
.afterDelete
Called before/after object delete
class Item {
void beforeDelete() {
...
}
void afterDelete() {
...
}
}Optimistic Locking and Version
Nagrand uses optimistic locking by a version property which is in turn mapped to a version column at the database.
class ClassWithVersion {
Integer id
String name
Integer version
}def entity = new ClassWithVersion(name: 'Spiderman').save()
assert entity.version == 1
entity.name = "Superman"
entity.save()
assert entity.version == 2Automatic timestamping
If you define a dateCreated property, it will be set to the current date for you when you create new instances. Likewise, if you define a lastUpdated property it will be automatically be updated for you when you change the instances.
class ClassAutoTimestamp {
Integer id
String name
Date dateCreated
Date lastUpdated
}License
Project is licensed under Apache License 2.