You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polygene.apache.org by ni...@apache.org on 2017/10/26 07:34:37 UTC

[07/33] polygene-java git commit: Committing an intermediate state of the JOOQ ES, to dig into the classloading issue in the Service composition.

Committing an intermediate state of the JOOQ ES, to dig into the classloading issue in the Service composition.

Signed-off-by: niclas <ni...@hedhman.org>


Project: http://git-wip-us.apache.org/repos/asf/polygene-java/repo
Commit: http://git-wip-us.apache.org/repos/asf/polygene-java/commit/60d2eebd
Tree: http://git-wip-us.apache.org/repos/asf/polygene-java/tree/60d2eebd
Diff: http://git-wip-us.apache.org/repos/asf/polygene-java/diff/60d2eebd

Branch: refs/heads/develop
Commit: 60d2eebd709dc2eb7078b04a305aaba2e4485299
Parents: c2a30f7
Author: niclas <ni...@hedhman.org>
Authored: Fri Jun 9 11:40:09 2017 +0800
Committer: niclas <ni...@hedhman.org>
Committed: Fri Jun 9 11:40:09 2017 +0800

----------------------------------------------------------------------
 .../org/apache/polygene/api/PolygeneAPI.java    |   1 +
 .../api/association/AssociationDescriptor.java  |   8 +-
 .../api/property/PropertyDescriptor.java        |   8 +-
 .../runtime/methods/AccessibleTest.java         |  99 +++++
 .../polygene/entitystore/jooq/BaseEntity.java   |  17 +
 .../entitystore/jooq/EntitiesTable.java         | 247 +++++++++++
 .../entitystore/jooq/JooqDslContext.java        |  24 +-
 .../jooq/JooqEntityStoreConfiguration.java      |  11 +
 .../entitystore/jooq/JooqEntityStoreMixin.java  |  67 ++-
 .../jooq/JooqEntityStoreService.java            |   2 +-
 .../polygene/entitystore/jooq/MixinTable.java   | 214 ++++++++++
 .../polygene/entitystore/jooq/SqlTable.java     | 416 +++++++------------
 .../polygene/entitystore/jooq/SqlType.java      | 185 ++++-----
 .../polygene/entitystore/jooq/TableFields.java  |  69 +++
 .../polygene/entitystore/jooq/TypesTable.java   | 187 +++++++++
 .../jooq/assembly/JooqEntityStoreAssembler.java |   7 +-
 .../entitystore/jooq/JooqEntityStoreTest.java   |  66 ++-
 .../sql/dbcp/DBCPDataSourceServiceImporter.java |   3 +-
 18 files changed, 1218 insertions(+), 413 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/core/api/src/main/java/org/apache/polygene/api/PolygeneAPI.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/PolygeneAPI.java b/core/api/src/main/java/org/apache/polygene/api/PolygeneAPI.java
index 2823cb6..15d104e 100644
--- a/core/api/src/main/java/org/apache/polygene/api/PolygeneAPI.java
+++ b/core/api/src/main/java/org/apache/polygene/api/PolygeneAPI.java
@@ -143,6 +143,7 @@ public interface PolygeneAPI
      * @return true if the given object is a Composite type.
      */
     boolean isComposite( Object object );
+
     /**
      * Function that returns the CompositeInstance of a Composite.
      */

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/core/api/src/main/java/org/apache/polygene/api/association/AssociationDescriptor.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/association/AssociationDescriptor.java b/core/api/src/main/java/org/apache/polygene/api/association/AssociationDescriptor.java
index e7a1c01..09cd2c4 100644
--- a/core/api/src/main/java/org/apache/polygene/api/association/AssociationDescriptor.java
+++ b/core/api/src/main/java/org/apache/polygene/api/association/AssociationDescriptor.java
@@ -59,11 +59,11 @@ public interface AssociationDescriptor extends MetaInfoHolder
      */
     Type type();
 
-    boolean isImmutable();
-
-    boolean isAggregated();
-
     AccessibleObject accessor();
 
     boolean queryable();
