ariatosca-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From emblempar...@apache.org
Subject incubator-ariatosca git commit: Move relationship utilities to be global functions
Date Thu, 16 Mar 2017 17:53:25 GMT
Repository: incubator-ariatosca
Updated Branches:
  refs/heads/ARIA-105-integrate-modeling d3b487366 -> b4b1127ec


Move relationship utilities to be global functions


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/b4b1127e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/b4b1127e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/b4b1127e

Branch: refs/heads/ARIA-105-integrate-modeling
Commit: b4b1127ec1672263c210d97a7c29f52c2fbbbe0f
Parents: d3b4873
Author: Tal Liron <tal.liron@gmail.com>
Authored: Thu Mar 16 12:53:05 2017 -0500
Committer: Tal Liron <tal.liron@gmail.com>
Committed: Thu Mar 16 12:53:05 2017 -0500

----------------------------------------------------------------------
 aria/modeling/mixins.py           | 376 ------------------------------
 aria/modeling/orchestration.py    |  29 +--
 aria/modeling/relationships.py    | 402 +++++++++++++++++++++++++++++++++
 aria/modeling/service_changes.py  |  23 +-
 aria/modeling/service_common.py   |  13 +-
 aria/modeling/service_instance.py | 194 ++++++++--------
 aria/modeling/service_template.py | 186 +++++++--------
 7 files changed, 623 insertions(+), 600 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b4b1127e/aria/modeling/mixins.py
----------------------------------------------------------------------
diff --git a/aria/modeling/mixins.py b/aria/modeling/mixins.py
index 06f2497..8eb08e8 100644
--- a/aria/modeling/mixins.py
+++ b/aria/modeling/mixins.py
@@ -13,32 +13,20 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# pylint: disable=invalid-name
-
 """
-ARIA's storage.structures module
-Path: aria.storage.structures
-
-models module holds ARIA's models.
-
 classes:
     * ModelMixin - abstract model implementation.
     * ModelIDMixin - abstract model implementation with IDs.
 """
 
-from sqlalchemy.orm import relationship, backref
-from sqlalchemy.orm.collections import attribute_mapped_collection
 from sqlalchemy.ext import associationproxy
 from sqlalchemy import (
     Column,
-    ForeignKey,
     Integer,
     Text,
-    Table,
 )
 
 from .utils import classproperty
-from ..utils import formatting
 
 
 class ModelMixin(object):
@@ -107,370 +95,6 @@ class ModelMixin(object):
             cls=self.__class__.__name__,
             id=getattr(self, self.name_column_name()))
 
-    # Model property declaration helpers
-
-    @classmethod
-    def _declare_fk(cls,
-                    other_table,
-                    nullable=False):
-        """
-        Declare a foreign key property, which will also create a foreign key column in the table
-        with the name of the property. By convention the property name should end in "_fk".
-
-        You are required to explicitly create foreign keys in order to allow for one-to-one,
-        one-to-many, and many-to-one relationships (but not for many-to-many relationships). If you
-        do not do so, SqlAlchemy will fail to create the relationship property and raise an
-        exception with a clear error message.
-
-        You should normally not have to access this property directly, but instead use the
-        associated relationship properties.
-
-        *This utility method should only be used during class creation.*
-
-        :param other_table: Other table name
-        :type other_table: basestring
-        :param nullable: True to allow null values (meaning that there is no relationship)
-        :type nullable: bool
-        """
-
-        return Column(Integer,
-                      ForeignKey('{table}.id'.format(table=other_table), ondelete='CASCADE'),
-                      nullable=nullable)
-
-    @classmethod
-    def _declare_one_to_one_self(cls,
-                                 fk,
-                                 relationship_kwargs=None):
-        """
-        Declare a one-to-one relationship property. The property value would be an instance of
-        the same model.
-
-        You will need an associated foreign key to our own table.
-
-        *This utility method should only be used during class creation.*
-
-        :param fk: Foreign key name
-        :type fk: basestring
-        :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
-        :type relationship_kwargs: {}
-        """
-
-        relationship_kwargs = relationship_kwargs or {}
-
-        remote_side = '{cls}.{remote_column}'.format(
-            cls=cls.__name__,
-            remote_column=cls.id_column_name()
-        )
-
-        primaryjoin = '{remote_side} == {cls}.{column}'.format(
-            remote_side=remote_side,
-            cls=cls.__name__,
-            column=fk
-        )
-
-        return relationship(
-            cls._get_class_for_table(cls.__tablename__).__name__,
-            primaryjoin=primaryjoin,
-            remote_side=remote_side,
-            post_update=True,
-            **relationship_kwargs
-        )
-
-    @classmethod
-    def _declare_one_to_many_self(cls,
-                                  fk,
-                                  dict_key=None,
-                                  relationship_kwargs=None):
-        """
-        Declare a one-to-many relationship property. The property value would be a list or dict
-        of instances of the same model.
-
-        You will need an associated foreign key to our own table.
-
-        *This utility method should only be used during class creation.*
-
-        :param fk: Foreign key name
-        :type fk: basestring
-        :param dict_key: If set the value will be a dict with this key as the dict key; otherwise
-                         will be a list
-        :type dict_key: basestring
-        :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
-        :type relationship_kwargs: {}
-        """
-
-        relationship_kwargs = relationship_kwargs or {}
-
-        relationship_kwargs.setdefault('remote_side', '{cls}.{remote_column}'.format(
-            cls=cls.__name__,
-            remote_column=fk
-        ))
-
-        return cls._declare_relationship(cls.__tablename__, None, relationship_kwargs,
-                                         other_property=False, dict_key=dict_key)
-
-    @classmethod
-    def _declare_one_to_one(cls,
-                            other_table,
-                            fk=None,
-                            other_fk=None,
-                            other_property=None,
-                            relationship_kwargs=None,
-                            backref_kwargs=None):
-        """
-        Declare a one-to-one relationship property. The property value would be an instance of
-        the other table's model.
-
-        You have two options for the foreign key. Either this table can have an associated key to
-        the other table (use the `fk` argument) or the other table can have an associated foreign
-        key to this our table (use the `other_fk` argument).
-
-        *This utility method should only be used during class creation.*
-
-        :param other_table: Other table name
-        :type other_table: basestring
-        :param fk: Foreign key name at our table (no need specify if there's no ambiguity)
-        :type fk: basestring
-        :param other_fk: Foreign key name at the other table (no need specify if there's no
-                         ambiguity)
-        :type other_fk: basestring
-        :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
-        :type relationship_kwargs: {}
-        :param backref_kwargs: Extra kwargs for SqlAlchemy `backref`
-        :type backref_kwargs: {}
-        """
-
-        backref_kwargs = backref_kwargs or {}
-        backref_kwargs.setdefault('uselist', False)
-
-        return cls._declare_relationship(other_table, backref_kwargs, relationship_kwargs,
-                                         other_property, fk=fk, other_fk=other_fk)
-
-    @classmethod
-    def _declare_one_to_many(cls,
-                             child_table,
-                             child_fk=None,
-                             dict_key=None,
-                             child_property=None,
-                             relationship_kwargs=None,
-                             backref_kwargs=None):
-        """
-        Declare a one-to-many relationship property. The property value would be a list or dict
-        of instances of the child table's model.
-
-        The child table will need an associated foreign key to our table.
-
-        The declaration will automatically create a matching many-to-one property at the child
-        model, named after our table name. Use the `child_property` argument to override this name.
-
-        *This utility method should only be used during class creation.*
-
-        :param child_table: Child table name
-        :type child_table: basestring
-        :param child_fk: Foreign key name at the child table (no need specify if there's no
-                         ambiguity)
-        :type child_fk: basestring
-        :param dict_key: If set the value will be a dict with this key as the dict key; otherwise
-                         will be a list
-        :type dict_key: basestring
-        :param child_property: Override name of matching many-to-one property at child table; set to
-                               false to disable
-        :type child_property: basestring|bool
-        :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
-        :type relationship_kwargs: {}
-        :param backref_kwargs: Extra kwargs for SqlAlchemy `backref`
-        :type backref_kwargs: {}
-        """
-
-        backref_kwargs = backref_kwargs or {}
-        backref_kwargs.setdefault('uselist', False)
-
-        return cls._declare_relationship(child_table, backref_kwargs, relationship_kwargs,
-                                         child_property, other_fk=child_fk, dict_key=dict_key)
-
-    @classmethod
-    def _declare_many_to_one(cls,
-                             parent_table,
-                             fk=None,
-                             parent_fk=None,
-                             parent_property=None,
-                             relationship_kwargs=None,
-                             backref_kwargs=None):
-        """
-        Declare a many-to-one relationship property. The property value would be an instance of
-        the parent table's model.
-
-        You will need an associated foreign key to the parent table.
-
-        The declaration will automatically create a matching one-to-many property at the child
-        model, named after the plural form of our table name. Use the `parent_property` argument to
-        override this name. Note: the automatic property will always be a SqlAlchemy query object;
-        if you need a Python collection then use :meth:`_declare_one_to_many` at that model.
-
-        *This utility method should only be used during class creation.*
-
-        :param parent_table: Parent table name
-        :type parent_table: basestring
-        :param fk: Foreign key name at our table (no need specify if there's no ambiguity)
-        :type fk: basestring
-        :param parent_property: Override name of matching one-to-many property at parent table; set
-                                to false to disable
-        :type parent_property: basestring|bool
-        :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
-        :type relationship_kwargs: {}
-        :param backref_kwargs: Extra kwargs for SqlAlchemy `backref`
-        :type backref_kwargs: {}
-        """
-
-        if parent_property is None:
-            parent_property = formatting.pluralize(cls.__tablename__)
-
-        backref_kwargs = backref_kwargs or {}
-        backref_kwargs.setdefault('uselist', True)
-        backref_kwargs.setdefault('lazy', 'dynamic')
-        backref_kwargs.setdefault('cascade', 'all') # delete children when parent is deleted
-
-        return cls._declare_relationship(parent_table, backref_kwargs, relationship_kwargs,
-                                         parent_property, fk=fk, other_fk=parent_fk)
-
-    @classmethod
-    def _declare_many_to_many(cls,
-                              other_table,
-                              prefix=None,
-                              dict_key=None,
-                              other_property=None,
-                              relationship_kwargs=None,
-                              backref_kwargs=None):
-        """
-        Declare a many-to-many relationship property. The property value would be a list or dict
-        of instances of the other table's model.
-
-        You do not need associated foreign keys for this relationship. Instead, an extra table will
-        be created for you.
-
-        The declaration will automatically create a matching many-to-many property at the other
-        model, named after the plural form of our table name. Use the `other_property` argument to
-        override this name. Note: the automatic property will always be a SqlAlchemy query object;
-        if you need a Python collection then use :meth:`_declare_many_to_many` again at that model.
-
-        *This utility method should only be used during class creation.*
-
-        :param parent_table: Parent table name
-        :type parent_table: basestring
-        :param prefix: Optional prefix for extra table name as well as for `other_property`
-        :type prefix: basestring
-        :param dict_key: If set the value will be a dict with this key as the dict key; otherwise
-                         will be a list
-        :type dict_key: basestring
-        :param other_property: Override name of matching many-to-many property at other table; set
-                               to false to disable
-        :type other_property: basestring|bool
-        :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
-        :type relationship_kwargs: {}
-        :param backref_kwargs: Extra kwargs for SqlAlchemy `backref`
-        :type backref_kwargs: {}
-        """
-
-        this_table = cls.__tablename__
-        this_column_name = '{0}_id'.format(this_table)
-        this_foreign_key = '{0}.id'.format(this_table)
-
-        other_column_name = '{0}_id'.format(other_table)
-        other_foreign_key = '{0}.id'.format(other_table)
-
-        secondary_table = '{0}_{1}'.format(this_table, other_table)
-
-        if other_property is None:
-            other_property = formatting.pluralize(this_table)
-            if prefix is not None:
-                secondary_table = '{0}_{1}'.format(prefix, secondary_table)
-                other_property = '{0}_{1}'.format(prefix, other_property)
-
-        backref_kwargs = backref_kwargs or {}
-        backref_kwargs.setdefault('uselist', True)
-
-        relationship_kwargs = relationship_kwargs or {}
-        relationship_kwargs.setdefault('secondary', ModelMixin._get_secondary_table(
-            cls.metadata,
-            secondary_table,
-            this_column_name,
-            other_column_name,
-            this_foreign_key,
-            other_foreign_key
-        ))
-
-        return cls._declare_relationship(other_table, backref_kwargs, relationship_kwargs,
-                                         other_property, dict_key=dict_key)
-
-    @classmethod
-    def _declare_relationship(cls, other_table, backref_kwargs, relationship_kwargs,
-                              other_property, fk=None, other_fk=None, dict_key=None):
-        relationship_kwargs = relationship_kwargs or {}
-
-        if fk:
-            relationship_kwargs.setdefault('foreign_keys',
-                                           lambda: getattr(
-                                               cls._get_class_for_table(cls.__tablename__),
-                                               fk))
-
-        elif other_fk:
-            relationship_kwargs.setdefault('foreign_keys',
-                                           lambda: getattr(
-                                               cls._get_class_for_table(other_table),
-                                               other_fk))
-
-        if dict_key:
-            relationship_kwargs.setdefault('collection_class',
-                                           attribute_mapped_collection(dict_key))
-
-        if other_property is False:
-            # No backref
-            return relationship(
-                lambda: cls._get_class_for_table(other_table),
-                **relationship_kwargs
-            )
-        else:
-            if other_property is None:
-                other_property = cls.__tablename__
-            backref_kwargs = backref_kwargs or {}
-            return relationship(
-                lambda: cls._get_class_for_table(other_table),
-                backref=backref(other_property, **backref_kwargs),
-                **relationship_kwargs
-            )
-
-    @classmethod
-    def _get_class_for_table(cls, tablename):
-        if tablename in (cls.__name__, cls.__tablename__):
-            return cls
-
-        for table_cls in cls._decl_class_registry.values():
-            if tablename == getattr(table_cls, '__tablename__', None):
-                return table_cls
-
-        raise ValueError('unknown table: {0}'.format(tablename))
-
-    @staticmethod
-    def _get_secondary_table(metadata,
-                             name,
-                             first_column,
-                             second_column,
-                             first_foreign_key,
-                             second_foreign_key):
-        return Table(
-            name,
-            metadata,
-            Column(
-                first_column,
-                Integer,
-                ForeignKey(first_foreign_key)
-            ),
-            Column(
-                second_column,
-                Integer,
-                ForeignKey(second_foreign_key)
-            )
-        )
-
 
 class ModelIDMixin(object):
     id = Column(Integer, primary_key=True, autoincrement=True)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b4b1127e/aria/modeling/orchestration.py
