python-general-be-lib 0.5.2__py3-none-any.whl → 0.5.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,4 +2,5 @@ from .base_handler import *
2
2
  from .ilike_handler import *
3
3
  from .interval_handler import *
4
4
  from .json_handler import *
5
+ from .json_ilike_handler import *
5
6
  from .statement_manager import *
@@ -0,0 +1,104 @@
1
+ __all__ = ["JsonILikeHandler"]
2
+
3
+ from typing import Any
4
+
5
+ from general.interface.repository.handler import BaseHandler
6
+ from sqlalchemy import Column, Select, Update, Delete, or_
7
+ from sqlalchemy.sql.base import ReadOnlyColumnCollection
8
+
9
+
10
+ class JsonILikeHandler(BaseHandler):
11
+ """Handler per ricerche case-insensitive (ILIKE) su più colonne tramite un alias.
12
+
13
+ Permette di esporre un singolo parametro di ricerca testuale (es. ``"search"``)
14
+ che viene applicato come ``ILIKE '%value%'`` su un insieme di colonne con ``OR``.
15
+
16
+ Attributes:
17
+ ilike_aliases (list[str]): Chiavi nel dizionario ``where`` che attivano
18
+ la ricerca ILIKE (es. ``["search", "q"]``).
19
+ ilike_attributes (list[str]): Nomi delle colonne su cui applicare ILIKE
20
+ (es. ``["name", "surname", "email"]``).
21
+
22
+ Example:
23
+ >>> handler = JsonILikeHandler(
24
+ ... columns=User.columns(),
25
+ ... ilike_aliases=["search"],
26
+ ... ilike_attributes=["name", "surname"]
27
+ ... )
28
+ >>> repo.find(where={"search": "mario"})
29
+ # WHERE name ILIKE '%mario%' OR surname ILIKE '%mario%'
30
+ """
31
+ __slots__ = "ilike_aliases", "ilike_attributes", "json_column", "json_ilike_keys"
32
+ ilike_aliases: list[str]
33
+ ilike_attributes: list[str]
34
+ json_ilike_keys: list[str]
35
+ json_column: str
36
+
37
+ def __init__(self, columns: ReadOnlyColumnCollection[str, Column[Any]], ilike_aliases: list[str] = None, ilike_attributes: list[str] = None):
38
+ """Inizializza l'handler validando che le colonne ILIKE esistano sull'entità.
39
+
40
+ Args:
41
+ columns (ReadOnlyColumnCollection): Colonne della tabella.
42
+ ilike_aliases (list[str], optional): Chiavi alias che attivano la ricerca.
43
+ Default: lista vuota.
44
+ ilike_attributes (list[str], optional): Colonne su cui applicare ILIKE.
45
+ Default: lista vuota.
46
+
47
+ Raises:
48
+ ValueError: Se uno degli ``ilike_attributes`` non è presente tra le colonne.
49
+ """
50
+ self.columns = columns
51
+ self.ilike_aliases = ilike_aliases if ilike_aliases is not None else []
52
+ self.ilike_attributes = []
53
+ self.json_ilike_keys = []
54
+
55
+ if ilike_attributes:
56
+ for ilike_attribute in ilike_attributes:
57
+ if ilike_attribute not in self.columns:
58
+ self.json_ilike_keys.append(ilike_attribute)
59
+ else:
60
+ self.ilike_attributes.append(ilike_attribute)
61
+
62
+ for key, column in columns.items():
63
+ try:
64
+ if column.type.python_type == dict:
65
+ self.json_column = key
66
+ break
67
+ except NotImplementedError:
68
+ continue
69
+
70
+ def handle(self, stmt: Select | Update | Delete, where: dict[str, Any] = None, **kwargs):
71
+ """Applica i filtri ILIKE allo statement per ogni alias trovato in ``where``.
72
+
73
+ Per ogni alias presente in ``ilike_aliases`` e trovato in ``where``,
74
+ estrae il valore, lo rimuove dal dizionario e aggiunge la condizione ILIKE
75
+ su tutte le colonne in ``ilike_attributes`` con ``OR``.
76
+
77
+ Args:
78
+ stmt (Select | Update | Delete): Statement su cui applicare i filtri.
79
+ where (dict[str, Any]): Dizionario dei filtri. Gli alias ILIKE vengono
80
+ estratti e rimossi in-place.
81
+ **kwargs: Ignorati (compatibilità con l'interfaccia base).
82
+
83
+ Returns:
84
+ Select | Update | Delete: Statement con le condizioni ILIKE aggiunte.
85
+ """
86
+
87
+ for alias in self.ilike_aliases:
88
+ condition = where.pop(alias, None)
89
+ if condition:
90
+ stmt = stmt.where(self._handle(alias, condition))
91
+ return stmt
92
+
93
+ def _handle(self, alias: str, condition: str, neq: bool = False):
94
+ """Costruisce la condizione ILIKE con OR su tutte le colonne configurate.
95
+
96
+ Args:
97
+ alias (str): Alias attivato (usato per identificare la ricerca, non la colonna).
98
+ condition (str): Stringa da cercare (viene wrappata con ``%``).
99
+ neq (bool): Non utilizzato in questa implementazione.
100
+
101
+ Returns:
102
+ ColumnElement: Espressione ``OR(col1 ILIKE '%val%', col2 ILIKE '%val%', ...)``.
103
+ """
104
+ return or_(*[self.columns[col].ilike(f'%{condition}%') for col in self.ilike_attributes], *[self.columns[self.json_column][key].as_string().ilike(f'%{condition}%') for key in self.json_ilike_keys])
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-general-be-lib
3
- Version: 0.5.2
3
+ Version: 0.5.3
4
4
  Summary: General purpose backend library — SQLAlchemy CRUD/Geometry repositories, FastAPI exceptions, Pydantic base models, logger utilities.