+
+    boolean isImmutable();
+
+    boolean isAggregated();
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/core/api/src/main/java/org/apache/polygene/api/property/PropertyDescriptor.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/property/PropertyDescriptor.java b/core/api/src/main/java/org/apache/polygene/api/property/PropertyDescriptor.java
index 6c7df05..4a21920 100644
--- a/core/api/src/main/java/org/apache/polygene/api/property/PropertyDescriptor.java
+++ b/core/api/src/main/java/org/apache/polygene/api/property/PropertyDescriptor.java
@@ -32,8 +32,6 @@ import org.apache.polygene.api.type.ValueType;
  */
 public interface PropertyDescriptor extends MetaInfoHolder
 {
-    boolean isImmutable();
-
     /**
      * Get the qualified name of the property which is equal to:
      * <pre><code>
@@ -54,9 +52,11 @@ public interface PropertyDescriptor extends MetaInfoHolder
 
     AccessibleObject accessor();
 
-    Object resolveInitialValue(ModuleDescriptor moduleDescriptor);
+    boolean isImmutable();
+
+    boolean queryable();
 
     ValueType valueType();
 
-    boolean queryable();
+    Object resolveInitialValue(ModuleDescriptor moduleDescriptor);
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/core/runtime/src/test/java/org/apache/polygene/runtime/methods/AccessibleTest.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/test/java/org/apache/polygene/runtime/methods/AccessibleTest.java b/core/runtime/src/test/java/org/apache/polygene/runtime/methods/AccessibleTest.java
new file mode 100644
index 0000000..0d3ccb4
--- /dev/null
+++ b/core/runtime/src/test/java/org/apache/polygene/runtime/methods/AccessibleTest.java
@@ -0,0 +1,99 @@
+/*
+ *  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.runtime.methods;
+
+import org.apache.polygene.api.injection.scope.This;
+import org.apache.polygene.api.mixin.Mixins;
+import org.apache.polygene.bootstrap.AssemblyException;
+import org.apache.polygene.bootstrap.ModuleAssembly;
+import org.apache.polygene.test.AbstractPolygeneTest;
+import org.junit.Test;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+
+public class AccessibleTest extends AbstractPolygeneTest
+{
+
+    @Override
+    public void assemble( ModuleAssembly module )
+        throws AssemblyException
+    {
+        module.transients( MyComposite.class );
+    }
+
+    @Test
+    public void givenPrivateMixinWhenCallingFromWithinExpectSuccess()
+    {
+        MyComposite myComposite = transientBuilderFactory.newTransient( MyComposite.class );
+        assertThat(myComposite.doSomething(), equalTo("Hello"));
+    }
+
+    @Mixins( MyCompositeMixin.class)
+    public interface MyComposite
+    {
+        String doSomething();
+    }
+
+    @Mixins( MyFunctionMixin.class )
+    public interface MyFunction
+    {
+        String doSomething();
+    }
+
+
+    public class MyCompositeMixin
+        implements MyComposite
+    {
+        @This
+        private MyFunction function;
+
+        @Override
+        public String doSomething()
+        {
+            return new MyObject( function ).doSomething() + " ---- " + getClass().getClassLoader();
+        }
+    }
+
+    public class MyFunctionMixin
+        implements MyFunction
+    {
+        @Override
+        public String doSomething()
+        {
+            return "Hello " + getClass().getClassLoader();
+        }
+    }
+
+    public class MyObject
+    {
+        private MyFunction fn;
+
+        public MyObject( MyFunction fn )
+        {
+            this.fn = fn;
+        }
+
+        String doSomething()
+        {
+            return fn.doSomething();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/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 07fb05c..e4eaa40 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
@@ -1,3 +1,20 @@
+/*
+ *  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;

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/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
new file mode 100644
index 0000000..dc765a9
--- /dev/null
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/EntitiesTable.java
@@ -0,0 +1,247 @@
+/*
+ *  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.sql.Timestamp;
+import java.time.Instant;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Consumer;
+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.entity.EntityDescriptor;
+import org.apache.polygene.api.entity.EntityReference;
+import org.apache.polygene.api.property.PropertyDescriptor;
+import org.apache.polygene.api.structure.ModuleDescriptor;
+import org.apache.polygene.api.type.EntityCompositeType;
+import org.apache.polygene.api.unitofwork.NoSuchEntityTypeException;
+import org.apache.polygene.api.util.Classes;
+import org.apache.polygene.spi.entitystore.EntityNotFoundException;
+import org.apache.polygene.spi.entitystore.EntityStoreUnitOfWork;
+import org.apache.polygene.spi.entitystore.helpers.DefaultEntityState;
+import org.jooq.Condition;
+import org.jooq.Field;
+import org.jooq.Record;
+import org.jooq.Result;
+import org.jooq.Schema;
+import org.jooq.SelectJoinStep;
+import org.jooq.SelectQuery;
+import org.jooq.Table;
+
+public class EntitiesTable
+    implements TableFields
+{
+    private Map<EntityCompositeType, Set<Class<?>>> mixinTypeCache = new ConcurrentHashMap<>();
+    private Map<Class<?>, MixinTable> mixinTablesCache = new ConcurrentHashMap<>();
+
+    private final Table<Record> entitiesTable;
+    private JooqDslContext dsl;
+    private final TypesTable types;
+    private final Schema schema;
+    private String applicationVersion;
+
+    EntitiesTable( JooqDslContext dsl, Schema schema, TypesTable types, String applicationVersion, String entitiesTableName )
+    {
+        this.dsl = dsl;
+        this.types = types;
+        this.schema = schema;
+        this.applicationVersion = applicationVersion;
+        entitiesTable = types.tableOf( entitiesTableName );
+    }
+
+    public BaseEntity fetchEntity( EntityReference reference, ModuleDescriptor module )
+    {
+        BaseEntity result = new BaseEntity();
+
+        Result<Record> baseEntityResult = dsl
+            .selectFrom( entitiesTable )
+            .where( identityColumn.eq( reference.identity().toString() ) )
+            .fetch();
+
+        if( baseEntityResult.isEmpty() )
+        {
+            throw new EntityNotFoundException( reference );
+        }
+        Record baseEntity = baseEntityResult.get( 0 );
+        String typeName = baseEntity.field( typeNameColumn ).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 = Instant.ofEpochMilli( baseEntity.field( modifiedColumn ).get( baseEntity ).getTime() );
+        result.createdAt = Instant.ofEpochMilli( baseEntity.field( createdColumn ).get( baseEntity ).getTime() );
+        return result;
+    }
+
+    private 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() );
+        }
+    }
+
+    void insertEntity( DefaultEntityState state )
+    {
+        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();
+        mixinTypes.forEach( type ->
+                            {
+                                MixinTable table = findMixinTable( type, state.entityDescriptor() );
+                                table.insertMixinState( state, valueIdentity );
+                            } );
+    }
+
+    private MixinTable findMixinTable( Class<?> type, EntityDescriptor entityDescriptor )
+    {
+        return mixinTablesCache.computeIfAbsent( type, t -> new MixinTable( dsl, schema, types, type, entityDescriptor ) );
+    }
+
+    private Set<Class<?>> mixinsOf( Stream<? extends AssociationDescriptor> stream )
+    {
+        return stream
+            .map( AssociationDescriptor::accessor )
+            .filter( Classes.instanceOf( Method.class ) )
+            .map( accessor -> (Method) accessor )
+            .map( Method::getDeclaringClass )
+            .collect( Collectors.toSet() );
+    }
+
+    private String columnNameOf( QualifiedName propertyName )
+    {
+        return null;
+    }
+
+    void modifyEntity( Class<?> mixinType, DefaultEntityState state )
+    {
+
+    }
+
+    void createNewBaseEntity( EntityReference reference, EntityDescriptor descriptor, EntityStoreUnitOfWork uow )
+    {
+        String valueIdentity = UUID.randomUUID().toString();
+        dsl.insertInto( entitiesTable )
+           .set( identityColumn, reference.identity().toString() )
+           .set( createdColumn, new Timestamp( uow.currentTime().toEpochMilli() ) )
+           .set( modifiedColumn, new Timestamp( uow.currentTime().toEpochMilli() ) )
+           .set( valueIdentityColumn, valueIdentity )
+           .set( typeNameColumn, descriptor.primaryType().getName() )
+           .set( versionColumn, "1" )
+           .set( applicationVersionColumn, applicationVersion )
+           .execute();
+    }
+
+    /**
+     * Builds the SELECT statement for a given entity.
+     * <p>
+     * Example; If we have the following entity
+     * </p>
+     * <code><pre>
+     *     public interface LegalEntity
+     *     {
+     *         Property&lt;String&gt; registration();
+     *     }
+     * <p>
+     *     public interface Person extends LegalEntity
+     *     {
+     *         Property&lt;String&gt; name();
+     * <p>
+     *         &#64;Optional
+     *         Association&lt;Person&gt; spouse();
+     * <p>
+     *         ManyAssocation&lt;Person&gt; 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();
+    }
+
+    public void fetchAssociations( Record record, Consumer<AssociationValue> consume )
+    {
+        AssociationValue value = new AssociationValue();
+        value.name = record.getValue( nameColumn );
+        value.position = record.getValue( indexColumn );
+        value.reference = record.getValue( referenceColumn );
+        consume.accept( value );
+    }
+
+    public List<Table<Record>> getTableJoins( EntityDescriptor entityDescriptor )
+    {
+        return entityDescriptor
+            .mixinTypes()
+            .map( ( Class<?> type ) -> types.tableFor( type, entityDescriptor ) )
+            .collect( Collectors.toList() );
+    }
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/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
index 8737936..95a0fd5 100644
--- 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
@@ -1,3 +1,20 @@
+/*
+ *  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.InvocationHandler;
@@ -6,7 +23,6 @@ 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;
@@ -23,13 +39,11 @@ public interface JooqDslContext extends DSLContext
     {
         private DSLContext dsl;
 
-        public Mixin( @Service DataSource dataSource, @Uses ServiceDescriptor serviceDescriptor )
+        public Mixin( @Service DataSource dataSource, @Uses Settings settings, @Uses SQLDialect dialect )
         {
-            Settings settings = serviceDescriptor.metaInfo( Settings.class );
-            SQLDialect sqlDialect = serviceDescriptor.metaInfo( SQLDialect.class );
             Configuration configuration = new DefaultConfiguration()
                 .set( dataSource )
-                .set( sqlDialect )
+                .set( dialect )
                 .set( settings );
             dsl = DSL.using( configuration );
         }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/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
index e3a79f6..7d27cdf 100644
--- 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
@@ -58,5 +58,16 @@ public interface JooqEntityStoreConfiguration extends SQLConfiguration
      */
     @UseDefaults( "true" )
     Property<Boolean> createIfMissing();
+
+    /**
+     * The SQL dialect that is being used.
+     * <p>
+     * Typically that is matching a supporting dialect in JOOQ.
+     * See {@link org.jooq.SQLDialect} for supported values.
+     * </p>
+     * @return The property with the dialect value.
+     */
+    @UseDefaults( "" )
+    Property<String> dialect();
 }
 // END SNIPPET: config

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/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 8974181..a22354b 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
@@ -30,11 +30,9 @@ 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;
@@ -53,19 +51,9 @@ import static org.apache.polygene.api.entity.EntityReference.parseEntityReferenc
 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;
 