----------------------------------------------------------------------
diff --git a/aria/modeling/orchestration.py b/aria/modeling/orchestration.py
index 683c526..c5e550a 100644
--- a/aria/modeling/orchestration.py
+++ b/aria/modeling/orchestration.py
@@ -41,12 +41,7 @@ from sqlalchemy.ext.declarative import declared_attr
 from ..orchestrator.exceptions import (TaskAbortException, TaskRetryException)
 from .types import (List, Dict)
 from .mixins import ModelMixin
-
-__all__ = (
-    'ExecutionBase',
-    'PluginBase',
-    'TaskBase'
-)
+from . import relationships
 
 
 class ExecutionBase(ModelMixin):
@@ -101,13 +96,13 @@ class ExecutionBase(ModelMixin):
 
     @declared_attr
     def service(cls):
-        return cls._declare_many_to_one('service')
+        return relationships.many_to_one(cls, 'service')
 
     # region foreign keys
 
     @declared_attr
     def service_fk(cls):
-        return cls._declare_fk('service')
+        return relationships.fk('service')
 
     # endregion
 
@@ -197,23 +192,23 @@ class TaskBase(ModelMixin):
 
     @declared_attr
     def node(cls):
-        return cls._declare_many_to_one('node')
+        return relationships.many_to_one(cls, 'node')
 
     @declared_attr
     def relationship(cls):
-        return cls._declare_many_to_one('relationship')
+        return relationships.many_to_one(cls, 'relationship')
 
     @declared_attr
     def plugin(cls):
-        return cls._declare_many_to_one('plugin')
+        return relationships.many_to_one(cls, 'plugin')
 
     @declared_attr
     def execution(cls):
-        return cls._declare_many_to_one('execution')
+        return relationships.many_to_one(cls, 'execution')
 
     @declared_attr
     def inputs(cls):
-        return cls._declare_many_to_many('parameter', prefix='inputs', dict_key='name')
+        return relationships.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
 
     status = Column(Enum(*STATES, name='status'), default=PENDING)
 
@@ -259,19 +254,19 @@ class TaskBase(ModelMixin):
 
     @declared_attr
     def node_fk(cls):
-        return cls._declare_fk('node', nullable=True)
+        return relationships.fk('node', nullable=True)
 
     @declared_attr
     def relationship_fk(cls):
-        return cls._declare_fk('relationship', nullable=True)
+        return relationships.fk('relationship', nullable=True)
 
     @declared_attr
     def plugin_fk(cls):
-        return cls._declare_fk('plugin', nullable=True)
+        return relationships.fk('plugin', nullable=True)
 
     @declared_attr
     def execution_fk(cls):
