소스 검색

Create validators and product structure for database.

Cixo Develop 6 달 전
부모
커밋
93992a3392
9개의 변경된 파일342개의 추가작업 그리고 0개의 파일을 삭제
  1. 1 0
      .gitignore
  2. 12 0
      assets/__init__.py
  3. 3 0
      assets/exception.py
  4. 153 0
      assets/product.py
  5. 131 0
      assets/validator.py
  6. 0 0
      core.py
  7. 2 0
      requirements.txt
  8. 10 0
      tests/000-default.py
  9. 30 0
      tests/001-validator.py

+ 1 - 0
.gitignore

@@ -3,6 +3,7 @@
 __pycache__/
 *.py[cod]
 *$py.class
+.venv/
 
 # C extensions
 *.so

+ 12 - 0
assets/__init__.py

@@ -0,0 +1,12 @@
+""" Validators. """
+from .validator import validator
+from .validator import name_validator
+from .validator import description_validator
+from .validator import barcode_validator
+
+""" Exceptions. """
+from .exception import validator_exception
+
+""" Product and helpers. """
+from .product import product
+from .product import product_builder

+ 3 - 0
assets/exception.py

@@ -0,0 +1,3 @@
+class validator_exception(Exception):
+    def __init__(self, name: str):
+        super("Invalid property names: " + name + ".")

+ 153 - 0
assets/product.py

@@ -0,0 +1,153 @@
+import sqlmodel
+
+from .exception import validator_exception
+from .validator import name_validator
+from .validator import description_validator
+
+class product(sqlmodel.SQLModel, table = True):
+    """ 
+    This class is product model in database. Product is item, which could be 
+    shared.
+    """
+
+    """ ID of the product in the database. """
+    id: int | None = sqlmodel.Field(default = None, primary_key = True)
+
+    """ Name of the product, or title of the book. """
+    name: str | None = sqlmodel.Field(default = None, index = True)
+
+    """ Description of the product, provided by creator. """
+    description: str | None = sqlmodel.Field(default = None)
+
+    """ Author of the product. """
+    author: str | None = sqlmodel.Field(default = None)
+
+    """ Link to image of the product. """
+    image: str | None = sqlmodel.Field(default = None)
+
+    """ Count of instances this products in stock. """
+    stock_count: int = sqlmodel.Field(default = 0)
+
+    """ This is barcode (EAN) of the product. """
+    badcode: str | None = sqlmodel.Field(
+        default = None, 
+        index = True, 
+        unique = True
+    )
+
+    @property
+    def in_database(self) -> bool:
+        """ This return True when product exists in database. """
+
+        return self.id is not None
+
+    def __str__(self) -> str:
+        """
+        This dump product to string, which is helpfull when debug.
+
+        Returns:
+            (str): Product as string dump
+        """
+
+        content = str(self.name) + " " + str(self.id or "") + "\n"
+        content = content + "Description: " + str(self.description) + "\n"
+        content = content + "Author: " + str(self.author) + "\n"
+        content = content + "Barcode (EAN): " + str(self.barcode) + "\n"
+        content = content + "Image (link): " + str(self.image) + "\n"
+        content = content + "In stock: " + str(self.stock_count) + "\n"
+
+        return content
+
+    @property
+    def ready(self) -> bool:
+        """ Check that product is ready to insert into database. """
+
+        if name is None or description is None: 
+            return False
+
+        if barcode is None or author is None:
+            return False
+
+        return True
+        
+        
+class product_builder:
+    """
+    This is builder of the product. It helps to handle validation of the 
+    product params, and modify exists product with validators.
+    """
+
+    def __init__(self, target: product | None = None) -> None:
+        """
+        This create new builder. When get already created item, it work on 
+        given once. When receive None, create new product to work on.
+
+        Parameters:
+            target (product | None): Item to work on (default: None)
+        """
+        
+        if target is not None:
+            self.__target = target
+            return
+
+        self.__target = product()
+
+    @property
+    def ready(self) -> bool:
+        """ It return True when target is ready to insert into database. """
+
+        return self.__target.ready
+
+    @property
+    def result(self) -> product:
+        """ It return ready product, or raise Exception if not Ready yet. """
+
+        if not self.__target.ready:
+            raise Exception("Product in builder is not ready yet.")
+
+        return self.__target
+
+    @property
+    def name(self) -> str | None:
+        """ It return name of the product. """
+
+        return self.__target.name
+
+    @name.setter
+    def name(self, target: str) -> None:
+        """ It set name of the product, and validating it. """
+
+        if name_validator(target).invalid:
+            raise validator_exception("product.name")
+
+        self.__target.name = target
+
+    @property
+    def description(self) -> str | None:
+        """ This return product description. """
+
+        return self.__target.description
+
+    @description.setter
+    def description(self, target: str) -> None:
+        """ This set description of the product, and validate it."""
+
+        if description_validator(target).invalid:
+            raise validator_exception("product.description")
+
+        self.__target.description = target    
+
+    @property
+    def barcode(self) -> str | None:
+        """ It return barcode of building product. """
+
+        return self.__target.badcode
+
+    @barcode.setter
+    def barcode(self, target: str) -> None:
+        """ This set new barcode, and validate it. """
+
+        if barcode_validator(target).invalid:
+            raise validator_exception("product.barcode")
+
+        self.__target.badcode = barcode

