implent AddressTypes, Addresses, Nodes, PUCs and SiteTags
authorTony Mack <tmack@paris.CS.Princeton.EDU>
Fri, 28 Sep 2012 19:12:38 +0000 (15:12 -0400)
committerTony Mack <tmack@paris.CS.Princeton.EDU>
Fri, 28 Sep 2012 19:12:38 +0000 (15:12 -0400)
PLC/AddressTypes.py
PLC/Addresses.py
PLC/Nodes.py
PLC/PCUs.py
PLC/SiteTags.py
PLC/TagTypes.py

index e4ad4de..3e41a92 100644 (file)
@@ -9,19 +9,19 @@ from types import StringTypes
 from PLC.Faults import *
 from PLC.Parameter import Parameter
 from PLC.Filter import Filter
+from PLC.Storage.AlchemyObj import AlchemyObj
 from PLC.Table import Row, Table
 
-class AddressType(Row):
+class AddressType(AlchemyObj):
     """
     Representation of a row in the address_types table. To use,
     instantiate with a dict of values.
     """
 
-    table_name = 'address_types'
-    primary_key = 'address_type_id'
+    tablename = 'address_types'
     join_tables = ['address_address_type']
     fields = {
-        'address_type_id': Parameter(int, "Address type identifier"),
+        'address_type_id': Parameter(int, "Address type identifier", primary_key=True),
         'name': Parameter(str, "Address type", max = 20),
         'description': Parameter(str, "Address type description", max = 254),
         }
@@ -39,34 +39,38 @@ class AddressType(Row):
 
         return name
 
-class AddressTypes(Table):
+    def sync(self, insert=False, validate=True):
+        AlchemyObj.sync(self, insert, validate):
+        if insert == True or 'address_type_id'  not in self:
+            AlchemyObj.insert(self, dict(self))
+        else:
+            AlchemyObj.update(self, dict(self))
+
+
+    def delete(self, commit=True):
+        AlchemyObj.delete(self, dict(self))
+
+class AddressTypes(list):
     """
     Representation of the address_types table in the database.
     """
 
     def __init__(self, api, address_type_filter = None, columns = None):
-        Table.__init__(self, api, AddressType, columns)
-
-        sql = "SELECT %s FROM address_types WHERE True" % \
-              ", ".join(self.columns)
-
-        if address_type_filter is not None:
-            if isinstance(address_type_filter, (list, tuple, set)):
-                # Separate the list into integers and strings
-                ints = filter(lambda x: isinstance(x, (int, long)), address_type_filter)
-                strs = filter(lambda x: isinstance(x, StringTypes), address_type_filter)
-                address_type_filter = Filter(AddressType.fields, {'address_type_id': ints, 'name': strs})
-                sql += " AND (%s) %s" % address_type_filter.sql(api, "OR")
-            elif isinstance(address_type_filter, dict):
-                address_type_filter = Filter(AddressType.fields, address_type_filter)
-                sql += " AND (%s) %s" % address_type_filter.sql(api, "AND")
-            elif isinstance(address_type_filter, (int, long)):
-                address_type_filter = Filter(AddressType.fields, {'address_type_id': address_type_filter})
-                sql += " AND (%s) %s" % address_type_filter.sql(api, "AND")
-            elif isinstance(address_type_filter, StringTypes):
-                address_type_filter = Filter(AddressType.fields, {'name': address_type_filter})
-                sql += " AND (%s) %s" % address_type_filter.sql(api, "AND")
-            else:
-                raise PLCInvalidArgument, "Wrong address type filter %r"%address_type_filter
+        if not address_type_filter:
+            address_types = AddressType().select()
+        elif isinstance(address_type_filter, (list, tuple, set)):
+            # Separate the list into integers and strings
+            ints = filter(lambda x: isinstance(x, (int, long)), address_type_filter)
+            strs = filter(lambda x: isinstance(x, StringTypes), address_type_filter)
+            address_types = AddressType().select(filter={'address_type_id': ints, 'name': strs})
+        elif isinstance(address_type_filter, dict):
+            address_types = AddressType().select(filter=address_type_filter)
+        elif isinstance(address_type_filter, (int, long)):
+            address_types = AddressType().select(filter={'address_type_id': address_type_filter})
+        elif isinstance(address_type_filter, StringTypes):
+            address_types = AddressType().select(filter={'name': address_type_filter})
+        else:
+            raise PLCInvalidArgument, "Wrong address type filter %r"%address_type_filter
 