-        return cls._declare_fk('execution', nullable=True)
+        return relationships.fk('execution', nullable=True)
 
     # endregion
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b4b1127e/aria/modeling/relationships.py
----------------------------------------------------------------------
diff --git a/aria/modeling/relationships.py b/aria/modeling/relationships.py
new file mode 100644
index 0000000..140b9f1
--- /dev/null
+++ b/aria/modeling/relationships.py
@@ -0,0 +1,402 @@
+# 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.
+
+# pylint: disable=invalid-name, redefined-outer-name
+
+from sqlalchemy.orm import relationship, backref
+from sqlalchemy.orm.collections import attribute_mapped_collection
+from sqlalchemy import (
+    Column,
+    ForeignKey,
+    Integer,
+    Table
+)
+
+from ..utils import formatting
+
+
+def fk(other_table,
+       nullable=False):
+    """
+    Declare a foreign key property, which will also create a foreign key column in the table with
+    the name of the property. By convention the property name should end in "_fk".
+
+    You are required to explicitly create foreign keys in order to allow for one-to-one,
+    one-to-many, and many-to-one relationships (but not for many-to-many relationships). If you do
+    not do so, SqlAlchemy will fail to create the relationship property and raise an exception with
+    a clear error message.
+
+    You should normally not have to access this property directly, but instead use the associated
+    relationship properties.
+
+    *This utility method should only be used during class creation.*
+
+    :param other_table: Other table name
+    :type other_table: basestring
+    :param nullable: True to allow null values (meaning that there is no relationship)
+    :type nullable: bool
+    """
+
+    return Column(Integer,
+                  ForeignKey('{table}.id'.format(table=other_table), ondelete='CASCADE'),
+                  nullable=nullable)
+
+
+def one_to_one_self(model_class,
+                    fk,
+                    relationship_kwargs=None):
+    """
+    Declare a one-to-one relationship property. The property value would be an instance of the same
+    model.
+
+    You will need an associated foreign key to our own table.
+
+    *This utility method should only be used during class creation.*
+
+    :param model_class: The class in which this relationship will be declared
+    :type model_class: type
+    :param fk: Foreign key name
+    :type fk: basestring
+    :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
+    :type relationship_kwargs: {}
+    """
+
+    relationship_kwargs = relationship_kwargs or {}
+
+    remote_side = '{model_class}.{remote_column}'.format(
+        model_class=model_class.__name__,
+        remote_column=model_class.id_column_name()
+    )
+
+    primaryjoin = '{remote_side} == {model_class}.{column}'.format(
+        remote_side=remote_side,
+        model_class=model_class.__name__,
+        column=fk
+    )
+
+    return relationship(
+        _get_class_for_table(model_class, model_class.__tablename__).__name__,
+        primaryjoin=primaryjoin,
+        remote_side=remote_side,
+        post_update=True,
+        **relationship_kwargs
+    )
+
+
+def one_to_many_self(model_class,
+                     fk,
+                     dict_key=None,
+                     relationship_kwargs=None):
+    """
+    Declare a one-to-many relationship property. The property value would be a list or dict of
+    instances of the same model.
+
+    You will need an associated foreign key to our own table.
+
+    *This utility method should only be used during class creation.*
+
+    :param model_class: The class in which this relationship will be declared
+    :type model_class: type
+    :param fk: Foreign key name
+    :type fk: basestring
+    :param dict_key: If set the value will be a dict with this key as the dict key; otherwise will
+                     be a list
+    :type dict_key: basestring
+    :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
+    :type relationship_kwargs: {}
+    """
+
+    relationship_kwargs = relationship_kwargs or {}
+
+    relationship_kwargs.setdefault('remote_side', '{model_class}.{remote_column}'.format(
+        model_class=model_class.__name__,
+        remote_column=fk
+    ))
+
+    return _relationship(model_class, model_class.__tablename__, None, relationship_kwargs,
+                         other_property=False, dict_key=dict_key)
+
+
+def one_to_one(model_class,
+               other_table,
+               fk=None,
+               other_fk=None,
+               other_property=None,
+               relationship_kwargs=None,
+               backref_kwargs=None):
+    """
+    Declare a one-to-one relationship property. The property value would be an instance of the other
+    table's model.
+
+    You have two options for the foreign key. Either this table can have an associated key to the
+    other table (use the `fk` argument) or the other table can have an associated foreign key to
+    this our table (use the `other_fk` argument).
+
+    *This utility method should only be used during class creation.*
+
+    :param model_class: The class in which this relationship will be declared
+    :type model_class: type
+    :param other_table: Other table name
+    :type other_table: basestring
+    :param fk: Foreign key name at our table (no need specify if there's no ambiguity)
+    :type fk: basestring
+    :param other_fk: Foreign key name at the other table (no need specify if there's no ambiguity)
+    :type other_fk: basestring
+    :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
+    :type relationship_kwargs: {}
+    :param backref_kwargs: Extra kwargs for SqlAlchemy `backref`
+    :type backref_kwargs: {}
+    """
+
+    backref_kwargs = backref_kwargs or {}
+    backref_kwargs.setdefault('uselist', False)
+
+    return _relationship(model_class, other_table, backref_kwargs, relationship_kwargs,
+                         other_property, fk=fk, other_fk=other_fk)
+
+
+def one_to_many(model_class,
+                child_table,
+                child_fk=None,
+                dict_key=None,
+                child_property=None,
+                relationship_kwargs=None,
+                backref_kwargs=None):
+    """
+    Declare a one-to-many relationship property. The property value would be a list or dict of
+    instances of the child table's model.
+
+    The child table will need an associated foreign key to our table.
+
+    The declaration will automatically create a matching many-to-one property at the child model,
+    named after our table name. Use the `child_property` argument to override this name.
+
+    *This utility method should only be used during class creation.*
+
+    :param model_class: The class in which this relationship will be declared
+    :type model_class: type
+    :param child_table: Child table name
+    :type child_table: basestring
+    :param child_fk: Foreign key name at the child table (no need specify if there's no ambiguity)
+    :type child_fk: basestring
+    :param dict_key: If set the value will be a dict with this key as the dict key; otherwise will
+                     be a list
+    :type dict_key: basestring
+    :param child_property: Override name of matching many-to-one property at child table; set to
+                           false to disable
+    :type child_property: basestring|bool
+    :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
+    :type relationship_kwargs: {}
+    :param backref_kwargs: Extra kwargs for SqlAlchemy `backref`
+    :type backref_kwargs: {}
+    """
+
+    backref_kwargs = backref_kwargs or {}
+    backref_kwargs.setdefault('uselist', False)
+
+    return _relationship(model_class, child_table, backref_kwargs, relationship_kwargs,
+                         child_property, other_fk=child_fk, dict_key=dict_key)
+
+
+def many_to_one(model_class,
+                parent_table,
+                fk=None,
+                parent_fk=None,
+                parent_property=None,
+                relationship_kwargs=None,
+                backref_kwargs=None):
+    """
+    Declare a many-to-one relationship property. The property value would be an instance of the
+    parent table's model.
+
+    You will need an associated foreign key to the parent table.
+
+    The declaration will automatically create a matching one-to-many property at the child model,
+    named after the plural form of our table name. Use the `parent_property` argument to override
+    this name. Note: the automatic property will always be a SqlAlchemy query object; if you need a
+    Python collection then use :meth:`one_to_many` at that model.
+
+    *This utility method should only be used during class creation.*
+
+    :param model_class: The class in which this relationship will be declared
+    :type model_class: type
+    :param parent_table: Parent table name
+    :type parent_table: basestring
+    :param fk: Foreign key name at our table (no need specify if there's no ambiguity)
+    :type fk: basestring
+    :param parent_property: Override name of matching one-to-many property at parent table; set to
+                            false to disable
+    :type parent_property: basestring|bool
+    :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
+    :type relationship_kwargs: {}
+    :param backref_kwargs: Extra kwargs for SqlAlchemy `backref`
+    :type backref_kwargs: {}
+    """
+
+    if parent_property is None:
+        parent_property = formatting.pluralize(model_class.__tablename__)
+
+    backref_kwargs = backref_kwargs or {}
+    backref_kwargs.setdefault('uselist', True)
+    backref_kwargs.setdefault('lazy', 'dynamic')
+    backref_kwargs.setdefault('cascade', 'all') # delete children when parent is deleted
+
+    return _relationship(model_class, parent_table, backref_kwargs, relationship_kwargs,
+                         parent_property, fk=fk, other_fk=parent_fk)
+
+
+def many_to_many(model_class,
+                 other_table,
+                 prefix=None,
+                 dict_key=None,
+                 other_property=None,
+                 relationship_kwargs=None,
+                 backref_kwargs=None):
+    """
+    Declare a many-to-many relationship property. The property value would be a list or dict of
+    instances of the other table's model.
+
+    You do not need associated foreign keys for this relationship. Instead, an extra table will be
+    created for you.
+
+    The declaration will automatically create a matching many-to-many property at the other model,
+    named after the plural form of our table name. Use the `other_property` argument to override
+    this name. Note: the automatic property will always be a SqlAlchemy query object; if you need a
+    Python collection then use :meth:`many_to_many` again at that model.
+
+    *This utility method should only be used during class creation.*
+
+    :param model_class: The class in which this relationship will be declared
+    :type model_class: type
+    :param parent_table: Parent table name
+    :type parent_table: basestring
+    :param prefix: Optional prefix for extra table name as well as for `other_property`
+    :type prefix: basestring
+    :param dict_key: If set the value will be a dict with this key as the dict key; otherwise will
+                     be a list
+    :type dict_key: basestring
+    :param other_property: Override name of matching many-to-many property at other table; set to
+                           false to disable
+    :type other_property: basestring|bool
+    :param relationship_kwargs: Extra kwargs for SqlAlchemy `relationship`
+    :type relationship_kwargs: {}
+    :param backref_kwargs: Extra kwargs for SqlAlchemy `backref`
+    :type backref_kwargs: {}
+    """
+
+    this_table = model_class.__tablename__
+    this_column_name = '{0}_id'.format(this_table)
+    this_foreign_key = '{0}.id'.format(this_table)
+
+    other_column_name = '{0}_id'.format(other_table)
+    other_foreign_key = '{0}.id'.format(other_table)
+
+    secondary_table = '{0}_{1}'.format(this_table, other_table)
+
+    if other_property is None:
+        other_property = formatting.pluralize(this_table)
+        if prefix is not None:
+            secondary_table = '{0}_{1}'.format(prefix, secondary_table)
+            other_property = '{0}_{1}'.format(prefix, other_property)
+
+    backref_kwargs = backref_kwargs or {}
+    backref_kwargs.setdefault('uselist', True)
+
+    relationship_kwargs = relationship_kwargs or {}
+    relationship_kwargs.setdefault('secondary', _get_secondary_table(
+        model_class.metadata,
+        secondary_table,
+        this_column_name,
+        other_column_name,
+        this_foreign_key,
+        other_foreign_key
+    ))
+
+    return _relationship(model_class, other_table, backref_kwargs, relationship_kwargs,
+                         other_property, dict_key=dict_key)
+
+
+def _relationship(model_class, other_table, backref_kwargs, relationship_kwargs, other_property,
+                  fk=None, other_fk=None, dict_key=None):
+    relationship_kwargs = relationship_kwargs or {}
+
+    if fk:
+        relationship_kwargs.setdefault('foreign_keys',
+                                       lambda: getattr(
+                                           _get_class_for_table(
+                                               model_class,
+                                               model_class.__tablename__),
+                                           fk))
+
+    elif other_fk:
+        relationship_kwargs.setdefault('foreign_keys',
+                                       lambda: getattr(
+                                           _get_class_for_table(
+                                               model_class,
+                                               other_table),
+                                           other_fk))
+
+    if dict_key:
+        relationship_kwargs.setdefault('collection_class',
+                                       attribute_mapped_collection(dict_key))
+
+    if other_property is False:
+        # No backref
+        return relationship(
+            lambda: _get_class_for_table(model_class, other_table),
+            **relationship_kwargs
+        )
+    else:
+        if other_property is None:
+            other_property = model_class.__tablename__
+        backref_kwargs = backref_kwargs or {}
+        return relationship(
+            lambda: _get_class_for_table(model_class, other_table),
+            backref=backref(other_property, **backref_kwargs),
+            **relationship_kwargs
+        )
+
+
+def _get_class_for_table(model_class, tablename):
+    if tablename in (model_class.__name__, model_class.__tablename__):
+        return model_class
+
+    for table_cls in model_class._decl_class_registry.values():
+        if tablename == getattr(table_cls, '__tablename__', None):
+            return table_cls
+
+    raise ValueError('unknown table: {0}'.format(tablename))
+
+
+def _get_secondary_table(metadata,
+                         name,
+                         first_column,
+                         second_column,
+                         first_foreign_key,
+                         second_foreign_key):
+    return Table(
+        name,
+        metadata,
+        Column(
+            first_column,
+            Integer,
+            ForeignKey(first_foreign_key)
+        ),
+        Column(
+            second_column,
+            Integer,
+            ForeignKey(second_foreign_key)
+        )
+    )

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b4b1127e/aria/modeling/service_changes.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_changes.py b/aria/modeling/service_changes.py
index eb7bb27..a5c6658 100644
--- a/aria/modeling/service_changes.py
+++ b/aria/modeling/service_changes.py
@@ -35,12 +35,7 @@ from sqlalchemy.ext.declarative import declared_attr
 
 from .types import (List, Dict)
 from .mixins import ModelMixin