@@ -103,7 +91,6 @@ public class JooqEntityStoreMixin
         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'
@@ -115,8 +102,7 @@ public class JooqEntityStoreMixin
                                 {
                                     addNamedAssociation( stateDescriptor, namedAssocs, associationValue );
                                 }
-                            } );
-                        } );
+                            } ) );
 
         return new DefaultEntityState( baseEntity.version,
                                        baseEntity.modifedAt,
@@ -155,7 +141,7 @@ public class JooqEntityStoreMixin
     @Override
     public StateCommitter applyChanges( EntityStoreUnitOfWork unitOfWork, Iterable<EntityState> state )
     {
-        return new JooqStateCommitter( unitOfWork, state );
+        return new JooqStateCommitter( unitOfWork, state, sqlTable.jooqDslContext() );
     }
 
     @Override
@@ -175,24 +161,65 @@ public class JooqEntityStoreMixin
         return null;
     }
 
-    private static class JooqStateCommitter
+    private class JooqStateCommitter
         implements StateCommitter
     {
-        public JooqStateCommitter( EntityStoreUnitOfWork unitOfWork, Iterable<EntityState> state )
-        {
+        private final EntityStoreUnitOfWork unitOfWork;
+        private final Iterable<EntityState> states;
+        private final JooqDslContext dslContext;
 
+        JooqStateCommitter( EntityStoreUnitOfWork unitOfWork, Iterable<EntityState> states, JooqDslContext dslContext )
+        {
+            this.unitOfWork = unitOfWork;
+            this.states = states;
+            this.dslContext = dslContext;
         }
 
         @Override
         public void commit()
         {
+            dslContext.transaction( configuration ->
+                                    {
+                                        for( EntityState es : this.states )
+                                        {
+                                            DefaultEntityState state = (DefaultEntityState) es;
+                                            if( state.status() == EntityStatus.NEW )
+                                            {
+                                                newState( state );
+                                            }
+                                            if( state.status() == EntityStatus.UPDATED )
+                                            {
+                                                updateState( state );
+                                            }
+                                            if( state.status() == EntityStatus.REMOVED )
+                                            {
+                                                removeState( state );
+                                            }
+                                        }
+                                    } );
+        }
+
+        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/60d2eebd/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
index 0259151..511f2f0 100644
--- 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
@@ -31,6 +31,6 @@ import org.apache.polygene.spi.entitystore.StateChangeNotificationConcern;
 @Concerns( { StateChangeNotificationConcern.class, ConcurrentModificationCheckConcern.class } )
 @Mixins( { JooqEntityStoreMixin.class } )
 public interface JooqEntityStoreService
-    extends EntityStore, EntityStateVersions, Configuration
+    extends EntityStore, EntityStateVersions, Configuration, SqlTable
 {
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/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
new file mode 100644
index 0000000..fee95ef
--- /dev/null
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/MixinTable.java
@@ -0,0 +1,214 @@
+/*
+ *  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.AccessibleObject;
+import java.lang.reflect.Method;
+import java.sql.Timestamp;
+import java.util.Map;
+import java.util.function.Consumer;
+import org.apache.polygene.api.association.AssociationDescriptor;
+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.property.PropertyDescriptor;
+import org.apache.polygene.spi.entity.ManyAssociationState;
+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.Name;
+import org.jooq.Record;
+import org.jooq.Schema;
+import org.jooq.Table;
+import org.jooq.impl.DSL;
+
+class MixinTable
+    implements TableFields
+{
+
+    private final Table<Record> mixinTable;
+    private final Table<Record> mixinAssocsTable;
+
+    private final JooqDslContext dsl;
+    private TypesTable types;
+    private final Class<?> mixinType;
+
+    MixinTable( JooqDslContext dsl, Schema schema, TypesTable types, Class<?> mixinType,
+                EntityDescriptor descriptor )
+    {
+        this.dsl = dsl;
+        this.types = types;
+        this.mixinType = mixinType;
+        mixinTable = types.tableFor( mixinType, descriptor );
+        mixinAssocsTable = getAssocsTable( descriptor, schema );
+    }
+
+    void insertMixinState( DefaultEntityState state, String valueIdentity )
+    {
+        InsertSetMoreStep<Record> primaryTable =
+            dsl.insertInto( mixinTable )
+               .set( identityColumn, valueIdentity )
+               .set( createdColumn, new Timestamp( System.currentTimeMillis() ) )
+               .set( modifiedColumn, new Timestamp( System.currentTimeMillis() ) );
+
+        EntityDescriptor entityDescriptor = state.entityDescriptor();
+        entityDescriptor.valueType().properties()
+                        .filter( this::isThisMixin )
+                        .forEach( propDescriptor ->
+                                  {
+                                      QualifiedName propertyName = propDescriptor.qualifiedName();
+                                      Field<Object> propertyField = types.fieldOf( propDescriptor );
+                                      primaryTable.set( propertyField, state.propertyValueOf( propertyName ) );
+                                  }
+                                );
+        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 );
+                                  }
+                                );
+
+        if( mixinAssocsTable != null )
+        {
+            entityDescriptor.valueType().manyAssociations()
+                            .filter( this::isThisMixin )
+                            .forEach( setManyAssociations( state, valueIdentity ) );
+
+            entityDescriptor.valueType().namedAssociations()
+                            .filter( this::isThisMixin )
+                            .forEach( setNamedAssociations( state, valueIdentity ) );
+        }
+    }
+
+    private Consumer<? super AssociationDescriptor> setManyAssociations( DefaultEntityState state, String valueIdentity )
+    {
+        return assocDescriptor ->
+        {
+            QualifiedName assocName = assocDescriptor.qualifiedName();
+            ManyAssociationState entityReferences = state.manyAssociationValueOf( assocName );
+            entityReferences.stream().forEach( setManyAssociation( state, assocDescriptor, valueIdentity ) );
+        };
+    }
+
+    private Consumer<? super EntityReference> setManyAssociation( DefaultEntityState state,
+                                                                  AssociationDescriptor assocDescriptor,
+                                                                  String valueIdentity )
+    {
+        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() );
+        };
+    }
+
+    private Consumer<? super AssociationDescriptor> setNamedAssociations( DefaultEntityState state,
+                                                                          String valueIdentity )
+    {
+        return assocDescriptor ->
+        {
+            QualifiedName assocName = assocDescriptor.qualifiedName();
+            NamedAssociationState entityReferences = state.namedAssociationValueOf( assocName );
+            entityReferences.stream().forEach( setNamedAssociation( state, assocDescriptor, valueIdentity ) );
+        };
+    }
+
+    private Consumer<? super Map.Entry<String, EntityReference>> setNamedAssociation( DefaultEntityState state,
+                                                                                      AssociationDescriptor assocDescriptor,
+                                                                                      String valueIdentity )
+    {
+        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() );
+        };
+    }
+
+    private boolean isThisMixin( PropertyDescriptor descriptor )
+    {
+        Class<?> declaringClass = declaredIn( descriptor );
+        return mixinType.equals( declaringClass );
+    }
+
+    private boolean isThisMixin( AssociationDescriptor descriptor )
+    {
+        Class<?> declaringClass = declaredIn( descriptor );
+        return mixinType.equals( declaringClass );
+    }
+
+    private Class<?> declaredIn( PropertyDescriptor descriptor )
+    {
+        AccessibleObject accessor = descriptor.accessor();
+        if( accessor instanceof Method )
+        {
+            return ( (Method) accessor ).getDeclaringClass();
+        }
+        throw new UnsupportedOperationException( "Property declared as " + accessor.getClass() + " is not supported in this Entity Store yet." );
+    }
+
+    private Class<?> declaredIn( AssociationDescriptor descriptor )
+    {
+        AccessibleObject accessor = descriptor.accessor();
+        if( accessor instanceof Method )
+        {
+            return ( (Method) accessor ).getDeclaringClass();
+        }
+        throw new UnsupportedOperationException( "Property declared as " + accessor.getClass() + " is not supported in this Entity Store yet." );
+    }
+
+    void modifyMixinState( Class<?> mixinType, DefaultEntityState state )
+    {
+
+    }
+
+    private Table<Record> getAssocsTable( EntityDescriptor descriptor, Schema schema )
+    {
+        if( descriptor.state().manyAssociations().count() > 0
+            || descriptor.state().namedAssociations().count() > 0 )
+        {
+            Name tableName = DSL.name( schema.getName(), mixinTable.getName() + ASSOCS_TABLE_POSTFIX );
+            Table<Record> table = DSL.table( tableName );
+            int result2 = dsl.createTableIfNotExists( table )
+                             .column( identityColumn )
+                             .column( nameColumn )
+                             .column( indexColumn )
+                             .column( referenceColumn )
+                             .execute();
+            return table;
+        }
+        else
+        {
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/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 1cf0c1c..2801f57 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
@@ -17,340 +17,236 @@
  */
 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 javax.sql.DataSource;
+import org.apache.polygene.api.PolygeneAPI;
+import org.apache.polygene.api.composite.TransientBuilderFactory;
 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.Service;
+import org.apache.polygene.api.injection.scope.Structure;
 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.object.ObjectFactory;
 import org.apache.polygene.api.service.ServiceActivation;
 import org.apache.polygene.api.service.ServiceDescriptor;
+import org.apache.polygene.api.structure.Application;
 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.apache.polygene.spi.entitystore.EntityStoreUnitOfWork;
+import org.apache.polygene.spi.entitystore.helpers.DefaultEntityState;
 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.conf.RenderNameStyle;
+import org.jooq.conf.Settings;
 import org.jooq.impl.DSL;
 
+/**
+ * This class handles all the Jooq interactions.
+ * <p>
+ * <p>
+ * <p>
+ * <h1>Tables</h1>
+ * <h2>Types Table</h2>
+ * <ul>
+ * <li>identity</li>
+ * <li>table_name</li>
+ * <li>created_at</li>
+ * <li>modified_at</li>
+ * </ul>
+ * <h2>Entities Table</h2>
+ * <ul>
+ * <li>identity</li>
+ * <li>app_version</li>
+ * <li>value_id</li>
+ * <li>version</li>
+ * <li>type</li>
+ * <li>modified_at</li>
+ * <li>created_at</li>
+ * </ul>
+ * <h2>Mixin Tables</h2>
+ * <p>
+ * Each Mixin is stored in its own table. Only the following column is always present;
+ * <ul>
+ * <li>identity - this is not entity identity but the UUID of the value_id in the Entities Table above.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Each Property of the Mixin (as defined by QualifiedName of the Property, will reside in its own column.
+ * All values in columns are (for now) serialized using a ValueSerialization service.
+ * </p>
+ * <p>
+ * Associations also has their own columns in the table, with the EntityReference.identity() stored in them.
+ * </p>
+ * <p>
+ * ManyAssociations and NamedAssociations are stored in a separate table, named &lt;mixintable&gt;_ASSOCS, see below.
+ * </p>
+ * <h2>Mixin_ASSOCS Table</h2>
+ * <ul>
+ * <li>identity - the value_id of the mixin value</li>
+ * <li>name - the name of the ManyAssociation or NamedAssociation</li>
+ * <li>position - for NamedAssociation this is the 'name' (i.e key) and for ManyAssociation this is the index into the list.</li>
+ * <li>reference - EntityReference.identity of that association</li>
+ * </ul>
+ */
 @Mixins( SqlTable.Mixin.class )
-public interface SqlTable
+public interface SqlTable extends ServiceActivation
 {
-    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 );
+    SelectQuery<Record> createGetEntityQuery( EntityDescriptor descriptor, EntityReference reference );
 
-    Record createNewBaseEntity( EntityReference reference, EntityDescriptor descriptor );
+    void fetchAssociations( Record record, Consumer<AssociationValue> consume );
 
-    SelectQuery<Record> createGetEntityQuery( EntityDescriptor entityDescriptor, EntityReference reference );
+    void createNewBaseEntity( EntityReference ref, EntityDescriptor descriptor, EntityStoreUnitOfWork unitOfWork );
 
-    void fetchAssociations( Record record, Consumer<AssociationValue> consume );
+    void insertEntity( DefaultEntityState state );
+
+    JooqDslContext jooqDslContext();
 
     class Mixin
-        implements SqlTable, ServiceActivation
+        implements SqlTable, TableFields, ServiceActivation
     {
+        @Structure
+        private Application application;
 
-        @This
-        JooqDslContext dsl;
+        @Structure
+        private PolygeneAPI api;
+
+        @Structure
+        private TransientBuilderFactory tbf;
+
+        @Structure
+        private ObjectFactory objectFactory;
 
         @This
         private Configuration<JooqEntityStoreConfiguration> configuration;
 
-        @This
-        private SqlType sqlType;
+        @Service
+        private DataSource datasource;
 
         @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 ) );
+        private EntitiesTable entitiesTable;
 
-            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();
-                }
-            }
-        }
+        private TypesTable types;
+        private JooqDslContext dsl;
 
         @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;