-        self.selectall(sql)
+        for address_type in address_types:
+            self.append(address_type) 
index 6d6acee..fac19f2 100644 (file)
@@ -1,20 +1,19 @@
 from PLC.Faults import *
 from PLC.Parameter import Parameter
-from PLC.Table import Row, Table
+from PLC.Storage.AlchemyObj import AlchemyObj
 from PLC.Filter import Filter
 from PLC.AddressTypes import AddressType, AddressTypes
 
-class Address(Row):
+class Address(AlchemyObj):
     """
     Representation of a row in the addresses table. To use, instantiate
     with a dict of values.
     """
 
-    table_name = 'addresses'
-    primary_key = 'address_id'
+    tablename = 'addresses'
     join_tables = ['address_address_type', 'site_address']
     fields = {
-        'address_id': Parameter(int, "Address identifier"),
+        'address_id': Parameter(int, "Address identifier", primary_key=True),
         'line1': Parameter(str, "Address line 1", max = 254),
         'line2': Parameter(str, "Address line 2", max = 254, nullok = True),
         'line3': Parameter(str, "Address line 3", max = 254, nullok = True),
@@ -22,8 +21,8 @@ class Address(Row):
         'state': Parameter(str, "State or province", max = 254),
         'postalcode': Parameter(str, "Postal code", max = 64),
         'country': Parameter(str, "Country", max = 128),
-        'address_type_ids': Parameter([int], "Address type identifiers"),
-        'address_types': Parameter([str], "Address types"),
+        'address_type_ids': Parameter([int], "Address type identifiers", joined=True),
+        'address_types': Parameter([str], "Address types", joined=True),
         }
 
     def add_address_type(self, address_type, commit = True):
@@ -77,23 +76,31 @@ class Address(Row):
             self['address_type_ids'].remove(address_type_id)
             self['address_types'].remove(address_type['name'])
 
-class Addresses(Table):
+    def sync(self, insert=False, validate=True):
+        AlchemyObj.sync(self, insert, validate)
+        if insert == True or 'id' not in self:
+            AlchemyObj.insert(self, dict(self))
+        else:
+            AlchemyObj.update(self, dict(self))
+
+    def delete(self, commit=True):
+        AlchemyObj.delete(self, dict(self))     
+            
+class Addresses(list):
     """
     Representation of row(s) from the addresses table in the
     database.
     """
 
     def __init__(self, api, address_filter = None, columns = None):
-        Table.__init__(self, api, Address, columns)
-
-        sql = "SELECT %s FROM view_addresses WHERE True" % \
-              ", ".join(self.columns)
-
-        if address_filter is not None:
-            if isinstance(address_filter, (list, tuple, set, int, long)):
-                address_filter = Filter(Address.fields, {'address_id': address_filter})
-            elif isinstance(address_filter, dict):
-                address_filter = Filter(Address.fields, address_filter)
-            sql += " AND (%s) %s" % address_filter.sql(api)
-
-        self.selectall(sql)
+        if address_filter is None:
+            addresses = Address().select()
+        elif isinstance(address_filter, (list, tuple, set, int, long)):
+            addresses = Address().select(filter={'address_id': address_filter})
+        elif isinstance(address_filter, dict):
+            addresses = Address().select(filter=address_filter)
+        else:
+            raise PLCInvalidArgument, "Wrong address filter %s" % address_filter
+
+        for address in addresses:
+            self.append(address)
index 87789ea..80de915 100644 (file)
@@ -12,7 +12,7 @@ from PLC.Faults import *
 from PLC.Parameter import Parameter, Mixed
 from PLC.Filter import Filter
 from PLC.Debug import profile
-from PLC.Table import Row, Table
+from PLC.Storage.AlchemyObj import AlchemyObj
 from PLC.NodeTypes import NodeTypes
 from PLC.BootStates import BootStates
 from PLC.Interfaces import Interface, Interfaces