-
-__all__ = (
-    'ServiceUpdateBase',
-    'ServiceUpdateStepBase',
-    'ServiceModificationBase'
-)
+from . import relationships
 
 
 class ServiceUpdateBase(ModelMixin):
@@ -65,21 +60,21 @@ class ServiceUpdateBase(ModelMixin):
 
     @declared_attr
     def execution(cls):
-        return cls._declare_many_to_one('execution')
+        return relationships.many_to_one(cls, 'execution')
 
     @declared_attr
     def service(cls):
-        return cls._declare_many_to_one('service', parent_property='updates')
+        return relationships.many_to_one(cls, 'service', parent_property='updates')
 
     # region foreign keys
 
     @declared_attr
     def execution_fk(cls):
-        return cls._declare_fk('execution', nullable=True)
+        return relationships.fk('execution', nullable=True)
 
     @declared_attr
     def service_fk(cls):
-        return cls._declare_fk('service')
+        return relationships.fk('service')
 
     # endregion
 
@@ -140,13 +135,13 @@ class ServiceUpdateStepBase(ModelMixin):
 
     @declared_attr
     def service_update(cls):
-        return cls._declare_many_to_one('service_update', parent_property='steps')
+        return relationships.many_to_one(cls, 'service_update', parent_property='steps')
 
     # region foreign keys
 
     @declared_attr
     def service_update_fk(cls):
-        return cls._declare_fk('service_update')
+        return relationships.fk('service_update')
 
     # endregion
 
@@ -213,13 +208,13 @@ class ServiceModificationBase(ModelMixin):
 
     @declared_attr
     def service(cls):
-        return cls._declare_many_to_one('service', parent_property='modifications')
+        return relationships.many_to_one(cls, 'service', parent_property='modifications')
 
     # region foreign keys
 
     @declared_attr
     def service_fk(cls):
-        return cls._declare_fk('service')
+        return relationships.fk('service')
 
     # endregion
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b4b1127e/aria/modeling/service_common.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_common.py b/aria/modeling/service_common.py
index 746f403..3ff0555 100644
--- a/aria/modeling/service_common.py
+++ b/aria/modeling/service_common.py
@@ -26,7 +26,10 @@ from ..parser.consumption import ConsumptionContext
 from ..utils import collections, formatting, console
 from .mixins import InstanceModelMixin, TemplateModelMixin
 from .types import List
-from . import utils
+from . import (
+    relationships,
+    utils
+)
 
 
 class ParameterBase(TemplateModelMixin):
@@ -114,18 +117,18 @@ class TypeBase(InstanceModelMixin):
 
     @declared_attr
     def parent(cls):
-        return cls._declare_one_to_one_self('parent_type_fk')
+        return relationships.one_to_one_self(cls, 'parent_type_fk')
 
     @declared_attr
     def children(cls):
-        return cls._declare_one_to_many_self('parent_type_fk')
+        return relationships.one_to_many_self(cls, 'parent_type_fk')
 
     # region foreign keys
 
     @declared_attr
     def parent_type_fk(cls):
         """For Type one-to-many to Type"""
-        return cls._declare_fk('type', nullable=True)
+        return relationships.fk('type', nullable=True)
 
     # endregion
 
@@ -251,7 +254,7 @@ class PluginSpecificationBase(InstanceModelMixin):
     @declared_attr
     def service_template_fk(cls):
         """For ServiceTemplate one-to-many to PluginSpecification"""
-        return cls._declare_fk('service_template', nullable=True)
+        return relationships.fk('service_template', nullable=True)
 
     # endregion
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b4b1127e/aria/modeling/service_instance.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_instance.py b/aria/modeling/service_instance.py
index 13f355d..63fd9cc 100644
--- a/aria/modeling/service_instance.py
+++ b/aria/modeling/service_instance.py
@@ -28,8 +28,8 @@ from .mixins import InstanceModelMixin
 from ..parser import validation
 from ..parser.consumption import ConsumptionContext
 from ..utils import collections, formatting, console
-
 from . import (
+    relationships,
     utils,
     types as modeling_types
 )
@@ -88,46 +88,46 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
 
     @declared_attr
     def service_template(cls):
-        return cls._declare_many_to_one('service_template')
+        return relationships.many_to_one(cls, 'service_template')
 
     description = Column(Text)
 
     @declared_attr
     def meta_data(cls):
         # Warning! We cannot use the attr name "metadata" because it's used by SqlAlchemy!
-        return cls._declare_many_to_many('metadata', dict_key='name')
+        return relationships.many_to_many(cls, 'metadata', dict_key='name')
 
     @declared_attr
     def nodes(cls):
-        return cls._declare_one_to_many('node', dict_key='name')
+        return relationships.one_to_many(cls, 'node', dict_key='name')
 
     @declared_attr
     def groups(cls):
-        return cls._declare_one_to_many('group', dict_key='name')
+        return relationships.one_to_many(cls, 'group', dict_key='name')
 
     @declared_attr
     def policies(cls):
-        return cls._declare_one_to_many('policy', dict_key='name')
+        return relationships.one_to_many(cls, 'policy', dict_key='name')
 
     @declared_attr
     def substitution(cls):
-        return cls._declare_one_to_one('substitution')
+        return relationships.one_to_one(cls, 'substitution')
 
     @declared_attr
     def inputs(cls):
-        return cls._declare_many_to_many('parameter', prefix='inputs', dict_key='name')
+        return relationships.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
 
     @declared_attr
     def outputs(cls):
-        return cls._declare_many_to_many('parameter', prefix='outputs', dict_key='name')
+        return relationships.many_to_many(cls, 'parameter', prefix='outputs', dict_key='name')
 
     @declared_attr
     def workflows(cls):
-        return cls._declare_one_to_many('operation', dict_key='name')
+        return relationships.one_to_many(cls, 'operation', dict_key='name')
 
     @declared_attr
     def plugin_specifications(cls):
-        return cls._declare_many_to_many('plugin_specification')
+        return relationships.many_to_many(cls, 'plugin_specification')
 
     created_at = Column(DateTime, nullable=False, index=True)
     updated_at = Column(DateTime)
@@ -144,12 +144,12 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
     @declared_attr
     def substitution_fk(cls):
         """Service one-to-one to Substitution"""
-        return cls._declare_fk('substitution', nullable=True)
+        return relationships.fk('substitution', nullable=True)
 
     @declared_attr
     def service_template_fk(cls):
         """For Service many-to-one to ServiceTemplate"""
