py-flexo 0.1.0__tar.gz → 0.2.0__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: py-flexo
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Python Web Framework built for learning purposes
5
5
  Requires-Python: >=3.12
6
6
  Description-Content-Type: text/markdown
@@ -0,0 +1,199 @@
1
+ import sqlite3
2
+ import inspect
3
+
4
+ class Database:
5
+ def __init__(self, path):
6
+ self.conn = sqlite3.Connection(path)
7
+
8
+ @property
9
+ def tables(self):
10
+ result = self.conn.execute("SELECT name FROM sqlite_master WHERE type='table';")
11
+ return [row[0] for row in result.fetchall()]
12
+
13
+ def create(self, table):
14
+ self.conn.execute(table._get_create_sql())
15
+
16
+ def save(self, instance):
17
+ sql, values = instance._insert_sql()
18
+ cursor = self.conn.execute(sql, values)
19
+ self.conn.commit()
20
+ instance._data["id"] = cursor.lastrowid
21
+
22
+ def all(self, table):
23
+ sql, fields = table._get_select_all_sql()
24
+ result = []
25
+ for row in self.conn.execute(sql).fetchall():
26
+ instance = table()
27
+ for field, value in zip(fields, row):
28
+ if field.endswith("_id"):
29
+ field = field[:-3]
30
+ fk = getattr(table, field)
31
+ value = self.get(fk.table, value)
32
+ setattr(instance, field, value)
33
+
34
+ result.append(instance)
35
+
36
+ return result
37
+
38
+ def get(self, table, id):
39
+ sql, fields = table._get_by_id_sql(id = id)
40
+ result = self.conn.execute(sql).fetchone()
41
+ if result is None:
42
+ raise Exception(f"{table.__name__} not found for id {id}")
43
+ instance = table()
44
+ for field, value in zip(fields, result):
45
+ if field.endswith("_id"):
46
+ field = field[:-3]
47
+ fk = getattr(table, field)
48
+ value = self.get(fk.table, value)
49
+ setattr(instance, field, value)
50
+ return instance
51
+
52
+ def update(self, instance):
53
+ sql, values = instance._update_sql()
54
+ self.conn.execute(sql, values)
55
+ self.conn.commit()
56
+
57
+ def delete(self, instance):
58
+ sql= instance._delete_sql()
59
+ self.conn.execute(sql)
60
+ self.conn.commit()
61
+
62
+
63
+ class Table:
64
+ def __init__(self, **kwargs):
65
+ self._data = {
66
+ "id": None
67
+ }
68
+
69
+ for name, value in kwargs.items():
70
+ self._data[name] = value
71
+
72
+
73
+ @classmethod
74
+ def _get_create_sql(cls):
75
+ CREATE_TABLE_SQL = 'CREATE TABLE IF NOT EXISTS {name} ({fields});'
76
+ fields = [
77
+ 'id INTEGER PRIMARY KEY AUTOINCREMENT'
78
+ ]
79
+
80
+ for name, col in inspect.getmembers(cls):
81
+ if isinstance(col, Column):
82
+ fields.append(f"{name} {col.sql_type}")
83
+
84
+ elif isinstance(col, ForeignKey):
85
+ fields.append(f"{name}_id INTEGER")
86
+ name = cls.__name__.lower()
87
+ fields = ", ".join(fields)
88
+
89
+ return CREATE_TABLE_SQL.format(name=name, fields=fields)
90
+
91
+ def _insert_sql(self):
92
+ INSERT_SQL = 'INSERT INTO {name} ({fields}) VALUES ({placeholders});'
93
+ cls = self.__class__
94
+ fields = []
95
+ placeholders = []
96
+ values = []
97
+
98
+ for name, col in inspect.getmembers(cls):
99
+ if isinstance(col, Column):
100
+ fields.append(name)
101
+ placeholders.append('?')
102
+ values.append(self._data[name])
103
+ elif isinstance(col, ForeignKey):
104
+ fields.append(f"{name}_id")
105
+ placeholders.append('?')
106
+ values.append(self._data[name].id)
107
+
108
+ fields = ", ".join(fields)
109
+ placeholders = ", ".join(placeholders)
110
+
111
+ name_table = cls.__name__.lower()
112
+
113
+ sql = INSERT_SQL.format(name=name_table, fields=fields, placeholders=placeholders)
114
+
115
+ return sql, values
116
+
117
+ def __getattribute__(self, name):
118
+ data = super().__getattribute__('_data')
119
+ if name in data:
120
+ return self._data[name]
121
+
122
+ return super().__getattribute__(name)
123
+
124
+ def __setattr__(self, name, value):
125
+ super().__setattr__(name, value)
126
+ if name in self._data:
127
+ self._data[name] = value
128
+
129
+
130
+ @classmethod
131
+ def _get_select_all_sql(cls):
132
+ SELECT_ALL_SQL = 'SELECT {fields} FROM {name};'
133
+ fields = ['id']
134
+ for name, col in inspect.getmembers(cls):
135
+ if isinstance(col, Column):
136
+ fields.append(name)
137
+ elif isinstance(col, ForeignKey):
138
+ fields.append(f"{name}_id")
139
+ name = cls.__name__.lower()
140
+ sql = SELECT_ALL_SQL.format(fields=', '.join(fields), name=name)
141
+
142
+ return sql, fields
143
+
144
+ @classmethod
145
+ def _get_by_id_sql(cls, id):
146
+ SELECT_BY_ID_SQL = 'SELECT {fields} FROM {name} WHERE id = {id};'
147
+ fields = ['id']
148
+ for name, col in inspect.getmembers(cls):
149
+ if isinstance(col, Column):
150
+ fields.append(name)
151
+ elif isinstance(col, ForeignKey):
152
+ fields.append(f"{name}_id")
153
+ name = cls.__name__.lower()
154
+ sql = SELECT_BY_ID_SQL.format(fields=', '.join(fields), name=name, id=id)
155
+
156
+ return sql, fields
157
+
158
+ def _update_sql(self):
159
+ UPDATE_SQL = 'UPDATE {name} SET {fields} WHERE id = {id};'
160
+ fields = []
161
+ values = []
162
+ for name, col in inspect.getmembers(self.__class__):
163
+ if isinstance(col, Column):
164
+ fields.append(f"{name} = ?")
165
+ values.append(getattr(self, name))
166
+ elif isinstance(col, ForeignKey):
167
+ fields.append(f"{name}_id = ?")
168
+ values.append(getattr(col.table, 'id'))
169
+
170
+ name = self.__class__.__name__.lower()
171
+ sql = UPDATE_SQL.format(fields=', '.join(fields), name=name, id=self.id)
172
+
173
+ return sql, values
174
+
175
+ def _delete_sql(self):
176
+ DELETE_SQL = 'DELETE FROM {name} WHERE id = {id};'
177
+ name = self.__class__.__name__.lower()
178
+ sql = DELETE_SQL.format(name=name, id=self.id)
179
+
180
+ return sql
181
+
182
+ class Column:
183
+ def __init__(self, column_type):
184
+ self.type = column_type
185
+
186
+ @property
187
+ def sql_type(self):
188
+ SQLITE_TYPE_MAP = {
189
+ int: 'INTEGER',
190
+ float: 'REAL',
191
+ bool: 'INTEGER',
192
+ str: 'TEXT'
193
+ }
194
+
195
+ return SQLITE_TYPE_MAP[self.type]
196
+
197
+ class ForeignKey:
198
+ def __init__(self, table):
199
+ self.table = table
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: py-flexo
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Python Web Framework built for learning purposes
5
5
  Requires-Python: >=3.12
6
6
  Description-Content-Type: text/markdown
@@ -3,6 +3,7 @@ pyproject.toml
3
3
  py_flexo/__init__.py
4
4
  py_flexo/app.py
5
5
  py_flexo/middleware.py
6
+ py_flexo/orm.py
6
7
  py_flexo/response.py
7
8
  py_flexo.egg-info/PKG-INFO
8
9
  py_flexo.egg-info/SOURCES.txt
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "py-flexo"
3
- version = "0.1.0"
3
+ version = "0.2.0"
4
4
  description = "Python Web Framework built for learning purposes"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
File without changes
File without changes
File without changes
File without changes
File without changes