product_loader.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. import typing
  2. import sqlmodel
  3. import sqlmodel.sql._expression_select_cls
  4. from .product import product
  5. from .product import product_factory
  6. from .validator import barcode_validator
  7. from .validator import name_validator
  8. from .validator import description_validator
  9. from .validator import author_validator
  10. from .exception import validator_exception
  11. class product_loader(sqlmodel.Session):
  12. """
  13. This is loader for product. It help in work with product database, and
  14. manage of the product of course.
  15. """
  16. def get_by_barcode(self, target: str) -> product | None:
  17. """
  18. It load product by barcode. When product with given barcode not
  19. exists, return None. It also validate barcode, and when it is not
  20. property, raise validation exception.
  21. Parameters:
  22. target (str): Barcode of product to load
  23. Returns:
  24. (product): Product with given barcode from database
  25. (None): When product not exists
  26. """
  27. if barcode_validator(target).invalid:
  28. raise validator_exception("get.barcode")
  29. query = self.__select.where(product.barcode == target)
  30. result = self.exec(query)
  31. return result.first()
  32. def get_by_name(self, target: str) -> product | None:
  33. """
  34. It load product by name. When product with given name not exists,
  35. returns None. It also validate name, and if it is not correct,
  36. raise validation_exception.
  37. Parameters:
  38. target (str): Name of the product to load
  39. Returns:
  40. (product): Product with given name
  41. (None): When product with that name not exists
  42. """
  43. if name_validator(target).invalid:
  44. raise validator_exception("get.name")
  45. query = self.__select.where(product.name == target)
  46. result = self.exec(query)
  47. return result.first()
  48. def search_by_name(self, target: str) -> typing.Iterable[product]:
  49. """
  50. This search by name. To start searching phrase with could be valid
  51. name must be given, that mean it could not be too short or too long.
  52. If phrase is not valid, then validator_exception is raised.
  53. Parameters:
  54. target (str): Phrase to search in names
  55. Returns:
  56. (Iterable[product]): Generator with products found by name
  57. """
  58. if name_validator(target).invalid:
  59. raise validator_exception("search.name")
  60. target = "%" + target + "%"
  61. query = self.__select.where(product.name.like(target))
  62. result = self.exec(query)
  63. for item in result:
  64. yield item
  65. def search_by_author(self, target: str) -> typing.Iterable[product]:
  66. """
  67. This search products by author. Author must be valid, when it is not
  68. then validation_exception would be raised.
  69. Parameters:
  70. target (str): Author to search product for
  71. Returns:
  72. (Iterable[product]): Generator with products with author
  73. """
  74. if author_validator(target).invalid:
  75. raise validator_exception("search.author")
  76. target = "%" + target + "%"
  77. query = self.__select.where(product.author.like(target))
  78. result = self.exec(query)
  79. for item in result:
  80. yield item
  81. def load_all(self) -> typing.Iterable[product]:
  82. """
  83. This load all products from database.
  84. Returns:
  85. (Iterable[produdct]): Generator with products from database
  86. """
  87. query = self.__select
  88. result = self.exec(query)
  89. for item in result:
  90. yield item
  91. def barcode_in_use(self, target: str) -> bool:
  92. """
  93. It check that barcode is already in use by any product.
  94. Parameters:
  95. target (str): Barcode to check
  96. Returns:
  97. (bool): True when item exists, false when not
  98. """
  99. return self.get_by_barcode(target) is not None
  100. def name_in_use(self, target: str) -> bool:
  101. """
  102. It check that name is already in use by any element.
  103. Parameters:
  104. target (str): Name to check that is in use
  105. Returns:
  106. (bool): True when name in use, False when not
  107. """
  108. return self.get_by_name(target) is not None
  109. def __append(self, target: product) -> bool:
  110. """
  111. This insert new product into database, when it is not stored yet. It
  112. check that item is ready, also barcode and name can not be in use.
  113. Parameters:
  114. target (product): Product to insert into database
  115. Returns:
  116. (bool): True when success, False when not
  117. """
  118. if self.barcode_in_use(target.barcode):
  119. exists_exception("barcode")
  120. if self.name_in_use(target.name):
  121. exists_exception("name")
  122. self.add(target)
  123. self.commit()
  124. self.refresh(target)
  125. return True
  126. def store(self, target: product) -> bool:
  127. """
  128. This save product into database. When product is not in database yet,
  129. then it inserting. If product is in database, then updating it. It
  130. check that new barcode and name is not already in use by another
  131. product.
  132. Parameters:
  133. target (product): Product to save or insert
  134. Returns:
  135. (bool): True when save success, False when not
  136. """
  137. if not target.ready:
  138. return False
  139. if not target.in_database:
  140. return self.__append(target)
  141. name_use = self.get_by_name(target.name)
  142. if name_use is not None and name_use.id != target.id:
  143. return False
  144. barcode_use = self.get_by_barcode(target.barcode)
  145. if barcode_use is not None and barcode_use.id != target.id:
  146. return False
  147. try:
  148. self.add(target)
  149. self.commit()
  150. self.refresh(target)
  151. return True
  152. except:
  153. return False
  154. def drop(self, target: product) -> bool:
  155. """
  156. This remove product from database. Product must exists, to delete
  157. it from storage.
  158. Parameters:
  159. target (product): Item to delete
  160. Returns:
  161. (bool): True when deleted successfull, False if not
  162. """
  163. if not target.in_database:
  164. return False
  165. try:
  166. self.delete(target)
  167. self.commit()
  168. return True
  169. except:
  170. return False
  171. @property
  172. def __select(self) -> sqlmodel.sql._expression_select_cls.SelectOfScalar:
  173. """ New product selector. """
  174. return sqlmodel.select(product)