-        return cls._declare_fk('service_template', nullable=True)
+        return relationships.fk('service_template', nullable=True)
 
     # endregion
 
@@ -337,47 +337,47 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
 
     @declared_attr
     def node_template(cls):
-        return cls._declare_many_to_one('node_template')
+        return relationships.many_to_one(cls, 'node_template')
 
     @declared_attr
     def type(cls):
-        return cls._declare_many_to_one('type')
+        return relationships.many_to_one(cls, 'type')
 
     description = Column(Text)
 
     @declared_attr
     def properties(cls):
-        return cls._declare_many_to_many('parameter', prefix='properties', dict_key='name')
+        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     @declared_attr
     def interfaces(cls):
-        return cls._declare_one_to_many('interface', dict_key='name')
+        return relationships.one_to_many(cls, 'interface', dict_key='name')
 
     @declared_attr
     def artifacts(cls):
-        return cls._declare_one_to_many('artifact', dict_key='name')
+        return relationships.one_to_many(cls, 'artifact', dict_key='name')
 
     @declared_attr
     def capabilities(cls):
-        return cls._declare_one_to_many('capability', dict_key='name')
+        return relationships.one_to_many(cls, 'capability', dict_key='name')
 
     @declared_attr
     def outbound_relationships(cls):
-        return cls._declare_one_to_many('relationship', child_fk='source_node_fk',
-                                        child_property='source_node')
+        return relationships.one_to_many(cls, 'relationship', child_fk='source_node_fk',
+                                         child_property='source_node')
 
     @declared_attr
     def inbound_relationships(cls):
-        return cls._declare_one_to_many('relationship', child_fk='target_node_fk',
-                                        child_property='target_node')
+        return relationships.one_to_many(cls, 'relationship', child_fk='target_node_fk',
+                                         child_property='target_node')
 
     @declared_attr
     def plugin_specifications(cls):
-        return cls._declare_many_to_many('plugin_specification', dict_key='name')
+        return relationships.many_to_many(cls, 'plugin_specification', dict_key='name')
 
     @declared_attr
     def host(cls):
-        return cls._declare_one_to_one_self('host_fk')
+        return relationships.one_to_one_self(cls, 'host_fk')
 
     # region orchestration
 
@@ -407,22 +407,22 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
     @declared_attr
     def type_fk(cls):
         """For Node many-to-one to Type"""
-        return cls._declare_fk('type')
+        return relationships.fk('type')
 
     @declared_attr
     def host_fk(cls):
         """For Node one-to-one to Node"""
-        return cls._declare_fk('node', nullable=True)
+        return relationships.fk('node', nullable=True)
 
     @declared_attr
     def service_fk(cls):
         """For Service one-to-many to Node"""
-        return cls._declare_fk('service')
+        return relationships.fk('service')
 
     @declared_attr
     def node_template_fk(cls):
         """For Node many-to-one to NodeTemplate"""
-        return cls._declare_fk('node_template', nullable=True)
+        return relationships.fk('node_template', nullable=True)
 
     # endregion
 
@@ -603,42 +603,42 @@ class GroupBase(InstanceModelMixin):
 
     @declared_attr
     def group_template(cls):
-        return cls._declare_many_to_one('group_template')
+        return relationships.many_to_one(cls, 'group_template')
 
     @declared_attr
     def type(cls):
-        return cls._declare_many_to_one('type')
+        return relationships.many_to_one(cls, 'type')
 
     description = Column(Text)
 
     @declared_attr
     def nodes(cls):
-        return cls._declare_many_to_many('node')
+        return relationships.many_to_many(cls, 'node')
 
     @declared_attr
     def properties(cls):
-        return cls._declare_many_to_many('parameter', prefix='properties', dict_key='name')
+        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     @declared_attr
     def interfaces(cls):
-        return cls._declare_one_to_many('interface', dict_key='name')
+        return relationships.one_to_many(cls, 'interface', dict_key='name')
 
     # region foreign_keys
 
     @declared_attr
     def type_fk(cls):
         """For Group many-to-one to Type"""
-        return cls._declare_fk('type')
+        return relationships.fk('type')
 
     @declared_attr
     def service_fk(cls):
         """For Service one-to-many to Group"""
-        return cls._declare_fk('service')
+        return relationships.fk('service')
 
     @declared_attr
     def group_template_fk(cls):
         """For Group many-to-one to GroupTemplate"""
-        return cls._declare_fk('group_template', nullable=True)
+        return relationships.fk('group_template', nullable=True)
 
     # endregion
 
@@ -702,42 +702,42 @@ class PolicyBase(InstanceModelMixin):
 
     @declared_attr
     def policy_template(cls):
-        return cls._declare_many_to_one('policy_template')
+        return relationships.many_to_one(cls, 'policy_template')
 
     @declared_attr
     def type(cls):
-        return cls._declare_many_to_one('type')
+        return relationships.many_to_one(cls, 'type')
 
     description = Column(Text)
 
     @declared_attr
     def properties(cls):
-        return cls._declare_many_to_many('parameter', prefix='properties', dict_key='name')
+        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     @declared_attr
     def nodes(cls):
-        return cls._declare_many_to_many('node')
+        return relationships.many_to_many(cls, 'node')
 
     @declared_attr
     def groups(cls):
-        return cls._declare_many_to_many('group')
+        return relationships.many_to_many(cls, 'group')
 
     # region foreign_keys
 
     @declared_attr
     def type_fk(cls):
         """For Policy many-to-one to Type"""
-        return cls._declare_fk('type')
+        return relationships.fk('type')
 
     @declared_attr
     def service_fk(cls):
         """For Service one-to-many to Policy"""
-        return cls._declare_fk('service')
+        return relationships.fk('service')
 
     @declared_attr
     def policy_template_fk(cls):
         """For Policy many-to-one to PolicyTemplate"""
-        return cls._declare_fk('policy_template', nullable=True)
+        return relationships.fk('policy_template', nullable=True)
 
     # endregion
 
@@ -797,27 +797,27 @@ class SubstitutionBase(InstanceModelMixin):
 
     @declared_attr
     def substitution_template(cls):
-        return cls._declare_many_to_one('substitution_template')
+        return relationships.many_to_one(cls, 'substitution_template')
 
     @declared_attr
     def node_type(cls):
-        return cls._declare_many_to_one('type')
+        return relationships.many_to_one(cls, 'type')
 
     @declared_attr
     def mappings(cls):
-        return cls._declare_one_to_many('substitution_mapping', dict_key='name')
+        return relationships.one_to_many(cls, 'substitution_mapping', dict_key='name')
 
     # region foreign_keys
 
     @declared_attr
     def node_type_fk(cls):
         """For Substitution many-to-one to Type"""
-        return cls._declare_fk('type')
+        return relationships.fk('type')
 
     @declared_attr
     def substitution_template_fk(cls):
         """For Substitution many-to-one to SubstitutionTemplate"""
-        return cls._declare_fk('substitution_template', nullable=True)
+        return relationships.fk('substitution_template', nullable=True)
 
     # endregion
 
@@ -869,37 +869,37 @@ class SubstitutionMappingBase(InstanceModelMixin):
 
     @declared_attr
     def node(cls):
-        return cls._declare_one_to_one('node')
+        return relationships.one_to_one(cls, 'node')
 
     @declared_attr
     def capability(cls):
-        return cls._declare_one_to_one('capability')
+        return relationships.one_to_one(cls, 'capability')
 
     @declared_attr
     def requirement_template(cls):
-        return cls._declare_one_to_one('requirement_template')
+        return relationships.one_to_one(cls, 'requirement_template')
 
     # region foreign keys
 
     @declared_attr
     def substitution_fk(cls):
         """For Substitution one-to-many to SubstitutionMapping"""
-        return cls._declare_fk('substitution')
+        return relationships.fk('substitution')
 
     @declared_attr
     def node_fk(cls):
         """For Substitution one-to-one to NodeTemplate"""
-        return cls._declare_fk('node')
+        return relationships.fk('node')
 
     @declared_attr
     def capability_fk(cls):
         """For Substitution one-to-one to Capability"""
-        return cls._declare_fk('capability', nullable=True)
+        return relationships.fk('capability', nullable=True)
 
     @declared_attr
     def requirement_template_fk(cls):
         """For Substitution one-to-one to RequirementTemplate"""
-        return cls._declare_fk('requirement_template', nullable=True)
+        return relationships.fk('requirement_template', nullable=True)
 
     # endregion
 
@@ -970,27 +970,27 @@ class RelationshipBase(InstanceModelMixin):
 
     @declared_attr
     def relationship_template(cls):
-        return cls._declare_many_to_one('relationship_template')
+        return relationships.many_to_one(cls, 'relationship_template')
 
     @declared_attr
     def requirement_template(cls):
-        return cls._declare_many_to_one('requirement_template')
+        return relationships.many_to_one(cls, 'requirement_template')
 
     @declared_attr
     def type(cls):
-        return cls._declare_many_to_one('type')
+        return relationships.many_to_one(cls, 'type')
 
     @declared_attr
     def target_capability(cls):
-        return cls._declare_one_to_one('capability')
+        return relationships.one_to_one(cls, 'capability')
 
     @declared_attr
     def properties(cls):
-        return cls._declare_many_to_many('parameter', prefix='properties', dict_key='name')
+        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     @declared_attr
     def interfaces(cls):