@@ -28,20 +28,19 @@ def valid_hostname(hostname):
     return hostname and \
            re.match(good_hostname, hostname, re.IGNORECASE)
 
-class Node(Row):
+class Node(AlchemyObj):
     """
     Representation of a row in the nodes table. To use, optionally
     instantiate with a dict of values. Update as you would a
     dict. Commit to the database with sync().
     """
 
-    table_name = 'nodes'
-    primary_key = 'node_id'
+    tablename = 'nodes'
     join_tables = [ 'slice_node', 'peer_node', 'slice_tag',
                     'node_session', 'node_slice_whitelist',
                     'node_tag', 'conf_file_node', 'pcu_node', 'leases', ]
     fields = {
-        'node_id': Parameter(int, "Node identifier"),
+        'node_id': Parameter(int, "Node identifier", primary_key=True),
         'node_type': Parameter(str,"Node type",max=20),
         'hostname': Parameter(str, "Fully qualified hostname", max = 255),
         'site_id': Parameter(int, "Site at which this node is located"),
@@ -63,31 +62,18 @@ class Node(Row):
         'verified': Parameter(bool, "Whether the node configuration is verified correct", ro=False),
         'key': Parameter(str, "(Admin only) Node key", max = 256),
         'session': Parameter(str, "(Admin only) Node session value", max = 256, ro = True),
-        'interface_ids': Parameter([int], "List of network interfaces that this node has"),
-        'conf_file_ids': Parameter([int], "List of configuration files specific to this node"),
+        'interface_ids': Parameter([int], "List of network interfaces that this node has", joined=True),
+        'conf_file_ids': Parameter([int], "List of configuration files specific to this node", joined=True),
         # 'root_person_ids': Parameter([int], "(Admin only) List of people who have root access to this node"),
-        'slice_ids': Parameter([int], "List of slices on this node"),
-        'slice_ids_whitelist': Parameter([int], "List of slices allowed on this node"),
-        'pcu_ids': Parameter([int], "List of PCUs that control this node"),
+        'slice_ids': Parameter([int], "List of slices on this node", joined=True),
+        'slice_ids_whitelist': Parameter([int], "List of slices allowed on this node", joined=True),
+        'pcu_ids': Parameter([int], "List of PCUs that control this node", joined=True),
         'ports': Parameter([int], "List of PCU ports that this node is connected to"),
         'peer_id': Parameter(int, "Peer to which this node belongs", nullok = True),
         'peer_node_id': Parameter(int, "Foreign node identifier at peer", nullok = True),
-        'node_tag_ids' : Parameter ([int], "List of tags attached to this node"),
-        'nodegroup_ids': Parameter([int], "List of node groups that this node is in"),
+        'node_tag_ids' : Parameter ([int], "List of tags attached to this node", joined=True),
+        'nodegroup_ids': Parameter([int], "List of node groups that this node is in", joined=True),
         }
-    related_fields = {
-        'interfaces': [Mixed(Parameter(int, "Interface identifier"),
-                             Filter(Interface.fields))],
-        'conf_files': [Parameter(int, "ConfFile identifier")],
-        'slices': [Mixed(Parameter(int, "Slice identifier"),
-                         Parameter(str, "Slice name"))],
-        'slices_whitelist': [Mixed(Parameter(int, "Slice identifier"),
-                                   Parameter(str, "Slice name"))]
-        }
-
-    view_tags_name = "view_node_tags"
-    # tags are used by the Add/Get/Update methods to expose tags
-    # this is initialized here and updated by the accessors factory
     tags = { }
 
     def validate_hostname(self, hostname):
@@ -114,13 +100,13 @@ class Node(Row):
             raise PLCInvalidArgument, "Invalid boot state %r"%boot_state
         return boot_state
 
-    validate_date_created = Row.validate_timestamp
-    validate_last_updated = Row.validate_timestamp
-    validate_last_contact = Row.validate_timestamp
-    validate_last_boot = Row.validate_timestamp
-    validate_last_download = Row.validate_timestamp
-    validate_last_pcu_reboot = Row.validate_timestamp
-    validate_last_pcu_confirmation = Row.validate_timestamp
+    validate_date_created = AlchemyObj.validate_timestamp
+    validate_last_updated = AlchemyObj.validate_timestamp
+    validate_last_contact = AlchemyObj.validate_timestamp
+    validate_last_boot = AlchemyObj.validate_timestamp
+    validate_last_download = AlchemyObj.validate_timestamp
+    validate_last_pcu_reboot = AlchemyObj.validate_timestamp
+    validate_last_pcu_confirmation = AlchemyObj.validate_timestamp
 
     def update_readonly_int(self, col_name, commit = True):
 
