product_loader.py 6.9 KB

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