-        return cls._declare_one_to_many('interface', dict_key='name')
+        return relationships.one_to_many(cls, 'interface', dict_key='name')
 
     # region orchestration
 
@@ -1004,32 +1004,32 @@ class RelationshipBase(InstanceModelMixin):
     @declared_attr
     def type_fk(cls):
         """For Relationship many-to-one to Type"""
-        return cls._declare_fk('type', nullable=True)
+        return relationships.fk('type', nullable=True)
 
     @declared_attr
     def source_node_fk(cls):
         """For Node one-to-many to Relationship"""
-        return cls._declare_fk('node')
+        return relationships.fk('node')
 
     @declared_attr
     def target_node_fk(cls):
         """For Node one-to-many to Relationship"""
-        return cls._declare_fk('node')
+        return relationships.fk('node')
 
     @declared_attr
     def target_capability_fk(cls):
         """For Relationship one-to-one to Capability"""
-        return cls._declare_fk('capability', nullable=True)
+        return relationships.fk('capability', nullable=True)
 
     @declared_attr
     def requirement_template_fk(cls):
         """For Relationship many-to-one to RequirementTemplate"""
-        return cls._declare_fk('requirement_template', nullable=True)
+        return relationships.fk('requirement_template', nullable=True)
 
     @declared_attr
     def relationship_template_fk(cls):
         """For Relationship many-to-one to RelationshipTemplate"""
-        return cls._declare_fk('relationship_template', nullable=True)
+        return relationships.fk('relationship_template', nullable=True)
 
     # endregion
 
@@ -1129,11 +1129,11 @@ class CapabilityBase(InstanceModelMixin):
 
     @declared_attr
     def capability_template(cls):
-        return cls._declare_many_to_one('capability_template')
+        return relationships.many_to_one(cls, 'capability_template')
 
     @declared_attr
     def type(cls):
-        return cls._declare_many_to_one('type')
+        return relationships.many_to_one(cls, 'type')
 
     min_occurrences = Column(Integer, default=None)
     max_occurrences = Column(Integer, default=None)
@@ -1141,24 +1141,24 @@ class CapabilityBase(InstanceModelMixin):
 
     @declared_attr
     def properties(cls):
-        return cls._declare_many_to_many('parameter', prefix='properties', dict_key='name')
+        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     # region foreign_keys
 
     @declared_attr
     def type_fk(cls):
         """For Capability many-to-one to Type"""
-        return cls._declare_fk('type')
+        return relationships.fk('type')
 
     @declared_attr
     def node_fk(cls):
         """For Node one-to-many to Capability"""
-        return cls._declare_fk('node')
+        return relationships.fk('node')
 
     @declared_attr
     def capability_template_fk(cls):
         """For Capability many-to-one to CapabilityTemplate"""
-        return cls._declare_fk('capability_template', nullable=True)
+        return relationships.fk('capability_template', nullable=True)
 
     # endregion
 
@@ -1237,48 +1237,48 @@ class InterfaceBase(InstanceModelMixin):
 
     @declared_attr
     def interface_template(cls):
-        return cls._declare_many_to_one('interface_template')
+        return relationships.many_to_one(cls, 'interface_template')
 
     @declared_attr
     def type(cls):
-        return cls._declare_many_to_one('type')
+        return relationships.many_to_one(cls, 'type')
 
     description = Column(Text)
 
     @declared_attr
     def inputs(cls):
-        return cls._declare_many_to_many('parameter', prefix='inputs', dict_key='name')
+        return relationships.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
 
     @declared_attr
     def operations(cls):
-        return cls._declare_one_to_many('operation', dict_key='name')
+        return relationships.one_to_many(cls, 'operation', dict_key='name')
 
     # region foreign_keys
 
     @declared_attr
     def type_fk(cls):
         """For Interface many-to-one to Type"""
-        return cls._declare_fk('type')
+        return relationships.fk('type')
 
     @declared_attr
     def node_fk(cls):
         """For Node one-to-many to Interface"""
-        return cls._declare_fk('node', nullable=True)
+        return relationships.fk('node', nullable=True)
 
     @declared_attr
     def group_fk(cls):
         """For Group one-to-many to Interface"""
-        return cls._declare_fk('group', nullable=True)
+        return relationships.fk('group', nullable=True)
 
     @declared_attr
     def relationship_fk(cls):
         """For Relationship one-to-many to Interface"""
-        return cls._declare_fk('relationship', nullable=True)
+        return relationships.fk('relationship', nullable=True)
 
     @declared_attr
     def interface_template_fk(cls):
         """For Interface many-to-one to InterfaceTemplate"""
-        return cls._declare_fk('interface_template', nullable=True)
+        return relationships.fk('interface_template', nullable=True)
 
     # endregion
 
@@ -1353,20 +1353,20 @@ class OperationBase(InstanceModelMixin):
 
     @declared_attr
     def operation_template(cls):
-        return cls._declare_many_to_one('operation_template')
+        return relationships.many_to_one(cls, 'operation_template')
 
     description = Column(Text)
 
     @declared_attr
     def plugin_specification(cls):
-        return cls._declare_one_to_one('plugin_specification')
+        return relationships.one_to_one(cls, 'plugin_specification')
 
     implementation = Column(Text)
     dependencies = Column(modeling_types.StrictList(item_cls=basestring))
 
     @declared_attr
     def inputs(cls):
-        return cls._declare_many_to_many('parameter', prefix='inputs', dict_key='name')
+        return relationships.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
 
     executor = Column(Text)
     max_retries = Column(Integer)
@@ -1377,22 +1377,22 @@ class OperationBase(InstanceModelMixin):
     @declared_attr
     def service_fk(cls):
         """For Service one-to-many to Operation"""
-        return cls._declare_fk('service', nullable=True)
+        return relationships.fk('service', nullable=True)
 
     @declared_attr
     def interface_fk(cls):
         """For Interface one-to-many to Operation"""
-        return cls._declare_fk('interface', nullable=True)
+        return relationships.fk('interface', nullable=True)
 
     @declared_attr
     def plugin_specification_fk(cls):
         """For Operation one-to-one to PluginSpecification"""
-        return cls._declare_fk('plugin_specification', nullable=True)
+        return relationships.fk('plugin_specification', nullable=True)
 
     @declared_attr
     def operation_template_fk(cls):
         """For Operation many-to-one to OperationTemplate"""
-        return cls._declare_fk('operation_template', nullable=True)
+        return relationships.fk('operation_template', nullable=True)
 
     # endregion
 
@@ -1476,11 +1476,11 @@ class ArtifactBase(InstanceModelMixin):
 
     @declared_attr
     def artifact_template(cls):
-        return cls._declare_many_to_one('artifact_template')
+        return relationships.many_to_one(cls, 'artifact_template')
 
     @declared_attr
     def type(cls):
-        return cls._declare_many_to_one('type')
+        return relationships.many_to_one(cls, 'type')
 
     description = Column(Text)
     source_path = Column(Text)
@@ -1490,24 +1490,24 @@ class ArtifactBase(InstanceModelMixin):
 
     @declared_attr
     def properties(cls):
-        return cls._declare_many_to_many('parameter', prefix='properties', dict_key='name')
+        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     # region foreign_keys
 
     @declared_attr
     def type_fk(cls):
         """For Artifact many-to-one to Type"""
-        return cls._declare_fk('type')
+        return relationships.fk('type')
 
     @declared_attr
     def node_fk(cls):
         """For Node one-to-many to Artifact"""
-        return cls._declare_fk('node')
+        return relationships.fk('node')
 
     @declared_attr
     def artifact_template_fk(cls):
         """For Artifact many-to-one to ArtifactTemplate"""
-        return cls._declare_fk('artifact_template', nullable=True)
+        return relationships.fk('artifact_template', nullable=True)
 
     # endregion
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b4b1127e/aria/modeling/service_template.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_template.py b/aria/modeling/service_template.py
index b365720..d93cbf3 100644
--- a/aria/modeling/service_template.py
+++ b/aria/modeling/service_template.py
@@ -35,6 +35,7 @@ from ..parser.reading import deepcopy_with_locators
 from ..utils import collections, formatting, console
 from .mixins import TemplateModelMixin
 from . import (
+    relationships,
     utils,
     types as modeling_types
 )
@@ -104,67 +105,68 @@ class ServiceTemplateBase(TemplateModelMixin): # pylint: disable=too-many-public
     @declared_attr
     def meta_data(cls):
         # Warning! We cannot use the attr name "metadata" because it's used by SqlAlchemy!
-        return cls._declare_many_to_many('metadata', dict_key='name')
+        return relationships.many_to_many(cls, 'metadata', dict_key='name')
 
     @declared_attr
     def node_templates(cls):
-        return cls._declare_one_to_many('node_template', dict_key='name')
+        return relationships.one_to_many(cls, 'node_template', dict_key='name')
 
     @declared_attr
     def group_templates(cls):
-        return cls._declare_one_to_many('group_template', dict_key='name')
+        return relationships.one_to_many(cls, 'group_template', dict_key='name')
 
     @declared_attr
     def policy_templates(cls):
-        return cls._declare_one_to_many('policy_template', dict_key='name')
+        return relationships.one_to_many(cls, 'policy_template', dict_key='name')
 
     @declared_attr
     def substitution_template(cls):
-        return cls._declare_one_to_one('substitution_template')
+        return relationships.one_to_one(cls, 'substitution_template')
 
     @declared_attr
     def inputs(cls):
