11from datetime import datetime
22
3- from sqlalchemy import Index
3+ from sqlalchemy import CheckConstraint , Index
44from werkzeug .security import generate_password_hash , check_password_hash
55from email_validator import validate_email , EmailNotValidError
66from email_normalize import normalize
77
88from app import db
99
1010
11+ class ConstraintFactory :
12+ @staticmethod
13+ def non_empty_string (column_name ):
14+ constraint_name = f'{ column_name } _non_empty'
15+ return CheckConstraint (f"TRIM({ column_name } ) != ''" , name = constraint_name )
16+
17+
1118class User (db .Model ):
1219 __tablename__ = 'user'
1320 id = db .Column (db .Integer , primary_key = True )
@@ -16,6 +23,12 @@ class User(db.Model):
1623 password_hash = db .Column (db .String (256 ), nullable = False )
1724 created_on = db .Column (db .DateTime , nullable = False , default = datetime .utcnow )
1825
26+ __table_args__ = (
27+ ConstraintFactory .non_empty_string ('email' ),
28+ ConstraintFactory .non_empty_string ('email_normalized' ),
29+ ConstraintFactory .non_empty_string ('password_hash' )
30+ )
31+
1932 # Does not check for non-deliverable mails. Use check_deliverability or resolve for that which does DNS checks
2033 # For more stricter validation, use confirmation emails, or a third party API
2134 @staticmethod
@@ -68,6 +81,10 @@ class Category(db.Model):
6881 created_at = db .Column (db .DateTime , nullable = False , default = datetime .utcnow )
6982 subcategories = db .relationship ("Subcategory" , secondary = category_subcategory , back_populates = "categories" , lazy = 'dynamic' , passive_deletes = True )
7083
84+ __table_args__ = (
85+ ConstraintFactory .non_empty_string ('name' ),
86+ )
87+
7188 def to_json (self ):
7289 return {
7390 'id' : self .id ,
@@ -84,6 +101,10 @@ class Subcategory(db.Model):
84101 categories = db .relationship ("Category" , secondary = category_subcategory , back_populates = "subcategories" , lazy = 'dynamic' , passive_deletes = True )
85102 products = db .relationship ("Product" , secondary = subcategory_product , back_populates = "subcategories" , lazy = 'dynamic' , passive_deletes = True )
86103
104+ __table_args__ = (
105+ ConstraintFactory .non_empty_string ('name' ),
106+ )
107+
87108 def to_json (self ):
88109 return {
89110 'id' : self .id ,
@@ -100,6 +121,10 @@ class Product(db.Model):
100121 created_at = db .Column (db .DateTime , nullable = False ,default = datetime .utcnow )
101122 subcategories = db .relationship ("Subcategory" , secondary = subcategory_product , back_populates = "products" , lazy = 'dynamic' , passive_deletes = True )
102123
124+ __table_args__ = (
125+ ConstraintFactory .non_empty_string ('name' ),
126+ )
127+
103128 def to_json (self ):
104129 return {
105130 'id' : self .id ,
0 commit comments