5
5
  Author-email: Andrea Di Placido <a.diplacido@arpes.it>, "Arpes S.r.l." <it.admin@arpes.it>
6
6
  License: MIT
@@ -17,14 +17,15 @@ general/interface/repository/crud_repository.py,sha256=j70VKjcVmkFVTZTYA9KQBKSnZ
17
17
  general/interface/repository/geometry_repository.py,sha256=bJVPhsr-fGhVTywdHwx9Qt_inWPHk5wqq9EFWFLfuGU,11181
18
18
  general/interface/repository/many_to_many_repository.py,sha256=iEhWyD8nPZSAPL8Z2wXrK-aRBnoh3evaSN-voaf0EP0,8662
19
19
  general/interface/repository/view_repository.py,sha256=Sm591FUP0iBYlI-ULNWszD5fOvTGwXX0iYoeDbUqo34,5397
20
- general/interface/repository/handler/__init__.py,sha256=-WaJmlNxA4oDw_4lWgUsqoqo1UHABY8hmnXG1lDfOrI,150
20
+ general/interface/repository/handler/__init__.py,sha256=J-fc-5Dl_C821oy_EVRdyU-L2iXiNFriYJDbK4ODIMM,184
21
21
  general/interface/repository/handler/base_handler.py,sha256=YEdE-S1JnLMo0LZn_9rHjEUgDNEM-qjcbNZ_rhsBnpg,2800
22
22
  general/interface/repository/handler/ilike_handler.py,sha256=_HHTvj6Tm1L-WvUy1S9faRChoRZni11i9mv76I4Xak0,3919
23
23
  general/interface/repository/handler/interval_handler.py,sha256=XxMQr6UuWnoCtbOOO7l80_Yja_aPKYtHhDfhFCRMaKg,4135
24
24
  general/interface/repository/handler/json_handler.py,sha256=7bS59seB-It5KHsWXTbHGsEvbQZ6lYyvX-d29BcRLVE,2956
25
+ general/interface/repository/handler/json_ilike_handler.py,sha256=yDuKER3yqtnHpVWndF8PVEaqDThcq1EhZzLaqxbQ0bU,4491
25
26
  general/interface/repository/handler/statement_manager.py,sha256=2_AjORmDnKtRaHxZc8RLKe68soNVv2YBRCB5jihgvcY,4392
26
- python_general_be_lib-0.5.2.dist-info/licenses/LICENSE,sha256=iUaO1XZyB9P3Tmog0OILuTisP6vXGe3QKz-4yRTxOFk,1069
27
- python_general_be_lib-0.5.2.dist-info/METADATA,sha256=08TJivyau73qu4SUj1i11ZDyKsVDWAXHBfDYNT7sRCo,1384
28
- python_general_be_lib-0.5.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
29
- python_general_be_lib-0.5.2.dist-info/top_level.txt,sha256=tTZePW8_CNUqSgKFd2SEH72ZbnhS0OYjRsgcv0ikSFY,8
30
- python_general_be_lib-0.5.2.dist-info/RECORD,,
27
+ python_general_be_lib-0.5.3.dist-info/licenses/LICENSE,sha256=iUaO1XZyB9P3Tmog0OILuTisP6vXGe3QKz-4yRTxOFk,1069
28
+ python_general_be_lib-0.5.3.dist-info/METADATA,sha256=ppE7Y1Ij9o6lkL9QY0Kn8NLBPfvaFRHFMmmtEnK8tKU,1384
29
+ python_general_be_lib-0.5.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
30
+ python_general_be_lib-0.5.3.dist-info/top_level.txt,sha256=tTZePW8_CNUqSgKFd2SEH72ZbnhS0OYjRsgcv0ikSFY,8
31
+ python_general_be_lib-0.5.3.dist-info/RECORD,,