-        return cls._declare_many_to_many('parameter', prefix='inputs', dict_key='name')
+        return relationships.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
 
     @declared_attr
     def outputs(cls):
-        return cls._declare_many_to_many('parameter', prefix='outputs', dict_key='name')
+        return relationships.many_to_many(cls, 'parameter', prefix='outputs', dict_key='name')
 
     @declared_attr
     def workflow_templates(cls):
-        return cls._declare_one_to_many('operation_template', dict_key='name')
+        return relationships.one_to_many(cls, 'operation_template', dict_key='name')
 
     @declared_attr
     def plugin_specifications(cls):
-        return cls._declare_one_to_many('plugin_specification', dict_key='name')
+        return relationships.one_to_many(cls, 'plugin_specification', dict_key='name')
 
     @declared_attr
     def node_types(cls):
-        return cls._declare_one_to_one('type', fk='node_type_fk', other_property=False)
+        return relationships.one_to_one(cls, 'type', fk='node_type_fk', other_property=False)
 
     @declared_attr
     def group_types(cls):
-        return cls._declare_one_to_one('type', fk='group_type_fk', other_property=False)
+        return relationships.one_to_one(cls, 'type', fk='group_type_fk', other_property=False)
 
     @declared_attr
     def policy_types(cls):
-        return cls._declare_one_to_one('type', fk='policy_type_fk', other_property=False)
+        return relationships.one_to_one(cls, 'type', fk='policy_type_fk', other_property=False)
 
     @declared_attr
     def relationship_types(cls):
-        return cls._declare_one_to_one('type', fk='relationship_type_fk', other_property=False)
+        return relationships.one_to_one(cls, 'type', fk='relationship_type_fk',
+                                        other_property=False)
 
     @declared_attr
     def capability_types(cls):
-        return cls._declare_one_to_one('type', fk='capability_type_fk', other_property=False)
+        return relationships.one_to_one(cls, 'type', fk='capability_type_fk', other_property=False)
 
     @declared_attr
     def interface_types(cls):
-        return cls._declare_one_to_one('type', fk='interface_type_fk', other_property=False)
+        return relationships.one_to_one(cls, 'type', fk='interface_type_fk', other_property=False)
 
     @declared_attr
     def artifact_types(cls):
-        return cls._declare_one_to_one('type', fk='artifact_type_fk', other_property=False)
+        return relationships.one_to_one(cls, 'type', fk='artifact_type_fk', other_property=False)
 
     # region orchestration
 
@@ -178,42 +180,42 @@ class ServiceTemplateBase(TemplateModelMixin): # pylint: disable=too-many-public
     @declared_attr
     def substitution_template_fk(cls):
         """For ServiceTemplate one-to-one to SubstitutionTemplate"""
-        return cls._declare_fk('substitution_template', nullable=True)
+        return relationships.fk('substitution_template', nullable=True)
 
     @declared_attr
     def node_type_fk(cls):
         """For ServiceTemplate one-to-one to Type"""
-        return cls._declare_fk('type', nullable=True)
+        return relationships.fk('type', nullable=True)
 
     @declared_attr
     def group_type_fk(cls):
         """For ServiceTemplate one-to-one to Type"""
-        return cls._declare_fk('type', nullable=True)
+        return relationships.fk('type', nullable=True)
 
     @declared_attr
     def policy_type_fk(cls):
         """For ServiceTemplate one-to-one to Type"""
-        return cls._declare_fk('type', nullable=True)
+        return relationships.fk('type', nullable=True)
 
     @declared_attr
     def relationship_type_fk(cls):
         """For ServiceTemplate one-to-one to Type"""
-        return cls._declare_fk('type', nullable=True)
+        return relationships.fk('type', nullable=True)
 
     @declared_attr
     def capability_type_fk(cls):
         """For ServiceTemplate one-to-one to Type"""
-        return cls._declare_fk('type', nullable=True)
+        return relationships.fk('type', nullable=True)
 
     @declared_attr
     def interface_type_fk(cls):
         """For ServiceTemplate one-to-one to Type"""
-        return cls._declare_fk('type', nullable=True)
+        return relationships.fk('type', nullable=True)
 
     @declared_attr
     def artifact_type_fk(cls):
         """For ServiceTemplate one-to-one to Type"""
-        return cls._declare_fk('type', nullable=True)
+        return relationships.fk('type', nullable=True)
 
     # endregion
 
@@ -412,7 +414,7 @@ class NodeTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def type(cls):
-        return cls._declare_many_to_one('type')
+        return relationships.many_to_one(cls, 'type')
 
     description = Column(Text)
     default_instances = Column(Integer, default=1)
@@ -421,42 +423,42 @@ class NodeTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def properties(cls):
-        return cls._declare_many_to_many('parameter', prefix='properties', dict_key='name')
+        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     @declared_attr
     def interface_templates(cls):
-        return cls._declare_one_to_many('interface_template', dict_key='name')
+        return relationships.one_to_many(cls, 'interface_template', dict_key='name')
 
     @declared_attr
     def artifact_templates(cls):
-        return cls._declare_one_to_many('artifact_template', dict_key='name')
+        return relationships.one_to_many(cls, 'artifact_template', dict_key='name')
 
     @declared_attr
     def capability_templates(cls):
-        return cls._declare_one_to_many('capability_template', dict_key='name')
+        return relationships.one_to_many(cls, 'capability_template', dict_key='name')
 
     @declared_attr
     def requirement_templates(cls):
-        return cls._declare_one_to_many('requirement_template', child_fk='node_template_fk',
-                                        child_property='node_template')
+        return relationships.one_to_many(cls, 'requirement_template', child_fk='node_template_fk',
+                                         child_property='node_template')
 
     target_node_template_constraints = Column(modeling_types.StrictList(FunctionType))
 
     @declared_attr
     def plugin_specifications(cls):
-        return cls._declare_many_to_many('plugin_specification', dict_key='name')
+        return relationships.many_to_many(cls, 'plugin_specification', dict_key='name')
 
     # region foreign_keys
 
     @declared_attr
     def type_fk(cls):
         """For NodeTemplate many-to-one to Type"""
-        return cls._declare_fk('type')
+        return relationships.fk('type')
 
     @declared_attr
     def service_template_fk(cls):
         """For ServiceTemplate one-to-many to NodeTemplate"""
-        return cls._declare_fk('service_template')
+        return relationships.fk('service_template')
 
     # endregion
 
@@ -575,33 +577,33 @@ class GroupTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def type(cls):
-        return cls._declare_many_to_one('type')
+        return relationships.many_to_one(cls, 'type')
 
     description = Column(Text)
 
     @declared_attr
     def node_templates(cls):
-        return cls._declare_many_to_many('node_template')
+        return relationships.many_to_many(cls, 'node_template')
 
     @declared_attr
     def properties(cls):
-        return cls._declare_many_to_many('parameter', prefix='properties', dict_key='name')
+        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     @declared_attr
     def interface_templates(cls):
-        return cls._declare_one_to_many('interface_template', dict_key='name')
+        return relationships.one_to_many(cls, 'interface_template', dict_key='name')
 
     # region foreign keys
 
     @declared_attr
     def type_fk(cls):
         """For GroupTemplate many-to-one to Type"""
-        return cls._declare_fk('type')
+        return relationships.fk('type')
 
     @declared_attr
     def service_template_fk(cls):
         """For ServiceTemplate one-to-many to GroupTemplate"""
-        return cls._declare_fk('service_template')
+        return relationships.fk('service_template')
 
     # endregion
 
@@ -680,33 +682,33 @@ class PolicyTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def type(cls):
-        return cls._declare_many_to_one('type')
+        return relationships.many_to_one(cls, 'type')
 
     description = Column(Text)
 
     @declared_attr
     def node_templates(cls):
-        return cls._declare_many_to_many('node_template')
+        return relationships.many_to_many(cls, 'node_template')
 
     @declared_attr
     def group_templates(cls):
-        return cls._declare_many_to_many('group_template')
+        return relationships.many_to_many(cls, 'group_template')
 
     @declared_attr
     def properties(cls):
-        return cls._declare_many_to_many('parameter', prefix='properties', dict_key='name')
+        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     # region foreign keys
 
     @declared_attr
     def type_fk(cls):
         """For PolicyTemplate many-to-one to Type"""
-        return cls._declare_fk('type')
+        return relationships.fk('type')
 
     @declared_attr
     def service_template_fk(cls):
         """For ServiceTemplate one-to-many to PolicyTemplate"""
-        return cls._declare_fk('service_template')
+        return relationships.fk('service_template')
 
     # endregion
 
@@ -777,18 +779,18 @@ class SubstitutionTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def node_type(cls):
-        return cls._declare_many_to_one('type')
+        return relationships.many_to_one(cls, 'type')
 
     @declared_attr
     def mappings(cls):
-        return cls._declare_one_to_many('substitution_template_mapping', dict_key='name')
+        return relationships.one_to_many(cls, 'substitution_template_mapping', dict_key='name')
 
     # region foreign keys
 
     @declared_attr
     def node_type_fk(cls):
         """For SubstitutionTemplate many-to-one to Type"""
-        return cls._declare_fk('type')
+        return relationships.fk('type')
 
     # endregion
 
@@ -844,37 +846,37 @@ class SubstitutionTemplateMappingBase(TemplateModelMixin):
 
     @declared_attr
     def node_template(cls):
