Repository: polygene-java Updated Branches: refs/heads/develop 0ef97e94d -> e2b886613
Introducing the beginning of an SQL entity store that is "enterprisey", laid out in a table per type, with manyassociations in mapping tables and so on. 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/c3d8e013 Tree: http://git-wip-us.apache.org/repos/asf/polygene-java/tree/c3d8e013 Diff: http://git-wip-us.apache.org/repos/asf/polygene-java/diff/c3d8e013 Branch: refs/heads/develop Commit: c3d8e013009eafd7f74344d4f08f66f0636e0a4c Parents: 718fa57 Author: niclas <[email protected]> Authored: Fri May 12 14:18:16 2017 +0800 Committer: niclas <[email protected]> Committed: Fri May 12 14:18:16 2017 +0800 ---------------------------------------------------------------------- extensions/entitystore-jooq/build.gradle | 44 +++ extensions/entitystore-jooq/dev-status.xml | 38 ++ extensions/entitystore-jooq/src/docs/es-orm.txt | 58 +++ .../entitystore/jooq/AssociationValue.java | 25 ++ .../polygene/entitystore/jooq/BaseEntity.java | 16 + .../entitystore/jooq/JooqDslContext.java | 44 +++ .../jooq/JooqEntityStoreConfiguration.java | 62 ++++ .../entitystore/jooq/JooqEntityStoreMixin.java | 198 +++++++++++ .../jooq/JooqEntityStoreService.java | 36 ++ .../polygene/entitystore/jooq/SqlTable.java | 356 +++++++++++++++++++ .../polygene/entitystore/jooq/SqlType.java | 148 ++++++++ .../jooq/assembly/JooqEntityStoreAssembler.java | 74 ++++ .../entitystore/jooq/JooqEntityStoreTest.java | 71 ++++ settings.gradle | 1 + 14 files changed, 1171 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c3d8e013/extensions/entitystore-jooq/build.gradle ---------------------------------------------------------------------- diff --git a/extensions/entitystore-jooq/build.gradle b/extensions/entitystore-jooq/build.gradle new file mode 100644 index 0000000..32ceb70 --- /dev/null +++ b/extensions/entitystore-jooq/build.gradle @@ -0,0 +1,44 @@ +/* + * 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. + * + * + */ + +apply plugin: 'polygene-extension' + +description = "Apache Polygene⢠ORM EntityStore Extension" + +jar { manifest { name = "Apache Polygene⢠Extension - EntityStore - ORM" } } + +dependencies { + api polygene.core.bootstrap + api polygene.library( 'sql' ) + api libraries.jooq + + runtimeOnly polygene.core.runtime + + testImplementation polygene.internals.testsupport + testImplementation polygene.library( 'sql-dbcp' ) + testImplementation libraries.docker_junit + + testRuntimeOnly libraries.logback + testRuntimeOnly libraries.derby + testRuntimeOnly libraries.h2 + testRuntimeOnly libraries.mysql_connector + testRuntimeOnly libraries.postgres + testRuntimeOnly libraries.sqlite +} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c3d8e013/extensions/entitystore-jooq/dev-status.xml ---------------------------------------------------------------------- diff --git a/extensions/entitystore-jooq/dev-status.xml b/extensions/entitystore-jooq/dev-status.xml new file mode 100644 index 0000000..0914c52 --- /dev/null +++ b/extensions/entitystore-jooq/dev-status.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!-- + ~ 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. + ~ + ~ + --> +<module xmlns="http://polygene.apache.org/schemas/2008/dev-status/1" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + 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, brief, good, complete --> + <documentation>good</documentation> + + <!-- 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/c3d8e013/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 new file mode 100644 index 0000000..413eb7b --- /dev/null +++ b/extensions/entitystore-jooq/src/docs/es-orm.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-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/c3d8e013/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 new file mode 100644 index 0000000..81331cf --- /dev/null +++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/AssociationValue.java @@ -0,0 +1,25 @@ +/* + * 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. + */ +package org.apache.polygene.entitystore.jooq; + +class AssociationValue +{ + String name; + String position; + String reference; +} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c3d8e013/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 new file mode 100644 index 0000000..07fb05c --- /dev/null +++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/BaseEntity.java @@ -0,0 +1,16 @@ +package org.apache.polygene.entitystore.jooq; + +import java.time.Instant; +import org.apache.polygene.api.entity.EntityDescriptor; +import org.apache.polygene.api.identity.Identity; + +class BaseEntity +{ + EntityDescriptor type; + Identity identity; + String version; + String applicationVersion; + Instant modifedAt; + Instant createdAt; + Identity currentValueIdentity; +} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c3d8e013/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqDslContext.java ---------------------------------------------------------------------- diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqDslContext.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqDslContext.java new file mode 100644 index 0000000..8737936 --- /dev/null +++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqDslContext.java @@ -0,0 +1,44 @@ +package org.apache.polygene.entitystore.jooq; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import javax.sql.DataSource; +import org.apache.polygene.api.injection.scope.Service; +import org.apache.polygene.api.injection.scope.Uses; +import org.apache.polygene.api.mixin.Mixins; +import org.apache.polygene.api.service.ServiceDescriptor; +import org.jooq.Configuration; +import org.jooq.DSLContext; +import org.jooq.SQLDialect; +import org.jooq.conf.Settings; +import org.jooq.impl.DSL; +import org.jooq.impl.DefaultConfiguration; + +@Mixins( JooqDslContext.Mixin.class ) +public interface JooqDslContext extends DSLContext +{ + + class Mixin + implements InvocationHandler + { + private DSLContext dsl; + + public Mixin( @Service DataSource dataSource, @Uses ServiceDescriptor serviceDescriptor ) + { + Settings settings = serviceDescriptor.metaInfo( Settings.class ); + SQLDialect sqlDialect = serviceDescriptor.metaInfo( SQLDialect.class ); + Configuration configuration = new DefaultConfiguration() + .set( dataSource ) + .set( sqlDialect ) + .set( settings ); + dsl = DSL.using( configuration ); + } + + @Override + public Object invoke( Object o, Method method, Object[] objects ) + throws Throwable + { + return method.invoke( dsl, objects ); // delegate all + } + } +} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c3d8e013/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreConfiguration.java ---------------------------------------------------------------------- diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreConfiguration.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreConfiguration.java new file mode 100644 index 0000000..e3a79f6 --- /dev/null +++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreConfiguration.java @@ -0,0 +1,62 @@ +/* + * 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. + */ +package org.apache.polygene.entitystore.jooq; + +import org.apache.polygene.api.common.UseDefaults; +import org.apache.polygene.api.property.Property; +import org.apache.polygene.library.sql.common.SQLConfiguration; + +// START SNIPPET: config +public interface JooqEntityStoreConfiguration extends SQLConfiguration +{ + /** + * Name of the database schema to use. + * Ignored on SQL databases that don't support schemas. + */ + @UseDefaults( "POLYGENE" ) + @Override + Property<String> schemaName(); + + /** + * Name of the entities table. + * <p> + * This table contains the Identity and other metadata about each entity instance + * </p> + */ + @UseDefaults( "ENTITIES" ) + Property<String> entitiesTableName(); + + /** + * Name of the entity types table. + * <p> + * This table contains the metainfo about each type. Types are versioned according to + * application version, to support entity migration over time, and therefor there might + * be (but not necessarily) multiple tables for entity types that has evolved beyond + * what can be managed within a single table. + * </p> + */ + @UseDefaults( "TYPES" ) + Property<String> typesTableName(); + + /** + * Defines whether the database schema and table should be created if not already present. + */ + @UseDefaults( "true" ) + Property<Boolean> createIfMissing(); +} +// END SNIPPET: config http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c3d8e013/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 new file mode 100644 index 0000000..8974181 --- /dev/null +++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreMixin.java @@ -0,0 +1,198 @@ +/* + * 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. + */ +package org.apache.polygene.entitystore.jooq; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; +import org.apache.polygene.api.association.AssociationDescriptor; +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.IdentityGenerator; +import org.apache.polygene.api.injection.scope.Service; +import org.apache.polygene.api.injection.scope.Structure; +import org.apache.polygene.api.injection.scope.This; +import org.apache.polygene.api.structure.ModuleDescriptor; +import org.apache.polygene.api.usecase.Usecase; +import org.apache.polygene.spi.PolygeneSPI; +import org.apache.polygene.spi.entity.EntityState; +import org.apache.polygene.spi.entity.EntityStatus; +import org.apache.polygene.spi.entitystore.DefaultEntityStoreUnitOfWork; +import org.apache.polygene.spi.entitystore.EntityNotFoundException; +import org.apache.polygene.spi.entitystore.EntityStore; +import org.apache.polygene.spi.entitystore.EntityStoreSPI; +import org.apache.polygene.spi.entitystore.EntityStoreUnitOfWork; +import org.apache.polygene.spi.entitystore.StateCommitter; +import org.apache.polygene.spi.entitystore.helpers.DefaultEntityState; +import org.jooq.Record; +import org.jooq.Result; +import org.jooq.SelectQuery; + +import static org.apache.polygene.api.entity.EntityReference.parseEntityReference; + +public class JooqEntityStoreMixin + implements EntityStore, EntityStoreSPI +{ + + @Structure + private PolygeneSPI spi; + + @This + private SqlType sqlType; + + @This + private SqlTable sqlTable; + + @This + private JooqDslContext jooqDslContext; + + @Service + private IdentityGenerator identityGenerator; + + @Override + public EntityState newEntityState( EntityStoreUnitOfWork unitOfWork, EntityReference reference, EntityDescriptor entityDescriptor ) + { + return new DefaultEntityState( unitOfWork.currentTime(), reference, entityDescriptor ); + } + + @Override + public EntityState entityStateOf( EntityStoreUnitOfWork unitOfWork, ModuleDescriptor module, EntityReference reference ) + { + BaseEntity baseEntity = sqlTable.fetchBaseEntity( reference, module ); + SelectQuery<Record> selectQuery = sqlTable.createGetEntityQuery( baseEntity.type, reference ); + Result<Record> result = selectQuery.fetch(); + if( result.isEmpty() ) + { + throw new EntityNotFoundException( 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 ); + } ); + 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 ) ); + } ); + 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 ); + } + } ); + } ); + + return new DefaultEntityState( baseEntity.version, + baseEntity.modifedAt, + reference, + EntityStatus.LOADED, + baseEntity.type, + properties, + assocations, + manyAssocs, + namedAssocs ); + } + + private void addNamedAssociation( AssociationStateDescriptor stateDescriptor, Map<QualifiedName, Map<String, EntityReference>> namedAssocs, AssociationValue associationValue ) + { + AssociationDescriptor descriptor = stateDescriptor.getNamedAssociationByName( associationValue.name ); + QualifiedName qualifiedName = descriptor.qualifiedName(); + Map<String, EntityReference> map = namedAssocs.computeIfAbsent( qualifiedName, k -> new HashMap<>() ); + map.put( associationValue.position, parseEntityReference( associationValue.reference ) ); + } + + private void addManyAssociation( AssociationStateDescriptor stateDescriptor, Map<QualifiedName, List<EntityReference>> manyAssocs, AssociationValue associationValue ) + { + AssociationDescriptor descriptor = stateDescriptor.getManyAssociationByName( associationValue.name ); + QualifiedName qualifiedName = descriptor.qualifiedName(); + List<EntityReference> list = manyAssocs.computeIfAbsent( qualifiedName, k -> new ArrayList<>() ); + list.add( parseEntityReference( associationValue.reference ) ); + } + + @Override + public String versionOf( EntityStoreUnitOfWork unitOfWork, EntityReference reference ) + { + BaseEntity baseEntity = sqlTable.fetchBaseEntity( reference, unitOfWork.module() ); + return baseEntity.version; + } + + @Override + public StateCommitter applyChanges( EntityStoreUnitOfWork unitOfWork, Iterable<EntityState> state ) + { + return new JooqStateCommitter( unitOfWork, state ); + } + + @Override + public EntityStoreUnitOfWork newUnitOfWork( ModuleDescriptor module, Usecase usecase, Instant currentTime ) + { + return new DefaultEntityStoreUnitOfWork( module, + this, + identityGenerator.generate( JooqEntityStoreService.class ), + usecase, + currentTime + ); + } + + @Override + public Stream<EntityState> entityStates( ModuleDescriptor module ) + { + return null; + } + + private static class JooqStateCommitter + implements StateCommitter + { + public JooqStateCommitter( EntityStoreUnitOfWork unitOfWork, Iterable<EntityState> state ) + { + + } + + @Override + public void commit() + { + + } + + @Override + public void cancel() + { + + } + } +} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c3d8e013/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreService.java ---------------------------------------------------------------------- diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreService.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreService.java new file mode 100644 index 0000000..0259151 --- /dev/null +++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreService.java @@ -0,0 +1,36 @@ +/* + * 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. + */ +package org.apache.polygene.entitystore.jooq; + +import org.apache.polygene.api.concern.Concerns; +import org.apache.polygene.api.configuration.Configuration; +import org.apache.polygene.api.mixin.Mixins; +import org.apache.polygene.spi.entitystore.ConcurrentModificationCheckConcern; +import org.apache.polygene.spi.entitystore.EntityStateVersions; +import org.apache.polygene.spi.entitystore.EntityStore; +import org.apache.polygene.spi.entitystore.StateChangeNotificationConcern; + +/** + * SQL EntityStore service. + */ +@Concerns( { StateChangeNotificationConcern.class, ConcurrentModificationCheckConcern.class } ) +@Mixins( { JooqEntityStoreMixin.class } ) +public interface JooqEntityStoreService + extends EntityStore, EntityStateVersions, Configuration +{ +} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c3d8e013/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 new file mode 100644 index 0000000..1cf0c1c --- /dev/null +++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlTable.java @@ -0,0 +1,356 @@ +/* + * 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. + */ +package org.apache.polygene.entitystore.jooq; + +import java.lang.reflect.Method; +import java.time.Instant; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import org.apache.polygene.api.configuration.Configuration; +import org.apache.polygene.api.entity.EntityDescriptor; +import org.apache.polygene.api.entity.EntityReference; +import org.apache.polygene.api.injection.scope.This; +import org.apache.polygene.api.injection.scope.Uses; +import org.apache.polygene.api.mixin.Mixins; +import org.apache.polygene.api.property.Property; +import org.apache.polygene.api.property.PropertyDescriptor; +import org.apache.polygene.api.service.ServiceActivation; +import org.apache.polygene.api.service.ServiceDescriptor; +import org.apache.polygene.api.structure.ModuleDescriptor; +import org.apache.polygene.api.type.ValueType; +import org.apache.polygene.api.unitofwork.NoSuchEntityTypeException; +import org.apache.polygene.spi.entitystore.EntityNotFoundException; +import org.jooq.Condition; +import org.jooq.CreateTableAsStep; +import org.jooq.Field; +import org.jooq.Record; +import org.jooq.Result; +import org.jooq.SQLDialect; +import org.jooq.Schema; +import org.jooq.SelectJoinStep; +import org.jooq.SelectQuery; +import org.jooq.Table; +import org.jooq.impl.DSL; + +@Mixins( SqlTable.Mixin.class ) +public interface SqlTable +{ + String IDENTITY_COLUMN_NAME = "identity"; + String VALUEID_COLUMN_NAME = "value_id"; + String VERSION_COLUMN_NAME = "version"; + String APPLICATIONVERSION_COLUMN_NAME = "app_version"; + String TYPE_COLUMN_NAME = "type"; + String LASTMODIFIED_COLUMN_NAME = "modified_at"; + String CREATED_COLUMN_NAME = "created_at"; + String TABLENAME_COLUMN_NAME = "table_name"; + String ASSOCIATIONS_COLUMN_NAME = "assocations"; + String POSITION_COLUMN_NAME = "position"; + + String createNewTableName( Class<?> type ); + + Result<Record> createNewTable( Class<?> mixinType, EntityDescriptor descriptor ); + + boolean isProperty( Method method ); + + Table<Record> findTable( Class<?> type, EntityDescriptor descriptor ); + + Table<Record> createTable( Class<?> type, EntityDescriptor descriptor ); + + String findTableName( Class<?> type, EntityDescriptor descriptor ); + + List<Table<Record>> getTableJoins( EntityDescriptor entityDescriptor ); + + Result<Record> fetchTypeInfoFromTable( Class<?> entityType ); + + BaseEntity fetchBaseEntity( EntityReference reference, ModuleDescriptor module ); + + EntityDescriptor findEntityDescriptor( String typeName, ModuleDescriptor module ); + + Record createNewBaseEntity( EntityReference reference, EntityDescriptor descriptor ); + + SelectQuery<Record> createGetEntityQuery( EntityDescriptor entityDescriptor, EntityReference reference ); + + void fetchAssociations( Record record, Consumer<AssociationValue> consume ); + + class Mixin + implements SqlTable, ServiceActivation + { + + @This + JooqDslContext dsl; + + @This + private Configuration<JooqEntityStoreConfiguration> configuration; + + @This + private SqlType sqlType; + + @Uses + private ServiceDescriptor serviceDescriptor; + + private Table<Record> typesTable; + private Table<Record> entitiesTable; + private Map<Class, Table<Record>> entityTables; + private Field<String> identityColumn; + private Field<String> valueIdentityColumn; + private Field<String> typeColumn; + private Field<String> versionColumn; + private Field<String> applicationVersionColumn; + private Field<Instant> modifiedColumn; + private Field<Instant> createdColumn; + private Field<String> tableNameColumn; + private Field<String> assocationsColumn; + private Field<String> positionColumn; + + private Schema schema; + + private SQLDialect dialect; + + @Override + public void activateService() + throws Exception + { + configuration.refresh(); + JooqEntityStoreConfiguration config = configuration.get(); + + // Prepare jooq DSL + dialect = serviceDescriptor.metaInfo( SQLDialect.class ); + + String schemaName = config.schemaName().get(); + String typesTableName = config.typesTableName().get(); + String entitiesTableName = config.entitiesTableName().get(); + schema = DSL.schema( DSL.name( schemaName ) ); + typesTable = DSL.table( + dialect.equals( SQLDialect.SQLITE ) + ? DSL.name( typesTableName ) + : DSL.name( schema.getName(), typesTableName ) + ); + entitiesTable = DSL.table( + dialect.equals( SQLDialect.SQLITE ) + ? DSL.name( entitiesTableName ) + : DSL.name( schema.getName(), entitiesTableName ) ); + + identityColumn = DSL.field( DSL.name( IDENTITY_COLUMN_NAME ), String.class ); + valueIdentityColumn = DSL.field( DSL.name( VALUEID_COLUMN_NAME ), String.class ); + versionColumn = DSL.field( DSL.name( VERSION_COLUMN_NAME ), String.class ); + applicationVersionColumn = DSL.field( DSL.name( APPLICATIONVERSION_COLUMN_NAME ), String.class ); + typeColumn = DSL.field( DSL.name( TYPE_COLUMN_NAME ), String.class ); + modifiedColumn = DSL.field( DSL.name( LASTMODIFIED_COLUMN_NAME ), Instant.class ); + createdColumn = DSL.field( DSL.name( CREATED_COLUMN_NAME ), Instant.class ); + tableNameColumn = DSL.field( DSL.name( TABLENAME_COLUMN_NAME ), String.class ); + assocationsColumn = DSL.field( DSL.name( ASSOCIATIONS_COLUMN_NAME ), String.class ); + positionColumn = DSL.field( DSL.name( POSITION_COLUMN_NAME ), String.class ); + + // Eventually create schema + if( config.createIfMissing().get() ) + { + if( !dialect.equals( SQLDialect.SQLITE ) + && dsl.meta().getSchemas().stream().noneMatch( s -> schema.getName().equalsIgnoreCase( s.getName() ) ) ) + { + dsl.createSchema( schema ).execute(); + } + } + } + + @Override + public BaseEntity fetchBaseEntity( EntityReference reference, ModuleDescriptor module ) + { + BaseEntity result = new BaseEntity(); + + Result<Record> baseEntityResult = dsl + .select() + .from( entitiesTable ) + .where( identityColumn.eq( reference.toURI() ) ) + .fetch(); + + if( baseEntityResult.isEmpty() ) + { + throw new EntityNotFoundException( reference ); + } + Record baseEntity = baseEntityResult.get( 0 ); + String typeName = baseEntity.field( typeColumn ).get( baseEntity ); + 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 = baseEntity.field( modifiedColumn ).get( baseEntity ); + result.createdAt = baseEntity.field( createdColumn ).get( baseEntity ); + return result; + } + + @Override + public void passivateService() + throws Exception + { + schema = null; + } + + public Result<Record> fetchTypeInfoFromTable( Class<?> entityType ) + { + return dsl + .select() + .from( typesTable ) + .where( identityColumn.eq( entityType.getName() ) ) + .fetch(); + } + + public List<Table<Record>> getTableJoins( EntityDescriptor entityDescriptor ) + { + return entityDescriptor + .mixinTypes() + .map( ( Class<?> type ) -> findTable( type, entityDescriptor ) ) + .collect( Collectors.toList() ); + } + + public Table<Record> findTable( Class<?> type, EntityDescriptor descriptor ) + { + return entityTables.computeIfAbsent( type, t -> createTable( t, descriptor ) ); + } + + public Table<Record> createTable( Class<?> type, EntityDescriptor descriptor ) + { + String tableName = findTableName( type, descriptor ); + return null; + } + + public String findTableName( Class<?> type, EntityDescriptor descriptor ) + { + Result<Record> typeInfo = fetchTypeInfoFromTable( type ); + if( typeInfo.isEmpty() ) + { + typeInfo = createNewTable( type, descriptor ); + } + return typeInfo.getValue( 0, tableNameColumn ); + } + + @Override + public String createNewTableName( Class<?> type ) + { + return null; + } + + public Result<Record> createNewTable( Class<?> mixinType, EntityDescriptor descriptor ) + { + String tableName = createNewTableName( mixinType ); + CreateTableAsStep<Record> table = dsl.createTable( tableName ); + Arrays.stream( mixinType.getDeclaredMethods() ) + .filter( this::isProperty ) + .forEach( method -> + { + PropertyDescriptor propertyDescriptor = descriptor.state().findPropertyModelByName( method.getName() ); + ValueType valueType = propertyDescriptor.valueType(); + Class<?> propertyType = valueType.primaryType(); + String propertyName = method.getName(); + table.column( propertyName, sqlType.getSqlDataTypeFor( propertyType ) ); + } ); + + return fetchTypeInfoFromTable( mixinType ); + } + + public boolean isProperty( Method method ) + { + return Property.class.isAssignableFrom( method.getReturnType() ) && method.getParameterCount() == 0; + } + + public EntityDescriptor findEntityDescriptor( String typeName, ModuleDescriptor module ) + { + try + { + Class<?> type = getClass().getClassLoader().loadClass( typeName ); + return module.typeLookup().lookupEntityModel( type ); + } + catch( ClassNotFoundException e ) + { + throw new NoSuchEntityTypeException( typeName, module.name(), module.typeLookup() ); + } + } + + @Override + public Record createNewBaseEntity( EntityReference reference, EntityDescriptor descriptor ) + { + return null; + } + + /** + * Builds the SELECT statement for a given entity. + * <p> + * Example; If we have the following entity + * </p> + * <code><pre> + * public interface LegalEntity + * { + * Property<String> registration(); + * } + * <p> + * public interface Person extends LegalEntity + * { + * Property<String> name(); + * <p> + * @Optional + * Association<Person> spouse(); + * <p> + * ManyAssocation<Person> children(); + * } + * </pre></code> + * <p> + * and we do a simple; + * <code><pre> + * Person p = uow.get( Person.class, "niclas" ); + * </pre></code> + * <p> + * then the generated query will be + * </p> + * <code><pre> + * SELECT * FROM ENTITIES + * JOIN Person ON identity = ENTITIES.value_id + * JOIN LegalEntity ON identity = ENTITIES.value_id + * JOIN Person_Assoc ON identity = ENTITIES.value_id + * WHERE ENTITIES.identity = '123' + * </pre></code> + * + * @param entityDescriptor The descriptor of the entity type to be built. + * @return The SELECT query that can be executed to retrieve the entity. + */ + public SelectQuery<Record> createGetEntityQuery( EntityDescriptor entityDescriptor, EntityReference reference ) + { + 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 ) ); + from = from.join( joinedTable ).on( joinCondition ); + } + return from.where( identityColumn.eq( reference.identity().toString() ) ).getQuery(); + } + + @Override + public void fetchAssociations( Record record, Consumer<AssociationValue> consume ) + { + AssociationValue value = new AssociationValue(); + value.name = record.getValue( assocationsColumn ); + value.position = record.getValue( positionColumn ); + value.reference = record.getValue( this.assocationsColumn ); + consume.accept( value ); + } + } +} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c3d8e013/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlType.java ---------------------------------------------------------------------- diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlType.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlType.java new file mode 100644 index 0000000..c872d62 --- /dev/null +++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlType.java @@ -0,0 +1,148 @@ +/* + * 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. + */ +package org.apache.polygene.entitystore.jooq; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.Period; +import java.time.ZonedDateTime; +import org.apache.polygene.api.mixin.Mixins; +import org.jooq.DataType; +import org.jooq.impl.SQLDataType; +import org.jooq.types.Interval; + +@Mixins( SqlType.Mixin.class ) +public interface SqlType +{ + DataType<?> getSqlDataTypeFor( Class<?> propertyType ); + + class Mixin + implements SqlType + { + public DataType<?> getSqlDataTypeFor( Class<?> propertyType ) + { + if( String.class.isAssignableFrom( propertyType ) ) + { + return SQLDataType.VARCHAR; + } + if( Integer.class.isAssignableFrom( propertyType ) ) + { + return SQLDataType.INTEGER; + } + if( Long.class.isAssignableFrom( propertyType ) ) + { + return SQLDataType.BIGINT; + } + if( Boolean.class.isAssignableFrom( propertyType ) ) + { + return SQLDataType.BOOLEAN; + } + if( Float.class.isAssignableFrom( propertyType ) ) + { + return SQLDataType.FLOAT; + } + if( Double.class.isAssignableFrom( propertyType ) ) + { + return SQLDataType.DOUBLE; + } + if( Instant.class.isAssignableFrom( propertyType ) ) + { + return SQLDataType.TIMESTAMPWITHTIMEZONE; + } + if( Interval.class.isAssignableFrom( propertyType ) ) + { + return SQLDataType.VARCHAR; + } + if( Period.class.isAssignableFrom( propertyType ) ) + { + return SQLDataType.VARCHAR; + } + if( LocalDate.class.isAssignableFrom( propertyType ) ) + { + return SQLDataType.LOCALDATE; + } + if( LocalTime.class.isAssignableFrom( propertyType ) ) + { + return SQLDataType.LOCALTIME; + } + if( LocalDateTime.class.isAssignableFrom( propertyType ) ) + { + return SQLDataType.LOCALDATETIME; + } + if( ZonedDateTime.class.isAssignableFrom( propertyType ) ) + { + return SQLDataType.OFFSETDATETIME; + } + if( OffsetDateTime.class.isAssignableFrom( propertyType ) ) + { + return SQLDataType.OFFSETDATETIME; + } + if( Character.class.isAssignableFrom( propertyType ) ) + { + return SQLDataType.CHAR( 1 ); + } + if( Short.class.isAssignableFrom( propertyType ) ) + { + return SQLDataType.INTEGER; + } + if( Byte.class.isAssignableFrom( propertyType ) ) + { + return SQLDataType.INTEGER; + } + if( propertyType.isPrimitive() ) + { + if( propertyType.equals( Integer.TYPE ) ) + { + return SQLDataType.INTEGER; + } + if( propertyType.equals( Long.TYPE ) ) + { + return SQLDataType.BIGINT; + } + if( propertyType.equals( Boolean.TYPE ) ) + { + return SQLDataType.BOOLEAN; + } + if( propertyType.equals( Float.TYPE ) ) + { + return SQLDataType.FLOAT; + } + if( propertyType.equals( Double.TYPE ) ) + { + return SQLDataType.DOUBLE; + } + if( propertyType.equals( Character.TYPE ) ) + { + return SQLDataType.CHAR( 1 ); + } + if( propertyType.equals( Short.TYPE ) ) + { + return SQLDataType.INTEGER; + } + if( propertyType.equals( Byte.TYPE ) ) + { + return SQLDataType.INTEGER; + } + } + return SQLDataType.VARCHAR; + } + } +} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c3d8e013/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/assembly/JooqEntityStoreAssembler.java ---------------------------------------------------------------------- diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/assembly/JooqEntityStoreAssembler.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/assembly/JooqEntityStoreAssembler.java new file mode 100644 index 0000000..8a986a9 --- /dev/null +++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/assembly/JooqEntityStoreAssembler.java @@ -0,0 +1,74 @@ +/* + * 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. + * + * + */ +package org.apache.polygene.entitystore.jooq.assembly; + +import org.apache.polygene.api.identity.Identity; +import org.apache.polygene.api.identity.StringIdentity; +import org.apache.polygene.bootstrap.Assembler; +import org.apache.polygene.bootstrap.Assemblers; +import org.apache.polygene.bootstrap.AssemblyException; +import org.apache.polygene.bootstrap.ModuleAssembly; +import org.apache.polygene.entitystore.jooq.JooqEntityStoreConfiguration; +import org.apache.polygene.entitystore.jooq.JooqEntityStoreService; +import org.jooq.SQLDialect; +import org.jooq.conf.RenderNameStyle; +import org.jooq.conf.Settings; + +/** + * MySQL EntityStore assembly. + */ +public class JooqEntityStoreAssembler extends Assemblers.VisibilityIdentityConfig<JooqEntityStoreAssembler> + implements Assembler +{ + public static final Identity DEFAULT_ENTITYSTORE_IDENTITY = new StringIdentity( "entitystore-jooq" ); + + @Override + public void assemble( ModuleAssembly module ) + { + Settings settings = getSettings(); + if( settings == null ) + { + throw new AssemblyException( "Settings must not be null" ); + } + + String identity = ( hasIdentity() ? identity() : DEFAULT_ENTITYSTORE_IDENTITY ).toString(); + + module.services( JooqEntityStoreService.class ) + .identifiedBy( identity ) + .visibleIn( visibility() ) + .setMetaInfo( getSQLDialect() ) + .setMetaInfo( settings ); + + if( hasConfig() ) + { + configModule().entities( JooqEntityStoreConfiguration.class ).visibleIn( configVisibility() ); + } + } + + protected Settings getSettings() + { + return new Settings().withRenderNameStyle( RenderNameStyle.QUOTED ); + } + + protected SQLDialect getSQLDialect() + { + return SQLDialect.DEFAULT; + } +} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c3d8e013/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 new file mode 100644 index 0000000..8db2784 --- /dev/null +++ b/extensions/entitystore-jooq/src/test/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreTest.java @@ -0,0 +1,71 @@ +/* + * 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. + * + * + */ +package org.apache.polygene.entitystore.jooq; + +import java.util.HashMap; +import org.apache.polygene.api.common.Visibility; +import org.apache.polygene.bootstrap.AssemblyException; +import org.apache.polygene.bootstrap.ModuleAssembly; +import org.apache.polygene.entitystore.jooq.assembly.JooqEntityStoreAssembler; +import org.apache.polygene.test.EntityTestAssembler; +import org.apache.polygene.test.entity.AbstractEntityStoreTest; +import org.apache.polygene.test.internal.DockerRule; +import org.jooq.SQLDialect; +import org.junit.ClassRule; + +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", "172.17.0.1" ); + }}, + 30000L +// , "mysqld: ready for connections" TODO: add this after next release of tdomzal/junit-docker-rule + ); + + @Override + // START SNIPPET: assembly + public void assemble( ModuleAssembly module ) + throws AssemblyException + { + // END SNIPPET: assembly + super.assemble( module ); + ModuleAssembly config = module.layer().module( "config" ); + new EntityTestAssembler().visibleIn( Visibility.module ).assemble( config ); + + // START SNIPPET: assembly + new JooqEntityStoreAssembler() + .withConfig( config, Visibility.layer ) + .identifiedBy( "jooq-entitystore" ) + .assemble( module ); + // END SNIPPET: assembly + + config.forMixin( JooqEntityStoreConfiguration.class ).setMetaInfo( SQLDialect.MARIADB ); + // START SNIPPET: assembly + } + // END SNIPPET: assembly +} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c3d8e013/settings.gradle ---------------------------------------------------------------------- diff --git a/settings.gradle b/settings.gradle index 0cee4a7..13b502c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -61,6 +61,7 @@ include 'core:api', 'extensions:entitystore-hazelcast', 'extensions:entitystore-jclouds', 'extensions:entitystore-jdbm', + 'extensions:entitystore-jooq', 'extensions:entitystore-leveldb', 'extensions:entitystore-memory', 'extensions:entitystore-mongodb',