+            return entitiesTable.fetchEntity( reference, module );
         }
 
         @Override
-        public void passivateService()
-            throws Exception
+        public SelectQuery<Record> createGetEntityQuery( EntityDescriptor descriptor, EntityReference reference )
         {
-            schema = null;
+            return entitiesTable.createGetEntityQuery( descriptor, reference );
         }
 
-        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 )
+        @Override
+        public void fetchAssociations( Record record, Consumer<AssociationValue> consume )
         {
-            return entityTables.computeIfAbsent( type, t -> createTable( t, descriptor ) );
+            entitiesTable.fetchAssociations( record, consume );
         }
 
-        public Table<Record> createTable( Class<?> type, EntityDescriptor descriptor )
+        @Override
+        public void createNewBaseEntity( EntityReference ref, EntityDescriptor descriptor, EntityStoreUnitOfWork unitOfWork )
         {
-            String tableName = findTableName( type, descriptor );
-            return null;
+            entitiesTable.createNewBaseEntity( ref, descriptor, unitOfWork );
         }
 
-        public String findTableName( Class<?> type, EntityDescriptor descriptor )
+        @Override
+        public void insertEntity( DefaultEntityState state )
         {
-            Result<Record> typeInfo = fetchTypeInfoFromTable( type );
-            if( typeInfo.isEmpty() )
-            {
-                typeInfo = createNewTable( type, descriptor );
-            }
-            return typeInfo.getValue( 0, tableNameColumn );
+            entitiesTable.insertEntity( state );
         }
 
         @Override