+ 131 - 0
assets/validator.py

@@ -0,0 +1,131 @@
+class validator:
+    """
+    This is base validator class. It implements base validator mechanism, 
+    and other validators must implements it.
+    """
+
+    def __init__(self, target: str) -> None:
+        """
+        This create new validator, from string. 
+        
+        Parameters:
+            target (str): Content to validate
+        """
+
+        self.__target = target
+        self._failed()
+
+    @property
+    def target(self) -> str:
+        """ This return content to validate. """
+
+        return self.__target
+
+    def _failed(self) -> None:
+        """
+        This would mark content as invalid. 
+        """
+
+        self.__result = False
+
+    def _check_all(self) -> None:
+        """
+        This would check all marks of the content.
+        It must be overwrite by target validator.
+        """
+
+        pass
+
+    def _contain(self, *args) -> bool:
+        """
+        This check that target contain any given phrase or letter.
+
+        Args:
+            (str): Phrase to check that content contain it
+
+        Returns:
+            (bool): True when any of given phrase is in the target
+        """
+
+        for letter in args:
+            if self.__target.find(letter) != -1:
+                return True
+        
+        return False
+
+    @property
+    def result(self) -> bool:
+        """ Validate content, True when valid or False when not. """
+
+        self.__result = True
+        self._check_all()
+
+        return self.__result
+
+    @property
+    def invalid(self) -> bool:
+        """ Validate, and return True when target is invalid. """
+        
+        return not self.result
+
+    @property
+    def valid(self) -> bool:
+        """ It validate target, and return True when valid. """
+
+        return self.result
+
+class name_validator(validator):
+    """
+    This is validator for product name. It check that it is not blank,
+    and it not contain white chars before and after content.
+    """
+
+    def _check_all(self) -> None:
+
+        # Could not being blank
+        if len(self.target.strip()) == 0:
+            return self._failed()
+
+        # Must be trimed
+        if len(self.target.strip()) != len(self.target):
+            return self._failed()
+
+class description_validator(validator):
+    """
+    This is validator for product description. It could be blank, but can not
+    have white chars before and after content (must be trimmed), and coud has 
+    only 500 chars.
+    """
+
+    def _check_all(self) -> None:
+
+        # Could be blank
+        if len(self.target) == 0:
+            return
+
+        # Must be trimmed
+        if len(self.target.strip()) != len(self.target):
+            return self._failed()
+
+        # Must has max 500 characters.
+        if len(self.target) > 500:
+            return self._failed()
+
+class barcode_validator(validator):
+    """
+    This is barcode validator. Barcode must be string, which contain number
+    with 8, 12 or 13 digits. That is standard EAN.
+    """
+
+    def _check_all(self) -> None:
+
+        # Must has only digits
+        if not self.target.isdigit():
+            return self._failed()
+
+        lenght = len(self.target)
+
+        # Must has 8, 12 or 13 chars
+        if lenght != 8 and lenght != 12 and lenght != 13:
+            return self._failed()
+

+ 0 - 0
core.py


+ 2 - 0
requirements.txt

@@ -0,0 +1,2 @@
+sqlmodel
+fastapi

+ 10 - 0
tests/000-default.py

@@ -0,0 +1,10 @@
+import pathlib
+
+current = pathlib.Path(__file__).parent
+root = current.parent
+
+import sys
+sys.path.append(str(root))
+
+import assets
+

+ 30 - 0
tests/001-validator.py

@@ -0,0 +1,30 @@
+import pathlib
+
+current = pathlib.Path(__file__).parent
+root = current.parent
+
+import sys
+sys.path.append(str(root))
+
+import assets
+
+def dump(content: str, validator: type) -> None:
+    result = "valid" if validator(content).result else "invalid"
+
+    if len(content) > 20:
+        content = content[:17] + "..."
+
+    print("Check validator on \"" + content + "\", result: " + result)
+
+dump("Name", assets.name_validator)
+dump("X game", assets.name_validator)
+dump(" Invaluid name", assets.name_validator)
+dump(" ", assets.name_validator)
+dump("", assets.description_validator)
+dump("UwU" * 200, assets.description_validator)
+dump(" x", assets.description_validator)
+dump("UwU", assets.barcode_validator)
+dump("12345678", assets.barcode_validator)
+dump("12121212121", assets.barcode_validator)
+dump("121212121212", assets.barcode_validator)
+dump("1212121212123", assets.barcode_validator)