hypern 0.3.2__cp311-cp311-win32.whl → 0.3.3__cp311-cp311-win32.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.
hypern/db/sql/model.py ADDED
@@ -0,0 +1,116 @@
1
+ import re
2
+ from datetime import date, datetime
3
+
4
+ from hypern.config import context_store
5
+ from hypern.exceptions import OutOfScopeApplicationException
6
+ from hypern.hypern import get_session_database
7
+
8
+ from .field import Field, ForeignKey
9
+ from .query import QuerySet
10
+
11
+
12
+ class MetaModel(type):
13
+ def __new__(mcs, name, bases, attrs):
14
+ # Skip initialization for base Model class
15
+ if name == "Model" and not bases:
16
+ return super().__new__(mcs, name, bases, attrs)
17
+
18
+ fields = {}
19
+ table_name = attrs.get("__tablename__")
20
+
21
+ # If table name not specified, convert CamelCase to snake_case
22
+ if not table_name:
23
+ table_name = re.sub("(?!^)([A-Z])", r"_\1", name).lower()
24
+
25
+ # Collect all fields
26
+ for key, value in list(attrs.items()):
27
+ if isinstance(value, Field):
28
+ fields[key] = value
29
+ value.name = key
30
+
31
+ # Store metadata in class
32
+ attrs["_fields"] = fields
33
+ attrs["_table_name"] = table_name
34
+
35
+ return super().__new__(mcs, name, bases, attrs)
36
+
37
+
38
+ class Model(metaclass=MetaModel):
39
+ def __init__(self, **kwargs):
40
+ self._data = {}
41
+ # Set default values
42
+ for name, field in self._fields.items():
43
+ if field.default is not None:
44
+ self._data[name] = field.default
45
+
46
+ # Set provided values
47
+ for key, value in kwargs.items():
48
+ if key in self._fields:
49
+ self._fields[key].validate(value)
50
+ self._data[key] = value
51
+ else:
52
+ raise ValueError(f"Unknown field {key}")
53
+
54
+ @classmethod
55
+ def get_session(cls):
56
+ try:
57
+ context_id = context_store.get_context()
58
+ except Exception:
59
+ raise OutOfScopeApplicationException("Context not set")
60
+ return get_session_database(context_id)
61
+
62
+ @classmethod
63
+ def objects(cls) -> QuerySet:
64
+ return QuerySet(cls)
65
+
66
+ @classmethod
67
+ def table_name(cls) -> str:
68
+ return cls._table_name
69
+
70
+ @classmethod
71
+ def create_table_sql(cls) -> str:
72
+ fields_sql = []
73
+ indexes_sql = []
74
+ foreign_keys = []
75
+
76
+ for name, field in cls._fields.items():
77
+ fields_sql.append(cls._get_field_sql(name, field))
78
+ if field.index:
79
+ indexes_sql.append(cls._get_index_sql(name))
80
+ if isinstance(field, ForeignKey):
81
+ foreign_keys.append(cls._get_foreign_key_sql(name, field))
82
+
83
+ fields_sql.extend(foreign_keys)
84
+ joined_fields_sql = ", \n ".join(fields_sql)
85
+
86
+ create_table = f"CREATE TABLE {cls.table_name()} (\n {joined_fields_sql} \n"
87
+
88
+ return f"{create_table};\n" + ";\n".join(indexes_sql)
89
+
90
+ @classmethod
91
+ def _get_field_sql(cls, name, field) -> str:
92
+ field_def = [f"{name} {field.sql_type()}"]
93
+ if field.primary_key:
94
+ field_def.append("PRIMARY KEY")
95
+ if not field.null:
96
+ field_def.append("NOT NULL")
97
+ if field.unique:
98
+ field_def.append("UNIQUE")
99
+ if field.default is not None:
100
+ if isinstance(field.default, (str, datetime, date)):
101
+ field_def.append(f"DEFAULT '{field.default}'")
102
+ else:
103
+ field_def.append(f"DEFAULT {field.default}")
104
+ return " ".join(field_def)
105
+
106
+ @classmethod
107
+ def _get_index_sql(cls, name) -> str:
108
+ return f"CREATE INDEX idx_{cls.table_name()}_{name} ON {cls.table_name()} ({name})"
109
+
110
+ @classmethod
111
+ def _get_foreign_key_sql(cls, name, field) -> str:
112
+ return f"FOREIGN KEY ({name}) REFERENCES {field.to_model}(id) ON DELETE {field.on_delete} ON UPDATE {field.on_update}"
113
+
114
+ def save(self):
115
+ query_object = QuerySet(self)
116
+ query_object.bulk_create([self])