@@ -276,68 +262,47 @@ class Node(Row):
             DeleteSliceFromNodesWhitelist.__call__(DeleteSliceFromNodesWhitelist(self.api), auth, stale_slice, [self['node_id']])
 
 
+
+    def sync(self, insert=False, validate=True):
+        AlchemyObj.sync(self, insert, validate)
+        if insert == True or 'node_id' not in self:
+            AlchemyObj.insert(self, dict(self))
+        else:
+            AlchemyObj.update(self, dict(self))
+
     def delete(self, commit = True):
         """
         Delete existing node.
         """
 
         assert 'node_id' in self
+        assert 'interface_ids' in self
+        Interface().delete(filter={'interface_id': self['interface_ids']})
+        AlchemyObj.delete(self, dict(self)
 
-        # we need to clean up InterfaceTags, so handling interfaces as part of join_tables does not work
-        # federated nodes don't have interfaces though so for smooth transition from 4.2 to 4.3
-        if 'peer_id' in self and self['peer_id']:
-            pass
-        else:
-            assert 'interface_ids' in self
-            for interface in Interfaces(self.api,self['interface_ids']):
-                interface.delete()
-
-        # Clean up miscellaneous join tables
-        for table in self.join_tables:
-            self.api.db.do("DELETE FROM %s WHERE node_id = %d" % \
-                           (table, self['node_id']))
-
-        # Mark as deleted
-        self['deleted'] = True
-        self.sync(commit)
-
-class Nodes(Table):
+class Nodes(list):
     """
     Representation of row(s) from the nodes table in the
     database.
     """
 
     def __init__(self, api, node_filter = None, columns = None):
-        Table.__init__(self, api, Node, columns)
-
-        # the view that we're selecting upon: start with view_nodes
-        view = "view_nodes"
         # as many left joins as requested tags
-        for tagname in self.tag_columns:
-            view= "%s left join %s using (%s)"%(view,Node.tagvalue_view_name(tagname),
-                                                Node.primary_key)
-
-        sql = "SELECT %s FROM %s WHERE deleted IS False" % \
-              (", ".join(self.columns.keys()+self.tag_columns.keys()),view)
-
-        if node_filter is not None:
-            if isinstance(node_filter, (list, tuple, set)):
-                # Separate the list into integers and strings
-                ints = filter(lambda x: isinstance(x, (int, long)), node_filter)
-                strs = filter(lambda x: isinstance(x, StringTypes), node_filter)
-                node_filter = Filter(Node.fields, {'node_id': ints, 'hostname': strs})
-                sql += " AND (%s) %s" % node_filter.sql(api, "OR")
-            elif isinstance(node_filter, dict):
-                allowed_fields=dict(Node.fields.items()+Node.tags.items())
-                node_filter = Filter(allowed_fields, node_filter)
-                sql += " AND (%s) %s" % node_filter.sql(api, "AND")
-            elif isinstance (node_filter, StringTypes):
-                node_filter = Filter(Node.fields, {'hostname':node_filter})
-                sql += " AND (%s) %s" % node_filter.sql(api, "AND")
-            elif isinstance (node_filter, (int, long)):
-                node_filter = Filter(Node.fields, {'node_id':node_filter})
-                sql += " AND (%s) %s" % node_filter.sql(api, "AND")
-            else:
-                raise PLCInvalidArgument, "Wrong node filter %r"%node_filter
+        if not node_filter:
+            nodes = Node().select()
+        elif isinstance(node_filter, (list, tuple, set)):
+            # Separate the list into integers and strings
+            ints = filter(lambda x: isinstance(x, (int, long)), node_filter)
+            strs = filter(lambda x: isinstance(x, StringTypes), node_filter)
+            nodes = Node().select(filter={'node_id': ints, 'hostname': strs})
+        elif isinstance(node_filter, dict):
+            nodes = Node().select(filter={'node_id': ints, 'hostname': strs})
+        elif isinstance (node_filter, StringTypes):
+            nodes = Node().select(filter={'hostname': strs})
+        elif isinstance (node_filter, (int, long)):
+            nodes = Node().select(filter={'node_id': ints})
+        else:
+            raise PLCInvalidArgument, "Wrong node filter %r"%node_filter
 
-        self.selectall(sql)
+        for node in nodes:
+            self.append(node)
index d628677..f4eaa34 100644 (file)
@@ -10,20 +10,20 @@ from PLC.Parameter import Parameter
 from PLC.Filter import Filter
 from PLC.Debug import profile
 from PLC.Table import Row, Table
+from PLC.Storage.AlchemyObject import AlchemyObj
 from PLC.Interfaces import valid_ip, Interface, Interfaces
 from PLC.Nodes import Node, Nodes
 
-class PCU(Row):
+class PCU(AlchemyObj):
     """
     Representation of a row in the pcus table. To use,
     instantiate with a dict of values.
     """
 
-    table_name = 'pcus'
-    primary_key = 'pcu_id'
+    tablename = 'pcus'
     join_tables = ['pcu_node']
     fields = {
-        'pcu_id': Parameter(int, "PCU identifier"),
+        'pcu_id': Parameter(int, "PCU identifier", primary_key=True),
         'site_id': Parameter(int, "Identifier of site where PCU is located"),
         'hostname': Parameter(str, "PCU hostname", max = 254),
         'ip': Parameter(str, "PCU IP address", max = 254),
@@ -33,8 +33,8 @@ class PCU(Row):
         'notes': Parameter(str, "Miscellaneous notes", max = 254, nullok = True),
         'model': Parameter(str, "PCU model string", max = 32, nullok = True),
         'node_ids': Parameter([int], "List of nodes that this PCU controls"),
-        'ports': Parameter([int], "List of the port numbers that each node is connected to"),
-        'last_updated': Parameter(int, "Date and time when node entry was created", ro = True),
+        'ports': Parameter([int], "List of the port numbers that each node is connected to", ro=True),
+        'last_updated': Parameter(int, "Date and time when node entry was created"),
         }
 
     def validate_ip(self, ip):
@@ -110,25 +110,31 @@ class PCU(Row):
             self['node_ids'].remove(node_id)
             self['ports'].remove(port)
 
-class PCUs(Table):
+    def sync(self, insert=False, validate=True):
+        AlchemyObj.sync(self, insert, validate):
+        if insert == True or 'id' not in self:
+            AlchemyObj.insert(self, dict(self))
+        else:
+            AlchemyObj.delete(self, dict(self))
+                
+class PCUs(list):
     """
     Representation of row(s) from the pcus table in the
     database.
     """
 
     def __init__(self, api, pcu_filter = None, columns = None):
-        Table.__init__(self, api, PCU, columns)
-
-        sql = "SELECT %s FROM view_pcus WHERE True" % \
-              ", ".join(self.columns)
-
-        if pcu_filter is not None:
-            if isinstance(pcu_filter, (list, tuple, set, int, long)):
-                pcu_filter = Filter(PCU.fields, {'pcu_id': pcu_filter})
-            elif isinstance(pcu_filter, dict):
-                pcu_filter = Filter(PCU.fields, pcu_filter)
-            else:
-                raise PLCInvalidArgument, "Wrong pcu filter %r"%pcu_filter
+        if not pcu_filter:
+            pcus = PCU().select()
+        elif isinstance(pcu_filter, int):
+            pcus = PCU().select(filter={'id': pcu_filter})
+        elif isinstance(pcu_filter, (list, tuple, set, int, long)):
+            pcus = PCU().select(filter={'pcu_id': pcu_filter})
+        elif isinstance(pcu_filter, dict):
+            pcus= PCU().select(filter=pcu_filter)
+        else:
+            raise PLCInvalidArgument, "Wrong pcu filter %r"%pcu_filter
             sql += " AND (%s) %s" % pcu_filter.sql(api)
 
-        self.selectall(sql)
+        for pcu in pcus:
+            self.append(pcu)
index 673d739..9b48e3c 100644 (file)
@@ -5,50 +5,56 @@ from PLC.Faults import *
 from PLC.Parameter import Parameter
 from PLC.Filter import Filter
 from PLC.Table import Row, Table
+from PLC.Storage.AlchemyObj import AlchemyObj
 from PLC.TagTypes import TagType, TagTypes
 from PLC.Sites import Site
 
-class SiteTag(Row):
+class SiteTag(AlchemyObj):
     """
     Representation of a row in the site_tag.
     To use, instantiate with a dict of values.
     """
 
-    table_name = 'site_tag'
-    primary_key = 'site_tag_id'
+    table_name = 'site_tags'
     fields = {
-        #'site_tag_id': Parameter(int, "Site setting identifier"),
-        #'site_id': Site.fields['site_id'],
-        #'login_base': Site.fields['login_base'],
-        #'tag_type_id': TagType.fields['tag_type_id'],
-        #'tagname': TagType.fields['tagname'],
-        #'description': TagType.fields['description'],
-        #'category': TagType.fields['category'],
-        #'value': Parameter(str, "Site setting value"),
+        'site_tag_id': Parameter(int, "Site setting identifier", primary_key=True),
+        'site_id': Parameter(int, "Site identifier"),
+        'login_base': Parameter(str, "Site login base"),
+        'tag_type_id': Parameter(int, "Tag Type identifier"),
+        'tagname': Parameter(str, "Tag Name"),
+        'description': Parameter(str, "Description"),
+        'category': Parameter(str, "Category"),
+        'value': Parameter(str, "Site setting value"),
         ### relations
 
         }
 
-class SiteTags(Table):
+    def sync(self, insert=False, validate=True):
+        AlchemyObj.sync(self, insert, validate)
+        if insert == True or 'site_tag_id' not in self:
+            AlchemyObj.insert(self, dict(self))
+        else:
+            AlchemyObj.update(self, dict(self))  
+
+    def delete(self, commit=True):
+        AlchemyObj.delete(self, dict(self))
+
+class SiteTags(list):
     """
     Representation of row(s) from the site_tag table in the
     database.
     """
 
     def __init__(self, api, site_tag_filter = None, columns = None):
-        Table.__init__(self, api, SiteTag, columns)
-
-        sql = "SELECT %s FROM view_site_tags WHERE True" % \
-              ", ".join(self.columns)
-
-        if site_tag_filter is not None:
-            if isinstance(site_tag_filter, (list, tuple, set, int, long)):
-                site_tag_filter = Filter(SiteTag.fields, {'site_tag_id': site_tag_filter})
-            elif isinstance(site_tag_filter, dict):
-                site_tag_filter = Filter(SiteTag.fields, site_tag_filter)
-            else:
-                raise PLCInvalidArgument, "Wrong site setting filter %r"%site_tag_filter
-            sql += " AND (%s) %s" % site_tag_filter.sql(api)
-
-
-        self.selectall(sql)
+        if not site_tag_filter:
+            site_tags = SiteTag().select()
+        if isinstance(site_tag_filter, (list, tuple, set, int, long)):
+            site_tags = SiteTag().select(filter={'site_tag_id': site_tag_filter})
+        elif isinstance(site_tag_filter, dict):
+            site_tags = SiteTag().select(filter=site_tag_filter)
+        else:
+            raise PLCInvalidArgument, "Wrong site setting filter %r"%site_tag_filter
+
+        for site_tag in site_tags:
+            self.append(site_tag)
+    
index f552435..8e7be6e 100644 (file)
@@ -6,18 +6,18 @@ from types import StringTypes
 from PLC.Faults import *
 from PLC.Parameter import Parameter
 from PLC.Filter import Filter
-from PLC.Table import Row, Table
+from PLC.Storage.AlchemyObject import AlchemyObj
 from PLC.Roles import Role, Roles
 
 # xxx todo : deleting a tag type should delete the related nodegroup(s)
 
-class TagType (Row):
+class TagType (AlchemyObj):
 
     """
     Representation of a row in the tag_types table.
     """
 
-    table_name = 'tag_types'
+    tablename = 'tag_types'
     primary_key = 'tag_type_id'
     join_tables = ['tag_type_role', 'node_tag', 'interface_tag', 'slice_tag', 'site_tag', 'person_tag' ]
     fields = {
@@ -25,8 +25,8 @@ class TagType (Row):
         'tagname': Parameter(str, "Node tag type name", max = 100),
         'description': Parameter(str, "Node tag type description", max = 254),
         'category' : Parameter (str, "Node tag category", max=64, optional=True),
-        'role_ids': Parameter([int], "List of role identifiers"),
-        'roles': Parameter([str], "List of roles"),
+        'role_ids': Parameter([int], "List of role identifiers", joined=True),
+        'roles': Parameter([str], "List of roles", joined=True),
         }
 
     def validate_name(self, name):
@@ -41,39 +41,41 @@ class TagType (Row):
 
         return name
 
-    add_role = Row.add_object(Role, 'tag_type_role')
-    remove_role = Row.remove_object(Role, 'tag_type_role')
+    #add_role = Row.add_object(Role, 'tag_type_role')
+    #remove_role = Row.remove_object(Role, 'tag_type_role')
 
+    def sync(self, insert=False, validate=True):
+        AlchemyObj.sync(self, insert, validate):
+        if insert == True or 'tag_type_id' not in self:
+            AlchemyObj.insert(self, dict(self))
+        else:
+            AlchemyObj.update(self, dict(self))
 
-class TagTypes(Table):
+    def delete(self, commit=True):
+        AlchemyObj.delete(self, dict(self)) 
+
+class TagTypes(list):
     """
     Representation of row(s) from the tag_types table
     in the database.
     """
 
     def __init__(self, api, tag_type_filter = None, columns = None):
-        Table.__init__(self, api, TagType, columns)
-
-        sql = "SELECT %s FROM view_tag_types WHERE True" % \
-              ", ".join(self.columns)
 
-        if tag_type_filter is not None:
-            if isinstance(tag_type_filter, (list, tuple, set)):
-                # Separate the list into integers and strings
-                ints = filter(lambda x: isinstance(x, (int, long)), tag_type_filter)
-                strs = filter(lambda x: isinstance(x, StringTypes), tag_type_filter)
-                tag_type_filter = Filter(TagType.fields, {'tag_type_id': ints, 'tagname': strs})
-                sql += " AND (%s) %s" % tag_type_filter.sql(api, "OR")
-            elif isinstance(tag_type_filter, dict):
-                tag_type_filter = Filter(TagType.fields, tag_type_filter)
-                sql += " AND (%s) %s" % tag_type_filter.sql(api, "AND")
-            elif isinstance(tag_type_filter, (int, long)):
-                tag_type_filter = Filter(TagType.fields, {'tag_type_id':tag_type_filter})
-                sql += " AND (%s) %s" % tag_type_filter.sql(api, "AND")
-            elif isinstance(tag_type_filter, StringTypes):
-                tag_type_filter = Filter(TagType.fields, {'tagname':tag_type_filter})
-                sql += " AND (%s) %s" % tag_type_filter.sql(api, "AND")
-            else:
-                raise PLCInvalidArgument, "Wrong tag type filter %r"%tag_type_filter
+        if not tag_type_filter:
+            tag_types = TagType().select()
+        else isinstance(tag_type_filter, (list, tuple, set)):
+            ints = filter(lambda x: isinstance(x, (int, long)), tag_type_filter)
+            strs = filter(lambda x: isinstance(x, StringTypes), tag_type_filter)
+            tag_types = TagType().select(filter={'tag_type_id': ints, 'tagname': strs})
+        elif isinstance(tag_type_filter, dict):
+            tag_types = TagType().select(filter=tag_type_filter)
+        elif isinstance(tag_type_filter, (int, long)):
+            tag_types = TagType().select(filter={'tag_type_id': tag_type_filter})
+        elif isinstance(tag_type_filter, StringTypes):
+            tag_types = TagType().select(filter={'tagname': tag_type_filter})
+        else:
+            raise PLCInvalidArgument, "Wrong tag type filter %r"%tag_type_filter
 
-        self.selectall(sql)
+        for tag_type in tag_types:
+            self.append(tag_type)