-        public String createNewTableName( Class<?> type )
+        public JooqDslContext jooqDslContext()
         {
-            return null;
+            return dsl;
         }
 
-        public Result<Record> createNewTable( Class<?> mixinType, EntityDescriptor descriptor )
+        @Override
+        public void activateService()
+            throws Exception
         {
-            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 ) );
-                            } );
+            JooqEntityStoreConfiguration config = this.configuration.get();
+            SQLDialect dialect = getSqlDialect( config );
 
-            return fetchTypeInfoFromTable( mixinType );
-        }
+            Settings settings = serviceDescriptor
+                .metaInfo( Settings.class )
+                .withRenderNameStyle( RenderNameStyle.QUOTED );
+            dsl = tbf.newTransient( JooqDslContext.class, settings, dialect );
 
-        public boolean isProperty( Method method )
-        {
-            return Property.class.isAssignableFrom( method.getReturnType() ) && method.getParameterCount() == 0;
-        }
+            String schemaName = config.schemaName().get();
+            String typesTableName = config.typesTableName().get();
+            String entitiesTableName = config.entitiesTableName().get();
+            Schema schema = DSL.schema( DSL.name( schemaName ) );
+            types = new TypesTable( dsl, schema, dialect, typesTableName );
+            entitiesTable = new EntitiesTable( dsl, schema, types, application.version(), entitiesTableName );
 
