Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,9 @@ class SchemaSpec extends Specification implements GraphQLSchemaSpec {
GraphQLInputObjectType type = schema.getType('ToOneCreate')

expect:
unwrap(null, type.getFieldDefinition('circularOne').type) == schema.getType('CircularOneCreateNested')
unwrap(null, type.getFieldDefinition('one').type) == schema.getType('OneCreateNested')
unwrap(null, type.getFieldDefinition('anEnum').type) == schema.getType('Enum')
type.getFieldDefinition('circularOne').type == schema.getType('CircularOneCreateNested')
type.getFieldDefinition('one').type == schema.getType('OneCreateNested')
type.getFieldDefinition('anEnum').type == schema.getType('Enum')

//everything else is a scalar.. not worth testing every property
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -467,8 +467,18 @@ class Book {
static hasMany = [authors: Author, tags: Tag, basics: String, otherBookTypes: BookType]

static constraints = {
description nullable: true
nullBookType nullable: true
title nullable: false
metadata nullable: false
bookType nullable: false

otherMetadata nullable: false
otherMetadata2 nullable: false
someOtherMetadata nullable: false

authors nullable: false
tags nullable: false
basics nullable: false
otherBookTypes nullable: false
}

static embedded = ['otherMetadata2', 'someOtherMetadata']
Expand All @@ -485,6 +495,10 @@ class Book2 implements Serializable {

static mapping = {
id composite: ['title', 'description']
title nullable: false
description nullable: false
metadata nullable: false
bookType nullable: false
}

int hashCode() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,6 @@ class EmbeddedInputObjectTypeBuilderSpec extends HibernateSpec {

then: 'one is included because it is the owning side, many is included because it is not bidirectional'
props*.name == ['one', 'many']
props.any { !it.nullable } //some are not nullable
!props.any { !it.nullable } //all are nullable by default
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import org.grails.datastore.mapping.reflect.ClassPropertyFetcher
* Implements the ORM mapping DSL constructing a model that can be evaluated by the
* GrailsDomainBinder class which maps GORM classes onto the database.
*
* @author Graeme Rocher
* @since 1.0
*/

Expand Down Expand Up @@ -468,7 +467,9 @@ class HibernateMappingBuilder implements MappingConfigurationBuilder<Mapping, Pr
property.ignoreNotFound = namedArgs.ignoreNotFound instanceof Boolean ? namedArgs.ignoreNotFound : property.ignoreNotFound
property.typeParams = namedArgs.params ?: property.typeParams
property.setUnique(namedArgs.unique ? namedArgs.unique : property.unique)
property.nullable = namedArgs.nullable instanceof Boolean ? namedArgs.nullable : property.nullable
if (namedArgs.nullable instanceof Boolean) {
property.nullable = namedArgs.nullable
}
property.maxSize = namedArgs.maxSize instanceof Number ? namedArgs.maxSize : property.maxSize
property.minSize = namedArgs.minSize instanceof Number ? namedArgs.minSize : property.minSize
if (namedArgs.size instanceof IntRange) {
Expand Down Expand Up @@ -703,4 +704,3 @@ class HibernateMappingBuilder implements MappingConfigurationBuilder<Mapping, Pr
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public HibernateMappingContext(HibernateConnectionSourceSettings settings, Objec

this.mappingFactory.setDefaultMapping(settings.getDefault().getMapping());
this.mappingFactory.setDefaultConstraints(settings.getDefault().getConstraints());
this.mappingFactory.setDefaultNullable(settings.getDefault().isNullable());
this.mappingFactory.setContextObject(contextObject);
this.syntaxStrategy = new JpaMappingConfigurationStrategy(mappingFactory) {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,15 @@
*/
package org.grails.orm.hibernate.cfg

import spock.lang.Specification

import grails.gorm.annotation.Entity
import org.grails.datastore.mapping.engine.types.AbstractMappingAwareCustomTypeMarshaller
import org.grails.datastore.mapping.model.PersistentEntity
import org.grails.datastore.mapping.model.PersistentProperty
import org.grails.datastore.mapping.model.ValueGenerator
import org.grails.orm.hibernate.connections.HibernateConnectionSourceSettings
import spock.lang.Specification

/**
* Created by graemerocher on 07/10/2016.
*/
class HibernateMappingContextSpec extends Specification {

void "test entity with custom id generator"() {
Expand All @@ -55,6 +53,51 @@ class HibernateMappingContextSpec extends Specification {
and:"The type is registered as a custom type with the mapping factory"
mappingContext.mappingFactory.isCustomType(MyUUIDGenerator)
}

void "unconstrained properties are nullable in the Hibernate mapping"() {
when:
def entity = new HibernateMappingContext().addPersistentEntity(MappingContextNullableByDefaultEntity)

then:
entity.getPropertyByName("name").mapping.mappedForm.nullable
}

void "explicit constraints do not prevent the default nullable mapping"() {
when:
def entity = new HibernateMappingContext().addPersistentEntity(MappingContextConstrainedEntity)

then:
entity.getPropertyByName("name").mapping.mappedForm.nullable
}

void "wildcard mappings do not prevent the default nullable mapping"() {
when:
def entity = new HibernateMappingContext().addPersistentEntity(MappingContextWildcardMappedEntity)

then:
entity.getPropertyByName("name").mapping.mappedForm.nullable
}

void "composite id components are nullable by default"() {
when:
def entity = new HibernateMappingContext().addPersistentEntity(MappingContextCompositeIdEntity)

then:
entity.getPropertyByName("tenantId").mapping.mappedForm.nullable
entity.getPropertyByName("code").mapping.mappedForm.nullable
}

void "default nullable can be disabled"() {
given:
def settings = new HibernateConnectionSourceSettings()
settings.default.nullable = false

when:
def entity = new HibernateMappingContext(settings).addPersistentEntity(MappingContextNullableByDefaultEntity)

then:
!entity.getPropertyByName("name").mapping.mappedForm.nullable
}
}

@Entity
Expand All @@ -65,6 +108,39 @@ class CustomIdGeneratorEntity {
}
}

@Entity
class MappingContextNullableByDefaultEntity {
String name
}

@Entity
class MappingContextConstrainedEntity {
String name

static constraints = {
name maxSize: 100
}
}

@Entity
class MappingContextWildcardMappedEntity {
String name

static mapping = {
'*' cache: true
}
}

@Entity
class MappingContextCompositeIdEntity {
String tenantId
String code

static mapping = {
id composite: ['tenantId', 'code']
}
}

class MyUUIDGenerator {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,19 @@ abstract class ApplicationContextDatabaseMigrationCommandSpec extends DatabaseMi
class Book {
String title
Author author

static constraints = {
title nullable: false
author nullable: false
}
}

@Entity
class Author {
String name
static hasMany = [books: Book]

static constraints = {
name nullable: false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public HibernateMappingContext(
initialize(settings);
this.mappingFactory.setDefaultMapping(settings.getDefault().getMapping());
this.mappingFactory.setDefaultConstraints(settings.getDefault().getConstraints());
this.mappingFactory.setDefaultNullable(settings.getDefault().isNullable());
this.mappingFactory.setContextObject(contextObject);
this.syntaxStrategy = new GrailsJpaMappingConfigurationStrategy(mappingFactory);
this.proxyFactory = new HibernateProxyHandler();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,9 @@ class AddressOwner {
Long id
EntityAddress address
static embedded = ['address']
static constraints = {
address nullable: false
}
}

class EntityAddress implements Serializable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,35 @@
*/
package org.grails.orm.hibernate.cfg

import org.springframework.validation.Errors

import grails.gorm.annotation.Entity
import grails.gorm.hibernate.HibernateEntity
import grails.gorm.tests.HibernateGormDatastoreSpec
import grails.gorm.transactions.Rollback
import org.grails.datastore.mapping.core.connections.ConnectionSource
import org.grails.datastore.mapping.engine.types.AbstractMappingAwareCustomTypeMarshaller
import org.grails.datastore.mapping.model.PersistentEntity
import org.grails.datastore.mapping.model.PersistentProperty
import org.grails.datastore.mapping.model.ValueGenerator
import org.grails.datastore.mapping.model.config.JpaMappingConfigurationStrategy
import org.grails.orm.hibernate.cfg.domainbinding.hibernate.GrailsHibernatePersistentEntity
import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernatePersistentProperty
import org.grails.orm.hibernate.cfg.domainbinding.hibernate.GrailsJpaMappingConfigurationStrategy
import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernatePersistentProperty
import org.grails.orm.hibernate.connections.HibernateConnectionSourceSettings
import org.springframework.validation.Errors
import org.grails.datastore.mapping.core.connections.ConnectionSource

class HibernateMappingContextSpec extends HibernateGormDatastoreSpec {

def setupSpec() {
manager.registerDomainClasses(MappingContextBook, MappingContextAuthor, MappingContextAddress)
manager.registerDomainClasses(
MappingContextBook,
MappingContextAuthor,
MappingContextAddress,
MappingContextNullableByDefaultEntity,
MappingContextConstrainedEntity,
MappingContextWildcardMappedEntity,
MappingContextCompositeIdEntity
)
}

// --- unit-style tests (no datastore required) ---
Expand Down Expand Up @@ -114,6 +124,25 @@ class HibernateMappingContextSpec extends HibernateGormDatastoreSpec {
mappingContext instanceof HibernateMappingContext
}

void "composite id components are nullable by default"() {
given:
PersistentEntity entity = mappingContext.getPersistentEntity(MappingContextCompositeIdEntity.name)

expect:
entity.getPropertyByName('tenantId').nullable
entity.getPropertyByName('code').nullable
}

@Rollback
void "saving an entity with an unset unconstrained property succeeds"() {
when:
def entity = new MappingContextNullableByDefaultEntity().save(flush: true)

then:
entity != null
!entity.hasErrors()
}

void "registered domain classes appear as persistent entities"() {
expect:
mappingContext.getPersistentEntity(MappingContextBook.name) != null
Expand Down Expand Up @@ -181,6 +210,42 @@ class HibernateMappingContextSpec extends HibernateGormDatastoreSpec {
noExceptionThrown()
}

void "unconstrained properties are nullable in the Hibernate mapping"() {
when:
def entity = new HibernateMappingContext().addPersistentEntity(MappingContextNullableByDefaultEntity)

then:
entity.getPropertyByName("name").mapping.mappedForm.nullable
}

void "explicit non-null constraints do not prevent the default nullable mapping"() {
when:
def entity = new HibernateMappingContext().addPersistentEntity(MappingContextConstrainedEntity)

then:
entity.getPropertyByName("name").mapping.mappedForm.nullable
}

void "wildcard mappings do not prevent the default nullable mapping"() {
when:
def entity = new HibernateMappingContext().addPersistentEntity(MappingContextWildcardMappedEntity)

then:
entity.getPropertyByName("name").mapping.mappedForm.nullable
}

void "default nullable can be disabled"() {
given:
def settings = new HibernateConnectionSourceSettings()
settings.default.nullable = false

when:
def entity = new HibernateMappingContext(settings).addPersistentEntity(MappingContextNullableByDefaultEntity)

then:
!entity.getPropertyByName("name").mapping.mappedForm.nullable
}

void "createPersistentEntity returns null for non-GormEntity class"() {
given:
def ctx = new HibernateMappingContext()
Expand Down Expand Up @@ -225,6 +290,39 @@ class MappingContextAddress {
String city
}

@Entity
class MappingContextNullableByDefaultEntity implements HibernateEntity<MappingContextNullableByDefaultEntity> {
String name
}

@Entity
class MappingContextConstrainedEntity implements HibernateEntity<MappingContextConstrainedEntity> {
String name

static constraints = {
name maxSize: 100
}
}

@Entity
class MappingContextWildcardMappedEntity implements HibernateEntity<MappingContextWildcardMappedEntity> {
String name

static mapping = {
'*' cache: true
}
}

@Entity
class MappingContextCompositeIdEntity implements HibernateEntity<MappingContextCompositeIdEntity> {
String tenantId
String code

static mapping = {
id composite: ['tenantId', 'code']
}
}

// --- helpers for unit tests ---

@Entity
Expand Down
Loading
Loading