server/schema2sql.py
changeset 10443 2d3834df64ab
parent 10204 f8ccae1e271d
child 10444 fb7c1013189e
--- a/server/schema2sql.py	Tue Jun 23 10:05:34 2015 +0200
+++ b/server/schema2sql.py	Mon May 18 11:36:07 2015 +0200
@@ -21,9 +21,10 @@
 
 from hashlib import md5
 
+from six import string_types
 from six.moves import range
 
-from yams.constraints import SizeConstraint, UniqueConstraint
+from yams.constraints import SizeConstraint, UniqueConstraint, Attribute
 
 # default are usually not handled at the sql level. If you want them, set
 # SET_DEFAULT to True
@@ -122,6 +123,15 @@
             w(' %s%s %s' % (prefix, rschema.type, sqltype))
         else:
             w(' %s%s %s,' % (prefix, rschema.type, sqltype))
+    for rschema, aschema in attrs:
+        if aschema is None:  # inline relation
+            continue
+        attr = rschema.type
+        rdef = rschema.rdef(eschema.type, aschema.type)
+        for constraint in rdef.constraints:
+            cstrname, check = check_constraint(eschema, aschema, attr, constraint, prefix=prefix)
+            if cstrname is not None:
+                w(', CONSTRAINT %s CHECK(%s)' % (cstrname, check))
     w(');')
     # create indexes
     for i in range(len(attrs)):
@@ -136,6 +146,40 @@
     w('')
     return '\n'.join(output)
 
+def check_constraint(eschema, aschema, attr, constraint, prefix=''):
+    # XXX should find a better name
+    cstrname = 'cstr' + md5(eschema.type + attr + constraint.type() +
+                            (constraint.serialize() or '')).hexdigest()
+    if constraint.type() == 'BoundaryConstraint':
+        if isinstance(constraint.boundary, Attribute):
+            value = prefix + constraint.boundary.attr
+        else:
+            value = constraint.boundary
+        return cstrname, '%s%s %s %s' % (prefix, attr, constraint.operator, value)
+    elif constraint.type() == 'IntervalBoundConstraint':
+        condition = []
+        if constraint.minvalue is not None:
+            if isinstance(constraint.minvalue, Attribute):
+                value = prefix + constraint.minvalue.attr
+            else:
+                value = constraint.minvalue
+            condition.append('%s%s >= %s' % (prefix, attr, value))
+        if constraint.maxvalue is not None:
+            if isinstance(constraint.maxvalue, Attribute):
+                value = prefix + constraint.maxvalue.attr
+            else:
+                value = constraint.maxvalue
+            condition.append('%s%s <= %s' % (prefix, attr, value))
+        return cstrname, ' AND '.join(condition)
+    elif constraint.type() == 'StaticVocabularyConstraint':
+        sample = next(iter(constraint.vocabulary()))
+        if not isinstance(sample, string_types):
+            values = ', '.join(str(word) for word in constraint.vocabulary())
+        else:
+            # XXX better quoting?
+            values = ', '.join("'%s'" % word.replace("'", "''") for word in constraint.vocabulary())
+        return cstrname, '%s%s IN (%s)' % (prefix, attr, values)
+    return None, None
 
 def aschema2sql(dbhelper, eschema, rschema, aschema, creating=True, indent=''):
     """write an attribute schema as SQL statements to stdout"""