-        public EntityDescriptor findEntityDescriptor( String typeName, ModuleDescriptor module )
-        {
-            try
-            {
-                Class<?> type = getClass().getClassLoader().loadClass( typeName );
-                return module.typeLookup().lookupEntityModel( type );
-            }
-            catch( ClassNotFoundException e )
+            // Eventually create schema
+            if( config.createIfMissing().get() )
             {
-                throw new NoSuchEntityTypeException( typeName, module.name(), module.typeLookup() );
+                if( !dialect.equals( SQLDialect.SQLITE )
+                    && dsl.meta().getSchemas().stream().noneMatch( s -> schema.getName().equalsIgnoreCase( s.getName() ) ) )
+                {
+                    dsl.createSchema( schema ).execute();
+                }
+
+                dsl.createTableIfNotExists( DSL.name( schemaName, typesTableName ) )
+                   .column( identityColumn )
+                   .column( tableNameColumn )
+                   .column( createdColumn )
+                   .column( modifiedColumn )
+                   .execute();
+
+                dsl.createTableIfNotExists( DSL.name( schemaName, entitiesTableName ) )
+                   .column( identityColumn )
+                   .column( applicationVersionColumn )
+                   .column( valueIdentityColumn )
+                   .column( versionColumn )
+                   .column( typeNameColumn )
+                   .column( modifiedColumn )
+                   .column( createdColumn )
+                   .execute();
             }
+            datasource.getConnection().commit();
         }
 
         @Override
