A lot of things fixed to get closer to a working implementation. Signed-off-by: niclas <[email protected]>
Project: http://git-wip-us.apache.org/repos/asf/polygene-java/repo Commit: http://git-wip-us.apache.org/repos/asf/polygene-java/commit/59a08629 Tree: http://git-wip-us.apache.org/repos/asf/polygene-java/tree/59a08629 Diff: http://git-wip-us.apache.org/repos/asf/polygene-java/diff/59a08629 Branch: refs/heads/develop Commit: 59a08629239a38bdf93cf02fb1a3722e36abbdd8 Parents: ffd7207 Author: niclas <[email protected]> Authored: Sun Jun 11 11:43:12 2017 +0800 Committer: niclas <[email protected]> Committed: Sun Jun 11 11:43:12 2017 +0800 ---------------------------------------------------------------------- .../test/entity/AbstractEntityStoreTest.java | 3 - extensions/entitystore-jooq/dev-status.xml | 20 +- .../entitystore-jooq/src/docs/es-jooq.txt | 58 +++++ extensions/entitystore-jooq/src/docs/es-orm.txt | 58 ----- .../entitystore/jooq/AssociationValue.java | 7 +- .../polygene/entitystore/jooq/BaseEntity.java | 3 +- .../entitystore/jooq/EntitiesTable.java | 210 ++++++++++++++----- .../entitystore/jooq/JooqEntityStoreMixin.java | 128 ++++++----- .../polygene/entitystore/jooq/MixinTable.java | 197 +++++++++++------ .../polygene/entitystore/jooq/SqlTable.java | 37 +++- .../polygene/entitystore/jooq/TableFields.java | 22 +- .../polygene/entitystore/jooq/TypesTable.java | 10 +- .../entitystore/jooq/JooqEntityStoreTest.java | 21 +- manual/src/docs/userguide/extensions.txt | 4 + 14 files changed, 506 insertions(+), 272 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/core/testsupport/src/main/java/org/apache/polygene/test/entity/AbstractEntityStoreTest.java ---------------------------------------------------------------------- diff --git a/core/testsupport/src/main/java/org/apache/polygene/test/entity/AbstractEntityStoreTest.java b/core/testsupport/src/main/java/org/apache/polygene/test/entity/AbstractEntityStoreTest.java index 2bb6abb..0eee83a 100644 --- a/core/testsupport/src/main/java/org/apache/polygene/test/entity/AbstractEntityStoreTest.java +++ b/core/testsupport/src/main/java/org/apache/polygene/test/entity/AbstractEntityStoreTest.java @@ -359,7 +359,6 @@ public abstract class AbstractEntityStoreTest try( UnitOfWork unitOfWork = unitOfWorkFactory.newUnitOfWork() ) { EntityBuilder<TestEntity> builder = unitOfWork.newEntityBuilder( TestEntity.class ); - testEntity = builder.newInstance(); unitOfWork.complete(); } @@ -368,7 +367,6 @@ public abstract class AbstractEntityStoreTest testEntity = unitOfWork.get( testEntity ); testEntity.name().set( "Rickard" ); version = spi.entityStateOf( testEntity ).version(); - unitOfWork.complete(); } try( UnitOfWork unitOfWork = unitOfWorkFactory.newUnitOfWork() ) @@ -376,7 +374,6 @@ public abstract class AbstractEntityStoreTest testEntity = unitOfWork.get( testEntity ); String newVersion = spi.entityStateOf( testEntity ).version(); assertThat( "version has not changed", newVersion, not( equalTo( version ) ) ); - unitOfWork.complete(); } } http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/dev-status.xml ---------------------------------------------------------------------- diff --git a/extensions/entitystore-jooq/dev-status.xml b/extensions/entitystore-jooq/dev-status.xml index 0914c52..6710bdd 100644 --- a/extensions/entitystore-jooq/dev-status.xml +++ b/extensions/entitystore-jooq/dev-status.xml @@ -23,16 +23,16 @@ xsi:schemaLocation="http://polygene.apache.org/schemas/2008/dev-status/1 http://polygene.apache.org/schemas/2008/dev-status/1/dev-status.xsd"> <status> - <!--none,early,beta,stable,mature--> - <codebase>stable</codebase> + <!--none,early,beta,stable,mature--> + <codebase>early</codebase> - <!-- none, brief, good, complete --> - <documentation>good</documentation> + <!-- none, brief, good, complete --> + <documentation>none</documentation> - <!-- none, some, good, complete --> - <unittests>good</unittests> - </status> - <licenses> - <license>ALv2</license> - </licenses> + <!-- none, some, good, complete --> + <unittests>good</unittests> + </status> + <licenses> + <license>ALv2</license> + </licenses> </module> http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/src/docs/es-jooq.txt ---------------------------------------------------------------------- diff --git a/extensions/entitystore-jooq/src/docs/es-jooq.txt b/extensions/entitystore-jooq/src/docs/es-jooq.txt new file mode 100644 index 0000000..a36d463 --- /dev/null +++ b/extensions/entitystore-jooq/src/docs/es-jooq.txt @@ -0,0 +1,58 @@ +/////////////////////////////////////////////////////////////// + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. +/////////////////////////////////////////////////////////////// + +[[extension-es-jooq,SQL EntityStore]] += ORM EntityStore = + +[devstatus] +-------------- +source=extensions/entitystore-jooq/dev-status.xml +-------------- + +This entitystore is backed by a SQL server, and maps each mixin type of the Composite into separate tables. This is more +enterprise-friendly, but comes at the cost of less performance compared to the <<extension-es-sql>>. + +This extension fully leverage the <<library-sql>> meaning that you must use it to assemble your DataSource and that you +get <<library-circuitbreaker,Circuit Breaker>> and <<library-jmx, JMX>> integration for free. + +include::../../build/docs/buildinfo/artifact.txt[] + +== Assembly == + +Assembly is done using the provided Assembler: + +[snippet,java] +---- +source=extensions/entitystore-jooq/src/test/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreTest.java +tag=assembly +---- + +== Configuration == + +Here are the available configuration properties: + +[snippet,java] +---- +source=extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreConfiguration.java +tag=config +---- + +All authentication related properties are optional. +By default no authentication is used. +As soon as you provide a `username`, authentication is set up. http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/src/docs/es-orm.txt ---------------------------------------------------------------------- diff --git a/extensions/entitystore-jooq/src/docs/es-orm.txt b/extensions/entitystore-jooq/src/docs/es-orm.txt deleted file mode 100644 index 413eb7b..0000000 --- a/extensions/entitystore-jooq/src/docs/es-orm.txt +++ /dev/null @@ -1,58 +0,0 @@ -/////////////////////////////////////////////////////////////// - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. -/////////////////////////////////////////////////////////////// - -[[extension-es-orm,ORM EntityStore]] -= ORM EntityStore = - -[devstatus] --------------- -source=extensions/entitystore-orm/dev-status.xml --------------- - -This entitystore is backed by a SQL server, and maps each type of the Composite into separate tables. This is more -enterprise-friendly, but comes at the cost of less performance compared to the <<extension-es-sql>>. - -This extension fully leverage the <<library-sql>> meaning that you must use it to assemble your DataSource and that you -get <<library-circuitbreaker,Circuit Breaker>> and <<library-jmx, JMX>> integration for free. - -include::../../build/docs/buildinfo/artifact.txt[] - -== Assembly == - -Assembly is done using the provided Assembler: - -[snippet,java] ----- -source=extensions/entitystore-riak/src/test/java/org/apache/polygene/entitystore/orm/OrmEntityStoreTest.java -tag=assembly ----- - -== Configuration == - -Here are the available configuration properties: - -[snippet,java] ----- -source=extensions/entitystore-riak/src/main/java/org/apache/polygene/entitystore/orm/OrmEntityStoreConfiguration.java -tag=config ----- - -All authentication related properties are optional. -By default no authentication is used. -As soon as you provide a `username`, authentication is set up. http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/AssociationValue.java ---------------------------------------------------------------------- diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/AssociationValue.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/AssociationValue.java index 81331cf..528ab8b 100644 --- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/AssociationValue.java +++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/AssociationValue.java @@ -17,9 +17,12 @@ */ package org.apache.polygene.entitystore.jooq; -class AssociationValue +import org.apache.polygene.api.common.QualifiedName; + +@SuppressWarnings( "WeakerAccess" ) +public class AssociationValue { - String name; + QualifiedName name; String position; String reference; } http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/BaseEntity.java ---------------------------------------------------------------------- diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/BaseEntity.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/BaseEntity.java index e4eaa40..3c16f16 100644 --- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/BaseEntity.java +++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/BaseEntity.java @@ -21,7 +21,8 @@ import java.time.Instant; import org.apache.polygene.api.entity.EntityDescriptor; import org.apache.polygene.api.identity.Identity; -class BaseEntity +@SuppressWarnings( "WeakerAccess" ) +public class BaseEntity { EntityDescriptor type; Identity identity; http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/EntitiesTable.java ---------------------------------------------------------------------- diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/EntitiesTable.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/EntitiesTable.java index dc765a9..001b590 100644 --- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/EntitiesTable.java +++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/EntitiesTable.java @@ -26,12 +26,18 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.polygene.api.association.AssociationDescriptor; import org.apache.polygene.api.common.QualifiedName; +import org.apache.polygene.api.composite.Composite; +import org.apache.polygene.api.entity.EntityComposite; import org.apache.polygene.api.entity.EntityDescriptor; import org.apache.polygene.api.entity.EntityReference; +import org.apache.polygene.api.identity.HasIdentity; +import org.apache.polygene.api.identity.StringIdentity; import org.apache.polygene.api.property.PropertyDescriptor; import org.apache.polygene.api.structure.ModuleDescriptor; import org.apache.polygene.api.type.EntityCompositeType; @@ -48,10 +54,14 @@ import org.jooq.Schema; import org.jooq.SelectJoinStep; import org.jooq.SelectQuery; import org.jooq.Table; +import org.jooq.impl.DSL; +@SuppressWarnings( "WeakerAccess" ) public class EntitiesTable implements TableFields { + private static final Predicate<? super Class<?>> NOT_COMPOSITE = type -> !( type.equals( Composite.class ) || type.equals( EntityComposite.class ) ); + private static final Predicate<? super Class<?>> NOT_HASIDENTITY = type -> !( type.equals( HasIdentity.class ) ); private Map<EntityCompositeType, Set<Class<?>>> mixinTypeCache = new ConcurrentHashMap<>(); private Map<Class<?>, MixinTable> mixinTablesCache = new ConcurrentHashMap<>(); @@ -60,6 +70,7 @@ public class EntitiesTable private final TypesTable types; private final Schema schema; private String applicationVersion; + private boolean replacementStrategy = false; // Figure out later if we should support both and if so, how. EntitiesTable( JooqDslContext dsl, Schema schema, TypesTable types, String applicationVersion, String entitiesTableName ) { @@ -72,7 +83,6 @@ public class EntitiesTable public BaseEntity fetchEntity( EntityReference reference, ModuleDescriptor module ) { - BaseEntity result = new BaseEntity(); Result<Record> baseEntityResult = dsl .selectFrom( entitiesTable ) @@ -83,18 +93,32 @@ public class EntitiesTable { throw new EntityNotFoundException( reference ); } - Record baseEntity = baseEntityResult.get( 0 ); - String typeName = baseEntity.field( typeNameColumn ).get( baseEntity ); + Record row = baseEntityResult.get( 0 ); + return toBaseEntity( row, module ); + } + + protected BaseEntity toBaseEntity( Record row, ModuleDescriptor module ) + { + BaseEntity result = new BaseEntity(); + String typeName = row.field( typeNameColumn ).get( row ); result.type = findEntityDescriptor( typeName, module ); - result.version = baseEntity.field( versionColumn ).get( baseEntity ); - result.applicationVersion = baseEntity.field( applicationVersionColumn ).get( baseEntity ); - result.identity = EntityReference.parseEntityReference( baseEntity.field( identityColumn ).get( baseEntity ) ).identity(); - result.currentValueIdentity = EntityReference.parseEntityReference( baseEntity.field( valueIdentityColumn ).get( baseEntity ) ).identity(); - result.modifedAt = Instant.ofEpochMilli( baseEntity.field( modifiedColumn ).get( baseEntity ).getTime() ); - result.createdAt = Instant.ofEpochMilli( baseEntity.field( createdColumn ).get( baseEntity ).getTime() ); + result.version = row.field( versionColumn ).get( row ); + result.applicationVersion = row.field( applicationVersionColumn ).get( row ); + result.identity = new StringIdentity( row.field( identityColumn ).get( row ) ); + result.currentValueIdentity = EntityReference.parseEntityReference( row.field( valueIdentityColumn ).get( row ) ).identity(); + result.modifedAt = Instant.ofEpochMilli( row.field( modifiedColumn ).get( row ).getTime() ); + result.createdAt = Instant.ofEpochMilli( row.field( createdColumn ).get( row ).getTime() ); return result; } + public Stream<BaseEntity> fetchAll( EntityDescriptor type, ModuleDescriptor module ) + { + Result<Record> baseEntityResult = dsl + .selectFrom( entitiesTable ) + .fetch(); + return baseEntityResult.stream().map( record -> toBaseEntity( record, module ) ); + } + private EntityDescriptor findEntityDescriptor( String typeName, ModuleDescriptor module ) { try @@ -108,34 +132,36 @@ public class EntitiesTable } } - void insertEntity( DefaultEntityState state ) + void insertEntity( DefaultEntityState state, BaseEntity baseEntity ) { EntityCompositeType compositeType = state.entityDescriptor().valueType(); - Set<Class<?>> mixinTypes = mixinTypeCache.computeIfAbsent( compositeType, type -> - { - Set<Class<?>> mixins = compositeType - .properties() - .map( PropertyDescriptor::accessor ) - .filter( Classes.instanceOf( Method.class ) ) - .map( accessor -> (Method) accessor ) - .map( Method::getDeclaringClass ) - .collect( Collectors.toSet() ); - Set<Class<?>> mixinsWithAssociations = mixinsOf( compositeType.associations() ); - Set<Class<?>> mixinsWithManyAssociations = mixinsOf( compositeType.manyAssociations() ); - Set<Class<?>> mixinsWithNamedAssociations = mixinsOf( compositeType.namedAssociations() ); - mixins.addAll( mixinsWithAssociations ); - mixins.addAll( mixinsWithManyAssociations ); - mixins.addAll( mixinsWithNamedAssociations ); - return mixins; - } ); - String valueIdentity = UUID.randomUUID().toString(); + Set<Class<?>> mixinTypes = mixinTypeCache.computeIfAbsent( compositeType, createMixinTypesSet( compositeType ) ); mixinTypes.forEach( type -> { MixinTable table = findMixinTable( type, state.entityDescriptor() ); - table.insertMixinState( state, valueIdentity ); + table.insertMixinState( state, baseEntity.currentValueIdentity.toString() ); } ); } + void modifyEntity( DefaultEntityState state, BaseEntity baseEntity, EntityStoreUnitOfWork uow ) + { + updateBaseEntity( baseEntity, uow ); + if( replacementStrategy ) + { + insertEntity( state, baseEntity ); // replacement strategy (more safe) + } + else + { + EntityCompositeType compositeType = state.entityDescriptor().valueType(); + Set<Class<?>> mixinTypes = mixinTypeCache.computeIfAbsent( compositeType, createMixinTypesSet( compositeType ) ); + mixinTypes.forEach( type -> + { + MixinTable table = findMixinTable( type, state.entityDescriptor() ); + table.modifyMixinState( state, baseEntity.currentValueIdentity.toString() ); + } ); + } + } + private MixinTable findMixinTable( Class<?> type, EntityDescriptor entityDescriptor ) { return mixinTablesCache.computeIfAbsent( type, t -> new MixinTable( dsl, schema, types, type, entityDescriptor ) ); @@ -148,17 +174,32 @@ public class EntitiesTable .filter( Classes.instanceOf( Method.class ) ) .map( accessor -> (Method) accessor ) .map( Method::getDeclaringClass ) + .filter( NOT_HASIDENTITY ) + .filter( NOT_COMPOSITE ) .collect( Collectors.toSet() ); } - private String columnNameOf( QualifiedName propertyName ) - { - return null; - } - - void modifyEntity( Class<?> mixinType, DefaultEntityState state ) + private Function<EntityCompositeType, Set<Class<?>>> createMixinTypesSet( EntityCompositeType compositeType ) { - + return type -> + { + Set<Class<?>> mixins = compositeType + .properties() + .map( PropertyDescriptor::accessor ) + .filter( Classes.instanceOf( Method.class ) ) + .map( accessor -> (Method) accessor ) + .map( Method::getDeclaringClass ) + .filter( NOT_HASIDENTITY ) + .filter( NOT_COMPOSITE ) + .collect( Collectors.toSet() ); + Set<Class<?>> mixinsWithAssociations = mixinsOf( compositeType.associations() ); + Set<Class<?>> mixinsWithManyAssociations = mixinsOf( compositeType.manyAssociations() ); + Set<Class<?>> mixinsWithNamedAssociations = mixinsOf( compositeType.namedAssociations() ); + mixins.addAll( mixinsWithAssociations ); + mixins.addAll( mixinsWithManyAssociations ); + mixins.addAll( mixinsWithNamedAssociations ); + return mixins; + }; } void createNewBaseEntity( EntityReference reference, EntityDescriptor descriptor, EntityStoreUnitOfWork uow ) @@ -175,6 +216,27 @@ public class EntitiesTable .execute(); } + private void updateBaseEntity( BaseEntity entity, EntityStoreUnitOfWork uow ) + { + entity.version = increment( entity.version ); + if( replacementStrategy ) + { + entity.currentValueIdentity = new StringIdentity( UUID.randomUUID().toString() ); + } + dsl.update( entitiesTable ) + .set( modifiedColumn, new Timestamp( uow.currentTime().toEpochMilli() ) ) + .set( valueIdentityColumn, entity.currentValueIdentity.toString() ) + .set( versionColumn, entity.version ) + .set( applicationVersionColumn, applicationVersion ) + .execute(); + } + + private String increment( String version ) + { + long ver = Long.parseLong( version ); + return Long.toString( ver + 1 ); + } + /** * Builds the SELECT statement for a given entity. * <p> @@ -217,31 +279,85 @@ public class EntitiesTable */ public SelectQuery<Record> createGetEntityQuery( EntityDescriptor entityDescriptor, EntityReference reference ) { + List<Table<Record>> joins = getMixinTables( entityDescriptor ); SelectJoinStep<Record> from = dsl.select().from( entitiesTable ); - List<Table<Record>> joins = getTableJoins( entityDescriptor ); for( Table<Record> joinedTable : joins ) { - Field<String> joinedField = joinedTable.field( identityColumn ); - Condition joinCondition = joinedField.eq( entitiesTable.field( valueIdentityColumn ) ); + Condition joinCondition = valueIdentityColumn.eq( identityColumnOf( joinedTable ) ); + from = from.leftJoin( joinedTable ).on( joinCondition ); + } + return from.where( identityColumnOf( entitiesTable ).eq( reference.identity().toString() ) ).getQuery(); + } + + public void fetchAssociations( BaseEntity entity, EntityDescriptor entityDescriptor, Consumer<AssociationValue> consume ) + { + List<Table<Record>> joins = getAssocationsTables( entityDescriptor ); + SelectJoinStep<Record> from = dsl.select().from( entitiesTable ); + for( Table<Record> joinedTable : joins ) + { + Condition joinCondition = valueIdentityColumn.eq( identityColumnOf( joinedTable ) ); from = from.join( joinedTable ).on( joinCondition ); } - return from.where( identityColumn.eq( reference.identity().toString() ) ).getQuery(); + String reference = entity.identity.toString(); + SelectQuery<Record> query = from.where( identityColumnOf( entitiesTable ).eq( reference ) ).getQuery(); + Result<Record> result = query.fetch(); + result.forEach( record -> + { + AssociationValue value = new AssociationValue(); + value.name = QualifiedName.fromClass( entityDescriptor.primaryType(), record.getValue( nameColumn ) ); + value.position = record.getValue( indexColumn ); + value.reference = record.getValue( referenceColumn ); + consume.accept( value ); + } ); } - public void fetchAssociations( Record record, Consumer<AssociationValue> consume ) + private Field<String> identityColumnOf( Table<Record> joinedTable ) { - AssociationValue value = new AssociationValue(); - value.name = record.getValue( nameColumn ); - value.position = record.getValue( indexColumn ); - value.reference = record.getValue( referenceColumn ); - consume.accept( value ); + return DSL.field( DSL.name( joinedTable.getName(), identityColumn.getName() ), String.class ); } - public List<Table<Record>> getTableJoins( EntityDescriptor entityDescriptor ) + public List<Table<Record>> getMixinTables( EntityDescriptor entityDescriptor ) { return entityDescriptor .mixinTypes() + .filter( NOT_COMPOSITE ) + .filter( NOT_HASIDENTITY ) .map( ( Class<?> type ) -> types.tableFor( type, entityDescriptor ) ) .collect( Collectors.toList() ); } + + public List<Table<Record>> getAssocationsTables( EntityDescriptor entityDescriptor ) + { + return entityDescriptor + .mixinTypes() + .filter( NOT_COMPOSITE ) + .filter( NOT_HASIDENTITY ) + .map( type -> findMixinTable( type, entityDescriptor ) ) + .map( MixinTable::associationsTable ) + .collect( Collectors.toList() ); + } + + public void removeEntity( EntityReference entityReference, EntityDescriptor descriptor ) + { + ModuleDescriptor module = descriptor.module(); + BaseEntity baseEntity = fetchEntity( entityReference, module ); + if( replacementStrategy ) + { + // TODO; Mark deleted, I guess... not implemented + } + else + { + dsl.delete( entitiesTable ) + .where( + identityColumnOf( entitiesTable ).eq( entityReference.identity().toString() ) + ) + .execute() + ; + String valueId = baseEntity.currentValueIdentity.toString(); + List<Table<Record>> mixinTables = getMixinTables( descriptor ); + List<Table<Record>> assocTables = getAssocationsTables( descriptor ); + mixinTables.forEach( table -> dsl.delete( table ).where( identityColumnOf( table ).eq( valueId ) ).execute() ); + assocTables.forEach( table -> dsl.delete( table ).where( identityColumnOf( table ).eq( valueId ) ).execute() ); + } + } } http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreMixin.java ---------------------------------------------------------------------- diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreMixin.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreMixin.java index a22354b..5a062d8 100644 --- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreMixin.java +++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreMixin.java @@ -28,9 +28,11 @@ import org.apache.polygene.api.association.AssociationStateDescriptor; import org.apache.polygene.api.common.QualifiedName; import org.apache.polygene.api.entity.EntityDescriptor; import org.apache.polygene.api.entity.EntityReference; +import org.apache.polygene.api.identity.HasIdentity; import org.apache.polygene.api.identity.IdentityGenerator; import org.apache.polygene.api.injection.scope.Service; import org.apache.polygene.api.injection.scope.This; +import org.apache.polygene.api.serialization.Serialization; import org.apache.polygene.api.structure.ModuleDescriptor; import org.apache.polygene.api.usecase.Usecase; import org.apache.polygene.spi.entity.EntityState; @@ -57,6 +59,9 @@ public class JooqEntityStoreMixin @Service private IdentityGenerator identityGenerator; + @Service + private Serialization serialization; + @Override public EntityState newEntityState( EntityStoreUnitOfWork unitOfWork, EntityReference reference, EntityDescriptor entityDescriptor ) { @@ -73,36 +78,45 @@ public class JooqEntityStoreMixin { throw new EntityNotFoundException( reference ); } + return toEntityState( result, baseEntity, reference ); + } + + protected EntityState toEntityState( Result<Record> result, BaseEntity baseEntity, EntityReference reference ) + { AssociationStateDescriptor stateDescriptor = baseEntity.type.state(); Map<QualifiedName, Object> properties = new HashMap<>(); - stateDescriptor.properties().forEach( prop -> - { - QualifiedName qualifiedName = prop.qualifiedName(); - Object value = result.getValue( 0, qualifiedName.name() ); - properties.put( qualifiedName, value ); - } ); + stateDescriptor.properties() + .filter( prop -> !HasIdentity.IDENTITY_STATE_NAME.equals( prop.qualifiedName() ) ) + .forEach( prop -> + { + QualifiedName qualifiedName = prop.qualifiedName(); + Object value = result.getValue( 0, qualifiedName.name() ); + properties.put( qualifiedName, value ); + } ); Map<QualifiedName, EntityReference> assocations = new HashMap<>(); - stateDescriptor.associations().forEach( assoc -> - { - QualifiedName qualifiedName = assoc.qualifiedName(); - String value = (String) result.getValue( 0, qualifiedName.name() ); - assocations.put( qualifiedName, parseEntityReference( value ) ); - } ); + stateDescriptor.associations() + .forEach( assoc -> + { + QualifiedName qualifiedName = assoc.qualifiedName(); + String value = (String) result.getValue( 0, qualifiedName.name() ); + if( value != null ) + { + assocations.put( qualifiedName, parseEntityReference( value ) ); + } + } ); Map<QualifiedName, List<EntityReference>> manyAssocs = new HashMap<>(); Map<QualifiedName, Map<String, EntityReference>> namedAssocs = new HashMap<>(); - result.forEach( record -> - sqlTable.fetchAssociations( record, associationValue -> - { - // TODO: Perhaps introduce "preserveManyAssociationOrder" option which would have an additional column, separating 'ordinal position' and 'name position' - if( associationValue.position == null ) - { - addManyAssociation( stateDescriptor, manyAssocs, associationValue ); - } - else - { - addNamedAssociation( stateDescriptor, namedAssocs, associationValue ); - } - } ) ); + sqlTable.fetchAssociations( baseEntity, baseEntity.type, associationValue -> + { + if( stateDescriptor.hasManyAssociation( associationValue.name ) ) + { + addManyAssociation( stateDescriptor, manyAssocs, associationValue ); + } + else if( stateDescriptor.hasNamedAssociation( associationValue.name ) ) + { + addNamedAssociation( stateDescriptor, namedAssocs, associationValue ); + } + } ); return new DefaultEntityState( baseEntity.version, baseEntity.modifedAt, @@ -117,7 +131,7 @@ public class JooqEntityStoreMixin private void addNamedAssociation( AssociationStateDescriptor stateDescriptor, Map<QualifiedName, Map<String, EntityReference>> namedAssocs, AssociationValue associationValue ) { - AssociationDescriptor descriptor = stateDescriptor.getNamedAssociationByName( associationValue.name ); + AssociationDescriptor descriptor = stateDescriptor.getNamedAssociationByName( associationValue.name.name() ); QualifiedName qualifiedName = descriptor.qualifiedName(); Map<String, EntityReference> map = namedAssocs.computeIfAbsent( qualifiedName, k -> new HashMap<>() ); map.put( associationValue.position, parseEntityReference( associationValue.reference ) ); @@ -125,10 +139,11 @@ public class JooqEntityStoreMixin private void addManyAssociation( AssociationStateDescriptor stateDescriptor, Map<QualifiedName, List<EntityReference>> manyAssocs, AssociationValue associationValue ) { - AssociationDescriptor descriptor = stateDescriptor.getManyAssociationByName( associationValue.name ); + AssociationDescriptor descriptor = stateDescriptor.getManyAssociationByName( associationValue.name.name() ); QualifiedName qualifiedName = descriptor.qualifiedName(); List<EntityReference> list = manyAssocs.computeIfAbsent( qualifiedName, k -> new ArrayList<>() ); - list.add( parseEntityReference( associationValue.reference ) ); + String reference = associationValue.reference; + list.add( reference == null ? null : parseEntityReference( reference ) ); } @Override @@ -158,7 +173,16 @@ public class JooqEntityStoreMixin @Override public Stream<EntityState> entityStates( ModuleDescriptor module ) { - return null; + Stream<? extends EntityDescriptor> entityTypes = module.entityComposites(); + return entityTypes + .flatMap( type -> sqlTable.fetchAll( type, module ) ) + .map( baseEntity -> + { + EntityReference reference = EntityReference.entityReferenceFor( baseEntity.identity ); + SelectQuery<Record> selectQuery = sqlTable.createGetEntityQuery( baseEntity.type, reference ); + Result<Record> result = selectQuery.fetch(); + return toEntityState( result, baseEntity, reference ); + } ); } private class JooqStateCommitter @@ -167,12 +191,36 @@ public class JooqEntityStoreMixin private final EntityStoreUnitOfWork unitOfWork; private final Iterable<EntityState> states; private final JooqDslContext dslContext; + private final ModuleDescriptor module; JooqStateCommitter( EntityStoreUnitOfWork unitOfWork, Iterable<EntityState> states, JooqDslContext dslContext ) { this.unitOfWork = unitOfWork; this.states = states; this.dslContext = dslContext; + this.module = unitOfWork.module(); + } + + private void newState( DefaultEntityState state, EntityStoreUnitOfWork unitOfWork ) + { + EntityReference ref = state.entityReference(); + EntityDescriptor descriptor = state.entityDescriptor(); + sqlTable.createNewBaseEntity( ref, descriptor, this.unitOfWork ); + sqlTable.insertEntity( state, sqlTable.fetchBaseEntity( ref, module ), unitOfWork ); + } + + private void updateState( DefaultEntityState state, EntityStoreUnitOfWork unitOfWork ) + { + EntityDescriptor descriptor = state.entityDescriptor(); + BaseEntity baseEntity = sqlTable.fetchBaseEntity( state.entityReference(), descriptor.module() ); + sqlTable.updateEntity( state, baseEntity, unitOfWork ); + } + + private void removeState( DefaultEntityState state ) + { + EntityReference reference = state.entityReference(); + EntityDescriptor descriptor = state.entityDescriptor(); + sqlTable.removeEntity( reference, descriptor ); } @Override @@ -185,11 +233,11 @@ public class JooqEntityStoreMixin DefaultEntityState state = (DefaultEntityState) es; if( state.status() == EntityStatus.NEW ) { - newState( state ); + newState( state, unitOfWork ); } if( state.status() == EntityStatus.UPDATED ) { - updateState( state ); + updateState( state, unitOfWork ); } if( state.status() == EntityStatus.REMOVED ) { @@ -199,24 +247,6 @@ public class JooqEntityStoreMixin } ); } - private void newState( DefaultEntityState state ) - { - EntityReference ref = state.entityReference(); - EntityDescriptor descriptor = state.entityDescriptor(); - sqlTable.createNewBaseEntity( ref, descriptor, unitOfWork ); - sqlTable.insertEntity( state ); - } - - private void updateState( DefaultEntityState state ) - { - - } - - private void removeState( DefaultEntityState state ) - { - EntityReference reference = state.entityReference(); - } - @Override public void cancel() { http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/MixinTable.java ---------------------------------------------------------------------- diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/MixinTable.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/MixinTable.java index fee95ef..257134e 100644 --- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/MixinTable.java +++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/MixinTable.java @@ -20,7 +20,11 @@ package org.apache.polygene.entitystore.jooq; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Method; import java.sql.Timestamp; +import java.util.Collections; +import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Consumer; import org.apache.polygene.api.association.AssociationDescriptor; import org.apache.polygene.api.common.QualifiedName; @@ -32,10 +36,12 @@ import org.apache.polygene.spi.entity.NamedAssociationState; import org.apache.polygene.spi.entitystore.helpers.DefaultEntityState; import org.jooq.Field; import org.jooq.InsertSetMoreStep; +import org.jooq.InsertSetStep; import org.jooq.Name; import org.jooq.Record; import org.jooq.Schema; import org.jooq.Table; +import org.jooq.UpdateSetMoreStep; import org.jooq.impl.DSL; class MixinTable @@ -46,6 +52,11 @@ class MixinTable private final Table<Record> mixinAssocsTable; private final JooqDslContext dsl; + private final Map<QualifiedName, Field<Object>> properties = new ConcurrentHashMap<>(); + private final Map<QualifiedName, Field<String>> associations = new ConcurrentHashMap<>(); + private final List<QualifiedName> manyAssociations = new CopyOnWriteArrayList<>(); + private final List<QualifiedName> namedAssociations = new CopyOnWriteArrayList<>(); + private TypesTable types; private final Class<?> mixinType; @@ -57,6 +68,34 @@ class MixinTable this.mixinType = mixinType; mixinTable = types.tableFor( mixinType, descriptor ); mixinAssocsTable = getAssocsTable( descriptor, schema ); + + descriptor.valueType().properties() + .filter( this::isThisMixin ) + .forEach( propDescriptor -> + { + QualifiedName propertyName = propDescriptor.qualifiedName(); + Field<Object> propertyField = types.fieldOf( propDescriptor ); + properties.put( propertyName, propertyField ); + } + ); + + descriptor.valueType().associations() + .filter( this::isThisMixin ) + .forEach( assocDescriptor -> + { + QualifiedName assocName = assocDescriptor.qualifiedName(); + Field<String> assocField = types.fieldOf( assocDescriptor ); + associations.put( assocName, assocField ); + } + ); + + descriptor.valueType().manyAssociations() + .filter( this::isThisMixin ) + .forEach( assocDescriptor -> manyAssociations.add( assocDescriptor.qualifiedName() ) ); + + descriptor.valueType().namedAssociations() + .filter( this::isThisMixin ) + .forEach( assocDescriptor -> manyAssociations.add( assocDescriptor.qualifiedName() ) ); } void insertMixinState( DefaultEntityState state, String valueIdentity ) @@ -64,93 +103,99 @@ class MixinTable InsertSetMoreStep<Record> primaryTable = dsl.insertInto( mixinTable ) .set( identityColumn, valueIdentity ) - .set( createdColumn, new Timestamp( System.currentTimeMillis() ) ) - .set( modifiedColumn, new Timestamp( System.currentTimeMillis() ) ); + .set( createdColumn, new Timestamp( System.currentTimeMillis() ) ); - EntityDescriptor entityDescriptor = state.entityDescriptor(); - entityDescriptor.valueType().properties() - .filter( this::isThisMixin ) - .forEach( propDescriptor -> + properties.forEach( ( propertyName, propertyField ) -> primaryTable.set( propertyField, state.propertyValueOf( propertyName ) ) ); + associations.forEach( ( assocName, assocField ) -> + { + EntityReference reference = state.associationValueOf( assocName ); + String identity = null; + if( reference != null ) { - QualifiedName propertyName = propDescriptor.qualifiedName(); - Field<Object> propertyField = types.fieldOf( propDescriptor ); - primaryTable.set( propertyField, state.propertyValueOf( propertyName ) ); + identity = reference.identity().toString(); } - ); - entityDescriptor.valueType().associations() - .filter( this::isThisMixin ) - .forEach( assocDescriptor -> - { - QualifiedName assocName = assocDescriptor.qualifiedName(); - Field<String> assocField = types.fieldOf( assocDescriptor ); - EntityReference reference = state.associationValueOf( assocName ); - String identity = null; - if( reference != null ) - { - identity = reference.identity().toString(); - } - primaryTable.set( assocField, identity ); - } - ); + primaryTable.set( assocField, identity ); + } + ); + int result = primaryTable.execute(); if( mixinAssocsTable != null ) { - entityDescriptor.valueType().manyAssociations() - .filter( this::isThisMixin ) - .forEach( setManyAssociations( state, valueIdentity ) ); - - entityDescriptor.valueType().namedAssociations() - .filter( this::isThisMixin ) - .forEach( setNamedAssociations( state, valueIdentity ) ); + insertManyAndNamedAssociations( state, valueIdentity ); } } - private Consumer<? super AssociationDescriptor> setManyAssociations( DefaultEntityState state, String valueIdentity ) + private void insertManyAndNamedAssociations( DefaultEntityState state, String valueIdentity ) { - return assocDescriptor -> - { - QualifiedName assocName = assocDescriptor.qualifiedName(); - ManyAssociationState entityReferences = state.manyAssociationValueOf( assocName ); - entityReferences.stream().forEach( setManyAssociation( state, assocDescriptor, valueIdentity ) ); - }; + InsertSetStep<Record> assocsTable = dsl.insertInto( mixinAssocsTable ); + manyAssociations.forEach( assocName -> + { + ManyAssociationState entityReferences = state.manyAssociationValueOf( assocName ); + entityReferences.stream().forEach( setManyAssociation( assocName, valueIdentity, assocsTable ) ); + } ); + + namedAssociations.forEach( assocName -> + { + NamedAssociationState entityReferences = state.namedAssociationValueOf( assocName ); + entityReferences.stream().forEach( setNamedAssociation( assocName, valueIdentity, assocsTable ) ); + } ); + + InsertSetMoreStep<Record> assocs = assocsTable.set( Collections.emptyMap() ); + assocs.execute(); } - private Consumer<? super EntityReference> setManyAssociation( DefaultEntityState state, - AssociationDescriptor assocDescriptor, - String valueIdentity ) + Table<Record> associationsTable() { - QualifiedName assocName = assocDescriptor.qualifiedName(); - Field<String> assocField = types.fieldOf( assocDescriptor ); - InsertSetMoreStep<Record> assocsTable = dsl.insertInto( mixinAssocsTable ).set( identityColumn, valueIdentity ); - return ref -> - { - assocsTable.newRecord(); - assocsTable.set( assocField, state.associationValueOf( assocName ).identity().toString() ); - }; + return mixinAssocsTable; } - private Consumer<? super AssociationDescriptor> setNamedAssociations( DefaultEntityState state, - String valueIdentity ) + /** + * Writes one ManyAssoc Reference to the _ASSOCS table. + * <ul> + * <li>identityColumn - valueIdentity of primaryTable row</li> + * <li>nameColumn - index in the of association in state holder</li> + * <li>indexColumn - the position within the many association, starting at 0</li> + * <li>referenceColumn - referenced entity's identity</li> + * </ul> + */ + private Consumer<? super EntityReference> setManyAssociation( QualifiedName assocName, + String valueIdentity, + InsertSetStep<Record> assocsTable ) { - return assocDescriptor -> + return new Consumer<EntityReference>() { - QualifiedName assocName = assocDescriptor.qualifiedName(); - NamedAssociationState entityReferences = state.namedAssociationValueOf( assocName ); - entityReferences.stream().forEach( setNamedAssociation( state, assocDescriptor, valueIdentity ) ); + private int counter = 0; + + @Override + public void accept( EntityReference ref ) + { + InsertSetMoreStep<Record> set = assocsTable.set( identityColumn, valueIdentity ) + .set( nameColumn, assocName.name() ) + .set( indexColumn, "" + counter++ ) + .set( referenceColumn, ref == null ? null : ref.identity().toString() ); + } }; } - private Consumer<? super Map.Entry<String, EntityReference>> setNamedAssociation( DefaultEntityState state, - AssociationDescriptor assocDescriptor, - String valueIdentity ) + /** + * Writes one Named Reference to the _ASSOCS table. + * <ul> + * <li>identityColumn - valueIdentity of primaryTable row</li> + * <li>nameColumn - name of association in state holder</li> + * <li>indexColumn - the key/lookup name of the reference</li> + * <li>referenceColumn - referenced entity's identity</li> + * </ul> + */ + private Consumer<? super Map.Entry<String, EntityReference>> setNamedAssociation( QualifiedName assocName, + String valueIdentity, + InsertSetStep<Record> assocsTable ) { - QualifiedName assocName = assocDescriptor.qualifiedName(); - Field<String> assocField = types.fieldOf( assocDescriptor ); - InsertSetMoreStep<Record> assocsTable = dsl.insertInto( mixinAssocsTable ).set( identityColumn, valueIdentity ); return ref -> { - assocsTable.newRecord(); - assocsTable.set( assocField, state.associationValueOf( assocName ).identity().toString() ); + InsertSetMoreStep<Record> set = assocsTable.set( identityColumn, valueIdentity ) + .set( nameColumn, assocName.name() ) + .set( indexColumn, ref.getKey() ) + .set( referenceColumn, ref.getValue().identity().toString() ); }; } @@ -186,9 +231,31 @@ class MixinTable throw new UnsupportedOperationException( "Property declared as " + accessor.getClass() + " is not supported in this Entity Store yet." ); } - void modifyMixinState( Class<?> mixinType, DefaultEntityState state ) + void modifyMixinState( DefaultEntityState state, String valueId ) { + UpdateSetMoreStep<Record> primaryTable = + dsl.update( mixinTable ) + .set( Collections.emptyMap() ); // empty map is a hack to get the right type returned from JOOQ. + + properties.forEach( ( propertyName, propertyField ) -> primaryTable.set( propertyField, state.propertyValueOf( propertyName ) ) ); + associations.forEach( ( assocName, assocField ) -> + { + EntityReference reference = state.associationValueOf( assocName ); + primaryTable.set( assocField, + reference == null ? null : reference.identity().toString() + ); + } + ); + int result = primaryTable.execute(); + if( mixinAssocsTable != null ) + { + // Need to remove existing records. + dsl.delete( mixinAssocsTable ) + .where( identityColumn.eq( valueId ) ) + .execute(); + insertManyAndNamedAssociations( state, valueId ); + } } private Table<Record> getAssocsTable( EntityDescriptor descriptor, Schema schema ) http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlTable.java ---------------------------------------------------------------------- diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlTable.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlTable.java index 2801f57..13b6c37 100644 --- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlTable.java +++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlTable.java @@ -18,6 +18,7 @@ package org.apache.polygene.entitystore.jooq; import java.util.function.Consumer; +import java.util.stream.Stream; import javax.sql.DataSource; import org.apache.polygene.api.PolygeneAPI; import org.apache.polygene.api.composite.TransientBuilderFactory; @@ -99,14 +100,20 @@ public interface SqlTable extends ServiceActivation SelectQuery<Record> createGetEntityQuery( EntityDescriptor descriptor, EntityReference reference ); - void fetchAssociations( Record record, Consumer<AssociationValue> consume ); + void fetchAssociations( BaseEntity entity, EntityDescriptor descriptor, Consumer<AssociationValue> consume ); void createNewBaseEntity( EntityReference ref, EntityDescriptor descriptor, EntityStoreUnitOfWork unitOfWork ); - void insertEntity( DefaultEntityState state ); + void insertEntity( DefaultEntityState state, BaseEntity baseEntity, EntityStoreUnitOfWork unitOfWork ); + + void updateEntity( DefaultEntityState state, BaseEntity baseEntity, EntityStoreUnitOfWork unitOfWork ); JooqDslContext jooqDslContext(); + void removeEntity( EntityReference entityReference, EntityDescriptor descriptor ); + + Stream<BaseEntity> fetchAll( EntityDescriptor type, ModuleDescriptor module ); + class Mixin implements SqlTable, TableFields, ServiceActivation { @@ -143,15 +150,21 @@ public interface SqlTable extends ServiceActivation } @Override + public Stream<BaseEntity> fetchAll( EntityDescriptor type, ModuleDescriptor module ) + { + return entitiesTable.fetchAll( type, module ); + } + + @Override public SelectQuery<Record> createGetEntityQuery( EntityDescriptor descriptor, EntityReference reference ) { return entitiesTable.createGetEntityQuery( descriptor, reference ); } @Override - public void fetchAssociations( Record record, Consumer<AssociationValue> consume ) + public void fetchAssociations( BaseEntity entity, EntityDescriptor descriptor, Consumer<AssociationValue> consume ) { - entitiesTable.fetchAssociations( record, consume ); + entitiesTable.fetchAssociations( entity, descriptor, consume ); } @Override @@ -161,9 +174,15 @@ public interface SqlTable extends ServiceActivation } @Override - public void insertEntity( DefaultEntityState state ) + public void insertEntity( DefaultEntityState state, BaseEntity baseEntity, EntityStoreUnitOfWork unitOfWork ) { - entitiesTable.insertEntity( state ); + entitiesTable.insertEntity( state, baseEntity ); + } + + @Override + public void updateEntity( DefaultEntityState state, BaseEntity baseEntity, EntityStoreUnitOfWork unitOfWork ) + { + entitiesTable.modifyEntity( state, baseEntity, unitOfWork ); } @Override @@ -173,6 +192,12 @@ public interface SqlTable extends ServiceActivation } @Override + public void removeEntity( EntityReference reference, EntityDescriptor descriptor ) + { + entitiesTable.removeEntity( reference, descriptor ); + } + + @Override public void activateService() throws Exception { http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TableFields.java ---------------------------------------------------------------------- diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TableFields.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TableFields.java index 2454ae4..db42413 100644 --- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TableFields.java +++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TableFields.java @@ -25,23 +25,23 @@ import static org.apache.polygene.entitystore.jooq.TypesTable.makeField; public interface TableFields { // Common in all tables - String IDENTITY_COLUMN_NAME = "identity"; - String CREATED_COLUMN_NAME = "created_at"; - String LASTMODIFIED_COLUMN_NAME = "modified_at"; + String IDENTITY_COLUMN_NAME = "_identity"; + String CREATED_COLUMN_NAME = "_created_at"; + String LASTMODIFIED_COLUMN_NAME = "_modified_at"; // Types Table - String TABLENAME_COLUMN_NAME = "table_name"; + String TABLENAME_COLUMN_NAME = "_table_name"; // Entities Table - String VALUEID_COLUMN_NAME = "value_id"; - String TYPE_COLUMN_NAME = "type"; - String VERSION_COLUMN_NAME = "version"; - String APPLICATIONVERSION_COLUMN_NAME = "app_version"; + String VALUEID_COLUMN_NAME = "_value_id"; + String TYPE_COLUMN_NAME = "_type"; + String VERSION_COLUMN_NAME = "_version"; + String APPLICATIONVERSION_COLUMN_NAME = "_app_version"; // Mixin Tables - String NAME_COLUMN_NAME = "name"; - String INDEX_COLUMN_NAME = "index"; // either index in ManyAssociation or name in NamedAssociation - String REFERENCE_COLUMN_NAME = "reference"; + String NAME_COLUMN_NAME = "_name"; + String INDEX_COLUMN_NAME = "_index"; // either index in ManyAssociation or name in NamedAssociation + String REFERENCE_COLUMN_NAME = "_reference"; String ASSOCS_TABLE_POSTFIX = "_ASSOCS"; http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TypesTable.java ---------------------------------------------------------------------- diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TypesTable.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TypesTable.java index 4672d4f..c816c95 100644 --- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TypesTable.java +++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TypesTable.java @@ -110,12 +110,14 @@ public class TypesTable { String mixinTypeName = mixinType.getName(); String tableName = createNewTableName( mixinType ); - CreateTableColumnStep primaryTable = dsl.createTable( tableName ).column( identityColumn ); + CreateTableColumnStep primaryTable = dsl.createTable( DSL.name( schema.getName(), tableName ) ) + .column( identityColumn ) + .column( createdColumn ); descriptor.state().properties().forEach( property -> { QualifiedName qualifiedName = property.qualifiedName(); - if( qualifiedName.toNamespace().equals( mixinTypeName ) ) + if( qualifiedName.type().replace( '-', '$' ).equals( mixinTypeName ) ) { primaryTable.column( fieldOf( property ) ); } @@ -124,12 +126,12 @@ public class TypesTable assoc -> { QualifiedName qualifiedName = assoc.qualifiedName(); - if( qualifiedName.toNamespace().equals( mixinTypeName ) ) + if( qualifiedName.type().replace( '-', '$' ).equals( mixinTypeName ) ) { primaryTable.column( fieldOf( assoc ) ); } } ); - + int result1 = primaryTable.execute(); int result3 = dsl.insertInto( typesTable ) .set( identityColumn, mixinTypeName ) .set( tableNameColumn, tableName ) http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/src/test/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreTest.java ---------------------------------------------------------------------- diff --git a/extensions/entitystore-jooq/src/test/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreTest.java b/extensions/entitystore-jooq/src/test/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreTest.java index e097662..f36db0e 100644 --- a/extensions/entitystore-jooq/src/test/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreTest.java +++ b/extensions/entitystore-jooq/src/test/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreTest.java @@ -29,22 +29,13 @@ import org.apache.polygene.library.sql.dbcp.DBCPDataSourceServiceAssembler; import org.apache.polygene.test.EntityTestAssembler; import org.apache.polygene.test.entity.AbstractEntityStoreTest; import org.jooq.SQLDialect; +import org.junit.Rule; +import org.junit.rules.TemporaryFolder; public class JooqEntityStoreTest extends AbstractEntityStoreTest { -// @ClassRule -// public static final DockerRule DOCKER = new DockerRule( -// "mysql", -// new HashMap<String, String>() -// {{ -// put( "MYSQL_ROOT_PASSWORD", "" ); -// put( "MYSQL_ALLOW_EMPTY_PASSWORD", "yes" ); -// put( "MYSQL_DATABASE", "jdbc_test_db" ); -// put( "MYSQL_ROOT_HOST", "127.0.0.1" ); -// }}, -// 30000L -//// , "mysqld: ready for connections" TODO: add this after next release of tdomzal/junit-docker-rule -// ); + @Rule + public final TemporaryFolder tmpDir = new TemporaryFolder(); @Override // START SNIPPET: assembly @@ -83,8 +74,6 @@ public class JooqEntityStoreTest extends AbstractEntityStoreTest .declareDefaults(); jooqDefaults.entitiesTableName().set( "ENTITIES" ); - String path = System.getProperty( "user.dir" ) + "/testdb"; - System.out.println("Niclas: " + path); DataSourceConfiguration dsDefaults = config.forMixin( DataSourceConfiguration.class ).declareDefaults(); dsDefaults.driver().set( org.h2.Driver.class.getName() ); dsDefaults.enabled().set( true ); @@ -92,7 +81,7 @@ public class JooqEntityStoreTest extends AbstractEntityStoreTest dsDefaults.minPoolSize().set( 1 ); dsDefaults.username().set( "" ); dsDefaults.password().set( "" ); - dsDefaults.url().set( "jdbc:h2:"+path+";create=true" ); + dsDefaults.url().set( "jdbc:h2:" + tmpDir.getRoot().getAbsolutePath() + "/testdb;create=true" ); // START SNIPPET: assembly } // END SNIPPET: assembly http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/manual/src/docs/userguide/extensions.txt ---------------------------------------------------------------------- diff --git a/manual/src/docs/userguide/extensions.txt b/manual/src/docs/userguide/extensions.txt index 44bfd3f..5026259 100644 --- a/manual/src/docs/userguide/extensions.txt +++ b/manual/src/docs/userguide/extensions.txt @@ -105,6 +105,10 @@ include::../../../../extensions/entitystore-riak/src/docs/es-riak.txt[] :leveloffset: 2 +include::../../../../extensions/entitystore-jooq/src/docs/es-jooq.txt[] + +:leveloffset: 2 + include::../../../../extensions/entitystore-sql/src/docs/es-sql.txt[] :leveloffset: 2
