join tested auth service login/select completed

This commit is contained in:
2025-05-13 13:19:01 +03:00
parent 1d4f00e8b2
commit cd62d96158
34 changed files with 1360 additions and 231 deletions

View File

@@ -1,12 +1,18 @@
import arrow
import datetime
from sqlalchemy import Column, Integer, String, Float, ForeignKey, UUID, TIMESTAMP, Boolean, SmallInteger, Numeric, func, text
from decimal import Decimal
from typing import Any, Optional
from sqlalchemy import Column, Integer, String, Float, ForeignKey, UUID, TIMESTAMP, Boolean, SmallInteger, Numeric, func, text, NUMERIC
from sqlalchemy.orm import relationship
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy_mixins.serialize import SerializeMixin
from sqlalchemy_mixins.repr import ReprMixin
from sqlalchemy_mixins.smartquery import SmartQueryMixin
from sqlalchemy_mixins.activerecord import ActiveRecordMixin
from sqlalchemy.orm import InstrumentedAttribute, Mapped
from api_controllers.postgres.engine import get_db, Base
@@ -26,6 +32,100 @@ class BasicMixin(
"""Get database session."""
return get_db()
@classmethod
def iterate_over_variables(cls, val: Any, key: str) -> tuple[bool, Optional[Any]]:
"""
Process a field value based on its type and convert it to the appropriate format.
Args:
val: Field value
key: Field name
Returns:
Tuple of (should_include, processed_value)
"""
try:
key_ = cls.__annotations__.get(key, None)
is_primary = key in getattr(cls, "primary_keys", [])
row_attr = bool(getattr(getattr(cls, key), "foreign_keys", None))
# Skip primary keys and foreign keys
if is_primary or row_attr:
return False, None
if val is None: # Handle None values
return True, None
if str(key[-5:]).lower() == "uu_id": # Special handling for UUID fields
return True, str(val)
if key_: # Handle typed fields
if key_ == Mapped[int]:
return True, int(val)
elif key_ == Mapped[bool]:
return True, bool(val)
elif key_ == Mapped[float] or key_ == Mapped[NUMERIC]:
return True, round(float(val), 3)
elif key_ == Mapped[TIMESTAMP]:
return True, str(arrow.get(str(val)).format("YYYY-MM-DD HH:mm:ss"))
elif key_ == Mapped[str]:
return True, str(val)
else: # Handle based on Python types
if isinstance(val, datetime.datetime):
return True, str(arrow.get(str(val)).format("YYYY-MM-DD HH:mm:ss"))
elif isinstance(val, bool):
return True, bool(val)
elif isinstance(val, (float, Decimal)):
return True, round(float(val), 3)
elif isinstance(val, int):
return True, int(val)
elif isinstance(val, str):
return True, str(val)
elif val is None:
return True, None
return False, None
except Exception as e:
err = e
return False, None
def get_dict(self, exclude_list: Optional[list[InstrumentedAttribute]] = None) -> dict[str, Any]:
"""
Convert model instance to dictionary with customizable fields.
Args:
exclude_list: List of fields to exclude from the dictionary
Returns:
Dictionary representation of the model
"""
try:
return_dict: Dict[str, Any] = {}
exclude_list = exclude_list or []
exclude_list = [exclude_arg.key for exclude_arg in exclude_list]
# Get all column names from the model
columns = [col.name for col in self.__table__.columns]
columns_set = set(columns)
# Filter columns
columns_list = set([col for col in columns_set if str(col)[-2:] != "id"])
columns_extend = set(col for col in columns_set if str(col)[-5:].lower() == "uu_id")
columns_list = set(columns_list) | set(columns_extend)
columns_list = list(set(columns_list) - set(exclude_list))
for key in columns_list:
val = getattr(self, key)
correct, value_of_database = self.iterate_over_variables(val, key)
if correct:
return_dict[key] = value_of_database
return return_dict
except Exception as e:
err = e
return {}
class CrudMixin(BasicMixin):
"""

View File

@@ -10,9 +10,9 @@ This module provides a class for managing Redis key-value operations with suppor
import arrow
import json
from typing import Union, Dict, List, Optional, Any, TypeVar
from Controllers.Redis.connection import redis_cli
from typing import Union, Dict, List, Optional, Any, TypeVar
from .connection import redis_cli
T = TypeVar("T", Dict[str, Any], List[Any])

View File

@@ -2,7 +2,7 @@ import time
from typing import Dict, Any
from redis import Redis, ConnectionError, TimeoutError, ConnectionPool
from Controllers.Redis.config import redis_configs
from .config import redis_configs
class RedisConn:

View File

@@ -2,9 +2,9 @@ import arrow
from typing import Optional, List, Dict, Union, Iterator
from Controllers.Redis.response import RedisResponse
from Controllers.Redis.connection import redis_cli
from Controllers.Redis.base import RedisRow
from .response import RedisResponse
from .connection import redis_cli
from .base import RedisRow
class MainConfig:
@@ -87,9 +87,7 @@ class RedisActions:
return bool(redis_cli.exists(key))
@classmethod
def refresh_ttl(
cls, key: Union[str, bytes], expires: Dict[str, int]
) -> RedisResponse:
def refresh_ttl(cls, key: Union[str, bytes], expires: Dict[str, int]) -> RedisResponse:
"""
Refresh TTL for an existing key.
@@ -160,9 +158,7 @@ class RedisActions:
)
@classmethod
def delete(
cls, list_keys: List[Union[Optional[str], Optional[bytes]]]
) -> RedisResponse:
def delete(cls, list_keys: List[Union[Optional[str], Optional[bytes]]]) -> RedisResponse:
"""
Delete multiple keys matching a pattern.
@@ -199,12 +195,7 @@ class RedisActions:
)
@classmethod
def set_json(
cls,
list_keys: List[Union[str, bytes]],
value: Optional[Union[Dict, List]],
expires: Optional[Dict[str, int]] = None,
) -> RedisResponse:
def set_json(cls, list_keys: List[Union[str, bytes]], value: Optional[Union[Dict, List]], expires: Optional[Dict[str, int]] = None) -> RedisResponse:
"""
Set JSON value in Redis with optional expiry.
@@ -252,11 +243,7 @@ class RedisActions:
)
@classmethod
def get_json(
cls,
list_keys: List[Union[Optional[str], Optional[bytes]]],
limit: Optional[int] = None,
) -> RedisResponse:
def get_json(cls, list_keys: List[Union[Optional[str], Optional[bytes]]], limit: Optional[int] = None) -> RedisResponse:
"""
Get JSON values from Redis using pattern matching.
@@ -313,9 +300,7 @@ class RedisActions:
)
@classmethod
def get_json_iterator(
cls, list_keys: List[Union[Optional[str], Optional[bytes]]]
) -> Iterator[RedisRow]:
def get_json_iterator(cls, list_keys: List[Union[Optional[str], Optional[bytes]]]) -> Iterator[RedisRow]:
"""
Get JSON values from Redis as an iterator for memory-efficient processing of large datasets.

View File

@@ -1,10 +1,11 @@
from Controllers.Redis.database import RedisActions
import threading
import time
import random
import uuid
import concurrent.futures
from .database import RedisActions
def example_set_json() -> None:
"""Example of setting JSON data in Redis with and without expiry."""

View File

@@ -1,5 +1,5 @@
from typing import Union, Dict, Optional, Any
from Controllers.Redis.base import RedisRow
from .base import RedisRow
class RedisResponse:
@@ -10,13 +10,7 @@ class RedisResponse:
with tools to convert between different data representations.
"""
def __init__(
self,
status: bool,
message: str,
data: Any = None,
error: Optional[str] = None,
):
def __init__(self, status: bool, message: str, data: Any = None, error: Optional[str] = None):
"""
Initialize a Redis response.