-        public Record createNewBaseEntity( EntityReference reference, EntityDescriptor descriptor )
+        public void passivateService()
+            throws Exception
         {
-            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&lt;String&gt; registration();
-         *     }
-         * <p>
-         *     public interface Person extends LegalEntity
-         *     {
-         *         Property&lt;String&gt; name();
-         * <p>
-         *         &#64;Optional
-         *         Association&lt;Person&gt; spouse();
-         * <p>
-         *         ManyAssocation&lt;Person&gt; 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 )
+        private SQLDialect getSqlDialect( JooqEntityStoreConfiguration config )
         {
-            SelectJoinStep<Record> from = dsl.select().from( entitiesTable );
-            List<Table<Record>> joins = getTableJoins( entityDescriptor );
-            for( Table<Record> joinedTable : joins )
+            SQLDialect dialect = null;
+            String dialectString = config.dialect().get();
+            if( dialectString.length() == 0 )
             {
-                Field<String> joinedField = joinedTable.field( identityColumn );
-                Condition joinCondition = joinedField.eq( entitiesTable.field( valueIdentityColumn ) );
-                from = from.join( joinedTable ).on( joinCondition );
+                dialect = SQLDialect.DEFAULT;
             }
-            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 );
+            else
+            {
+                try
+                {
+                    dialect = SQLDialect.valueOf( dialectString );
+                }
+                catch( IllegalArgumentException e )
+                {
+                    throw new IllegalArgumentException( "Invalid SQLDialect: '" + dialectString + "'" );
+                }
+            }
+            return dialect;
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/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
index c872d62..6b6dfdd 100644
--- 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
@@ -24,125 +24,118 @@ 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
+class SqlType
 {
-    DataType<?> getSqlDataTypeFor( Class<?> propertyType );
-
-    class Mixin
-        implements SqlType
+    @SuppressWarnings( "unchecked" )
+    static <T> DataType<T> getSqlDataTypeFor( Class<?> propertyType )
     {
-        public DataType<?> getSqlDataTypeFor( Class<?> propertyType )
+        if( String.class.isAssignableFrom( 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 (DataType<T>) SQLDataType.VARCHAR;
+        }
+        if( Integer.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.INTEGER;
+        }
+        if( Long.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.BIGINT;
+        }
+        if( Boolean.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.BOOLEAN;
+        }
+        if( Float.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.FLOAT;
+        }
+        if( Double.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.DOUBLE;
+        }
+        if( Instant.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.TIMESTAMPWITHTIMEZONE;
+        }
+        if( Interval.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.VARCHAR;
+        }
+        if( Period.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.VARCHAR;
+        }
+        if( LocalDate.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.LOCALDATE;
+        }
+        if( LocalTime.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.LOCALTIME;
+        }
+        if( LocalDateTime.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.LOCALDATETIME;
+        }
+        if( ZonedDateTime.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.OFFSETDATETIME;
+        }
+        if( OffsetDateTime.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.OFFSETDATETIME;
+        }
+        if( Character.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.CHAR( 1 );
+        }
+        if( Short.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.INTEGER;
+        }
+        if( Byte.class.isAssignableFrom( propertyType ) )
+        {
+            return (DataType<T>) SQLDataType.INTEGER;
+        }
+        if( propertyType.isPrimitive() )
+        {
+            if( propertyType.equals( Integer.TYPE ) )
             {
-                return SQLDataType.LOCALTIME;
+                return (DataType<T>) SQLDataType.INTEGER;
             }
-            if( LocalDateTime.class.isAssignableFrom( propertyType ) )
+            if( propertyType.equals( Long.TYPE ) )
             {
-                return SQLDataType.LOCALDATETIME;
+                return (DataType<T>) SQLDataType.BIGINT;
             }
-            if( ZonedDateTime.class.isAssignableFrom( propertyType ) )
+            if( propertyType.equals( Boolean.TYPE ) )
             {
-                return SQLDataType.OFFSETDATETIME;
+                return (DataType<T>) SQLDataType.BOOLEAN;
             }
-            if( OffsetDateTime.class.isAssignableFrom( propertyType ) )
+            if( propertyType.equals( Float.TYPE ) )
             {
-                return SQLDataType.OFFSETDATETIME;
+                return (DataType<T>) SQLDataType.FLOAT;
             }
-            if( Character.class.isAssignableFrom( propertyType ) )
+            if( propertyType.equals( Double.TYPE ) )
             {
-                return SQLDataType.CHAR( 1 );
+                return (DataType<T>) SQLDataType.DOUBLE;
             }
-            if( Short.class.isAssignableFrom( propertyType ) )
+            if( propertyType.equals( Character.TYPE ) )
             {
-                return SQLDataType.INTEGER;
+                return (DataType<T>) SQLDataType.CHAR( 1 );
             }
-            if( Byte.class.isAssignableFrom( propertyType ) )
+            if( propertyType.equals( Short.TYPE ) )
             {
-                return SQLDataType.INTEGER;
+                return (DataType<T>) SQLDataType.INTEGER;
             }
-            if( propertyType.isPrimitive() )
+            if( propertyType.equals( Byte.TYPE ) )
             {
-                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 (DataType<T>) SQLDataType.INTEGER;
             }
-            return SQLDataType.VARCHAR;
         }
+        return (DataType<T>) SQLDataType.VARCHAR;
     }
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/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
new file mode 100644
index 0000000..2454ae4
--- /dev/null
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TableFields.java
@@ -0,0 +1,69 @@
+/*
+ *  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.sql.Timestamp;
+import org.jooq.Field;
+
+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";
+
+    // Types Table
+    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";
+
+    // 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 ASSOCS_TABLE_POSTFIX = "_ASSOCS";
+
+
+    // Common Fields
+    Field<String> identityColumn = makeField( IDENTITY_COLUMN_NAME, String.class );
+    Field<Timestamp> createdColumn = makeField( CREATED_COLUMN_NAME, Timestamp.class );
+    Field<Timestamp> modifiedColumn = makeField( LASTMODIFIED_COLUMN_NAME, Timestamp.class );
+
+    // Types Table
+    Field<String> tableNameColumn = makeField( TABLENAME_COLUMN_NAME, String.class );
+
+    // Entities Table
+    Field<String> valueIdentityColumn = makeField( VALUEID_COLUMN_NAME, String.class );
+    Field<String> typeNameColumn = makeField( TYPE_COLUMN_NAME, String.class );
+    Field<String> versionColumn = makeField( VERSION_COLUMN_NAME, String.class );
+    Field<String> applicationVersionColumn = makeField( APPLICATIONVERSION_COLUMN_NAME, String.class );
+
+    // Mixin Tables
+
+    // The _ASSOCS table
+    Field<String> nameColumn = makeField( NAME_COLUMN_NAME, String.class );
+    Field<String> referenceColumn = makeField( REFERENCE_COLUMN_NAME, String.class );
+    Field<String> indexColumn = makeField( INDEX_COLUMN_NAME, String.class );
+
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/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
new file mode 100644
index 0000000..4672d4f
--- /dev/null
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TypesTable.java
@@ -0,0 +1,187 @@
+/*
+ *  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.lang.reflect.Type;
+import java.sql.Timestamp;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.polygene.api.association.AssociationDescriptor;
+import org.apache.polygene.api.common.QualifiedName;
+import org.apache.polygene.api.entity.EntityDescriptor;
+import org.apache.polygene.api.property.Property;
+import org.apache.polygene.api.property.PropertyDescriptor;
+import org.apache.polygene.api.util.Classes;
+import org.jooq.CreateTableColumnStep;
+import org.jooq.DataType;
+import org.jooq.Field;
+import org.jooq.Record;
+import org.jooq.Result;
+import org.jooq.SQLDialect;
+import org.jooq.Schema;
+import org.jooq.Table;
+import org.jooq.impl.DSL;
+
+public class TypesTable
+    implements TableFields
+{
+    private final Map<Class<?>, Table<Record>> mixinTablesCache = new ConcurrentHashMap<>();
+    private final Map<Class<?>, Table<Record>> mixinAssocsTablesCache = new ConcurrentHashMap<>();
+
+    private final Table<Record> typesTable;
+    private final SQLDialect dialect;
+    private final Schema schema;
+
+    private final JooqDslContext dsl;
+
+    TypesTable( JooqDslContext dsl, Schema schema,
+                SQLDialect dialect,
+                String typesTablesName
+              )
+    {
+        this.schema = schema;
+        this.dialect = dialect;
+        typesTable = tableOf( typesTablesName );
+        this.dsl = dsl;
+    }
+
+    static <T> Field<T> makeField( String columnName, Class<T> type )
+    {
+        return DSL.field( DSL.name( columnName ), type );
+    }
+
+    Table<Record> tableOf( String tableName )
+    {
+        return DSL.table(
+            dialect.equals( SQLDialect.SQLITE )
+            ? DSL.name( tableName )
+            : DSL.name( schema.getName(), tableName ) );
+    }
+
+    String tableNameOf( Class<?> mixinType )
+    {
+        Result<Record> typeInfo = fetchTypeInfoFromTable( mixinType );
+        if( typeInfo.isEmpty() )
+        {
+            return null;
+        }
+        return typeInfo.getValue( 0, tableNameColumn );
+    }
+
+    Table<Record> tableFor( Class<?> type, EntityDescriptor descriptor )
+    {
+        return mixinTablesCache.computeIfAbsent( type, t ->
+        {
+            String tableName = tableNameOf( t );
+            if( tableName == null )
+            {
+                Result<Record> newMixinTable = createNewMixinTable( type, descriptor );
+                return tableOf( newMixinTable.getValue( 0, tableNameColumn ) );
+            }
+            return tableOf( tableName );
+        } );
+    }
+
+    private Result<Record> fetchTypeInfoFromTable( Class<?> mixinTableName )
+    {
+        return dsl.select()
+                  .from( typesTable )
+                  .where( identityColumn.eq( mixinTableName.getName() ) )
+                  .fetch();
+    }
+
+    private Result<Record> createNewMixinTable( Class<?> mixinType, EntityDescriptor descriptor )
+    {
+        String mixinTypeName = mixinType.getName();
+        String tableName = createNewTableName( mixinType );
+        CreateTableColumnStep primaryTable = dsl.createTable( tableName ).column( identityColumn );
+        descriptor.state().properties().forEach(
+            property ->
+            {
+                QualifiedName qualifiedName = property.qualifiedName();
+                if( qualifiedName.toNamespace().equals( mixinTypeName ) )
+                {
+                    primaryTable.column( fieldOf( property ) );
+                }
+            } );
+        descriptor.state().associations().forEach(
+            assoc ->
+            {
+                QualifiedName qualifiedName = assoc.qualifiedName();
+                if( qualifiedName.toNamespace().equals( mixinTypeName ) )
+                {
+                    primaryTable.column( fieldOf( assoc ) );
+                }
+            } );
+
+        int result3 = dsl.insertInto( typesTable )
+                         .set( identityColumn, mixinTypeName )
+                         .set( tableNameColumn, tableName )
+                         .set( createdColumn, new Timestamp( System.currentTimeMillis() ) )
+                         .set( modifiedColumn, new Timestamp( System.currentTimeMillis() ) )
+                         .execute();
+        return fetchTypeInfoFromTable( mixinType );
+    }
+
+    private String createNewTableName( Class<?> mixinType )
+    {
+        String typeName = mixinType.getSimpleName();
+        String postFix = "";
+        int counter = 0;
+        boolean found = false;
+        do
+        {
+            found = checkForTableNamed( typeName + postFix );
+            postFix = "_" + counter++;
+        } while( found );
+        return typeName;
+    }
+
+    private boolean checkForTableNamed( String tableName )
+    {
+        return dsl.select()
+                  .from( typesTable )
+                  .where( tableNameColumn.eq( tableName ) )
+                  .fetch().size() > 0;
+    }
+
+    private boolean isProperty( Method method )
+    {
+        return Property.class.isAssignableFrom( method.getReturnType() ) && method.getParameterCount() == 0;
+    }
+
+    Field<Object> fieldOf( PropertyDescriptor descriptor )
+    {
+        String propertyName = descriptor.qualifiedName().name();
+        return DSL.field( DSL.name( propertyName ), dataTypeOf( descriptor ) );
+    }
+
+    Field<String> fieldOf( AssociationDescriptor descriptor )
+    {
+        String propertyName = descriptor.qualifiedName().name();
+        return DSL.field( DSL.name( propertyName ), DSL.getDataType( String.class ) );
+    }
+
+    private <T> DataType<T> dataTypeOf( PropertyDescriptor property )
+    {
+        Type type = property.type();
+        Class<?> rawType = Classes.RAW_CLASS.apply( type );
+        return SqlType.getSqlDataTypeFor( rawType );
+    }
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/60d2eebd/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
index 8a986a9..c251efe 100644
--- 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
@@ -25,6 +25,7 @@ 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.JooqDslContext;
 import org.apache.polygene.entitystore.jooq.JooqEntityStoreConfiguration;
 import org.apache.polygene.entitystore.jooq.JooqEntityStoreService;
 import org.jooq.SQLDialect;
@@ -32,8 +33,9 @@ import org.jooq.conf.RenderNameStyle;
 import org.jooq.conf.Settings;
 
 /**
- * MySQL EntityStore assembly.
+ * JOOQ EntityStore assembly.
  */
+@SuppressWarnings( "WeakerAccess" )
 public class JooqEntityStoreAssembler extends Assemblers.VisibilityIdentityConfig<JooqEntityStoreAssembler>
     implements Assembler
 {
@@ -49,11 +51,12 @@ public class JooqEntityStoreAssembler extends Assemblers.VisibilityIdentityConfi
         }
 
         String identity = ( hasIdentity() ? identity() : DEFAULT_ENTITYSTORE_IDENTITY ).toString();
+        module.transients( JooqDslContext.class );
 
         module.services( JooqEntityStoreService.class )
               .identifiedBy( identity )
               .visibleIn( visibility() )
-              .setMetaInfo( getSQLDialect() )
+              .instantiateOnStartup()
               .setMetaInfo( settings );
 
         if( hasConfig() )