-        return cls._declare_one_to_one('node_template')
+        return relationships.one_to_one(cls, 'node_template')
 
     @declared_attr
     def capability_template(cls):
-        return cls._declare_one_to_one('capability_template')
+        return relationships.one_to_one(cls, 'capability_template')
 
     @declared_attr
     def requirement_template(cls):
-        return cls._declare_one_to_one('requirement_template')
+        return relationships.one_to_one(cls, 'requirement_template')
 
     # region foreign keys
 
     @declared_attr
     def substitution_template_fk(cls):
         """For SubstitutionTemplate one-to-many to SubstitutionTemplateMapping"""
-        return cls._declare_fk('substitution_template')
+        return relationships.fk('substitution_template')
 
     @declared_attr
     def node_template_fk(cls):
         """For SubstitutionTemplate one-to-one to NodeTemplate"""
-        return cls._declare_fk('node_template')
+        return relationships.fk('node_template')
 
     @declared_attr
     def capability_template_fk(cls):
         """For SubstitutionTemplate one-to-one to CapabilityTemplate"""
-        return cls._declare_fk('capability_template', nullable=True)
+        return relationships.fk('capability_template', nullable=True)
 
     @declared_attr
     def requirement_template_fk(cls):
         """For SubstitutionTemplate one-to-one to RequirementTemplate"""
-        return cls._declare_fk('requirement_template', nullable=True)
+        return relationships.fk('requirement_template', nullable=True)
 
     # endregion
 
@@ -965,50 +967,52 @@ class RequirementTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def target_node_type(cls):
-        return cls._declare_many_to_one('type', fk='target_node_type_fk', parent_property=False)
+        return relationships.many_to_one(cls, 'type', fk='target_node_type_fk',
+                                         parent_property=False)
 
     @declared_attr
     def target_node_template(cls):
-        return cls._declare_one_to_one('node_template', fk='target_node_template_fk',
-                                       other_property=False)
+        return relationships.one_to_one(cls, 'node_template', fk='target_node_template_fk',
+                                        other_property=False)
 
     @declared_attr
     def target_capability_type(cls):
-        return cls._declare_one_to_one('type', fk='target_capability_type_fk', other_property=False)
+        return relationships.one_to_one(cls, 'type', fk='target_capability_type_fk',
+                                        other_property=False)
 
     target_capability_name = Column(Text)
     target_node_template_constraints = Column(modeling_types.StrictList(FunctionType))
 
     @declared_attr
     def relationship_template(cls):
-        return cls._declare_one_to_one('relationship_template')
+        return relationships.one_to_one(cls, 'relationship_template')
 
     # region foreign keys
 
     @declared_attr
     def target_node_type_fk(cls):
         """For RequirementTemplate many-to-one to Type"""
-        return cls._declare_fk('type', nullable=True)
+        return relationships.fk('type', nullable=True)
 
     @declared_attr
     def target_node_template_fk(cls):
         """For RequirementTemplate one-to-one to NodeTemplate"""
-        return cls._declare_fk('node_template', nullable=True)
+        return relationships.fk('node_template', nullable=True)
 
     @declared_attr
     def target_capability_type_fk(cls):
         """For RequirementTemplate one-to-one to NodeTemplate"""
-        return cls._declare_fk('type', nullable=True)
+        return relationships.fk('type', nullable=True)
 
     @declared_attr
     def node_template_fk(cls):
         """For NodeTemplate one-to-many to RequirementTemplate"""
-        return cls._declare_fk('node_template')
+        return relationships.fk('node_template')
 
     @declared_attr
     def relationship_template_fk(cls):
         """For RequirementTemplate one-to-one to RelationshipTemplate"""
-        return cls._declare_fk('relationship_template', nullable=True)
+        return relationships.fk('relationship_template', nullable=True)
 
     # endregion
 
@@ -1148,24 +1152,24 @@ class RelationshipTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def type(cls):
-        return cls._declare_many_to_one('type')
+        return relationships.many_to_one(cls, 'type')
 
     description = Column(Text)
 
     @declared_attr
     def properties(cls):
-        return cls._declare_many_to_many('parameter', prefix='properties', dict_key='name')
+        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     @declared_attr
     def interface_templates(cls):
-        return cls._declare_one_to_many('interface_template', dict_key='name')
+        return relationships.one_to_many(cls, 'interface_template', dict_key='name')
 
     # region foreign keys
 
     @declared_attr
     def type_fk(cls):
         """For RelationshipTemplate many-to-one to Type"""
-        return cls._declare_fk('type', nullable=True)
+        return relationships.fk('type', nullable=True)
 
     # endregion
 
@@ -1245,7 +1249,7 @@ class CapabilityTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def type(cls):
-        return cls._declare_many_to_one('type')
+        return relationships.many_to_one(cls, 'type')
 
     description = Column(Text)
     min_occurrences = Column(Integer, default=None)  # optional
@@ -1253,23 +1257,23 @@ class CapabilityTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def valid_source_node_types(cls):
-        return cls._declare_many_to_many('type', prefix='valid_sources')
+        return relationships.many_to_many(cls, 'type', prefix='valid_sources')
 
     @declared_attr
     def properties(cls):
-        return cls._declare_many_to_many('parameter', prefix='properties', dict_key='name')
+        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     # region foreign keys
 
     @declared_attr
     def type_fk(cls):
         """For CapabilityTemplate many-to-one to Type"""
-        return cls._declare_fk('type')
+        return relationships.fk('type')
 
     @declared_attr
     def node_template_fk(cls):
         """For NodeTemplate one-to-many to CapabilityTemplate"""
-        return cls._declare_fk('node_template')
+        return relationships.fk('node_template')
 
     # endregion
 
@@ -1376,39 +1380,39 @@ class InterfaceTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def type(cls):
-        return cls._declare_many_to_one('type')
+        return relationships.many_to_one(cls, 'type')
 
     description = Column(Text)
 
     @declared_attr
     def inputs(cls):
-        return cls._declare_many_to_many('parameter', prefix='inputs', dict_key='name')
+        return relationships.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
 
     @declared_attr
     def operation_templates(cls):
-        return cls._declare_one_to_many('operation_template', dict_key='name')
+        return relationships.one_to_many(cls, 'operation_template', dict_key='name')
 
     # region foreign keys
 
     @declared_attr
     def type_fk(cls):
         """For InterfaceTemplate many-to-one to Type"""
-        return cls._declare_fk('type')
+        return relationships.fk('type')
 
     @declared_attr
     def node_template_fk(cls):
         """For NodeTemplate one-to-many to InterfaceTemplate"""
-        return cls._declare_fk('node_template', nullable=True)
+        return relationships.fk('node_template', nullable=True)
 
     @declared_attr
     def group_template_fk(cls):
         """For GroupTemplate one-to-many to InterfaceTemplate"""
-        return cls._declare_fk('group_template', nullable=True)
+        return relationships.fk('group_template', nullable=True)
 
     @declared_attr
     def relationship_template_fk(cls):
         """For RelationshipTemplate one-to-many to InterfaceTemplate"""
-        return cls._declare_fk('relationship_template', nullable=True)
+        return relationships.fk('relationship_template', nullable=True)
 
     # endregion
 
@@ -1495,14 +1499,14 @@ class OperationTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def plugin_specification(cls):
-        return cls._declare_one_to_one('plugin_specification')
+        return relationships.one_to_one(cls, 'plugin_specification')
 
     implementation = Column(Text)
     dependencies = Column(modeling_types.StrictList(item_cls=basestring))
 
     @declared_attr
     def inputs(cls):
-        return cls._declare_many_to_many('parameter', prefix='inputs', dict_key='name')
+        return relationships.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
 
     executor = Column(Text)
     max_retries = Column(Integer)
@@ -1513,17 +1517,17 @@ class OperationTemplateBase(TemplateModelMixin):
     @declared_attr
     def service_template_fk(cls):
         """For ServiceTemplate one-to-many to OperationTemplate"""
-        return cls._declare_fk('service_template', nullable=True)
+        return relationships.fk('service_template', nullable=True)
 
     @declared_attr
     def interface_template_fk(cls):
         """For InterfaceTemplate one-to-many to OperationTemplate"""
-        return cls._declare_fk('interface_template', nullable=True)
+        return relationships.fk('interface_template', nullable=True)
 
     @declared_attr
     def plugin_specification_fk(cls):
         """For OperationTemplate one-to-one to PluginSpecification"""
-        return cls._declare_fk('plugin_specification', nullable=True)
+        return relationships.fk('plugin_specification', nullable=True)
 
     # endregion
 
@@ -1616,7 +1620,7 @@ class ArtifactTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def type(cls):
-        return cls._declare_many_to_one('type')
+        return relationships.many_to_one(cls, 'type')
 
     description = Column(Text)
     source_path = Column(Text)
@@ -1626,19 +1630,19 @@ class ArtifactTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def properties(cls):
-        return cls._declare_many_to_many('parameter', prefix='properties', dict_key='name')
+        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     # region foreign keys
 
     @declared_attr
     def type_fk(cls):
         """For ArtifactTemplate many-to-one to Type"""
-        return cls._declare_fk('type')
+        return relationships.fk('type')
 
     @declared_attr
     def node_template_fk(cls):
         """For NodeTemplate one-to-many to ArtifactTemplate"""
-        return cls._declare_fk('node_template')
+        return relationships.fk('node_template')
 
     # endregion
 


Mime
View raw message