square_database_structure 2.8.1__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.
- square_database_structure-2.8.1/PKG-INFO +243 -0
- square_database_structure-2.8.1/README.md +216 -0
- square_database_structure-2.8.1/pyproject.toml +38 -0
- square_database_structure-2.8.1/square_database_structure/__init__.py +1 -0
- square_database_structure-2.8.1/square_database_structure/create_database.py +108 -0
- square_database_structure-2.8.1/square_database_structure/main.py +101 -0
- square_database_structure-2.8.1/square_database_structure/square/__init__.py +1 -0
- square_database_structure-2.8.1/square_database_structure/square/authentication/__init__.py +1 -0
- square_database_structure-2.8.1/square_database_structure/square/authentication/data.py +1 -0
- square_database_structure-2.8.1/square_database_structure/square/authentication/enums.py +17 -0
- square_database_structure-2.8.1/square_database_structure/square/authentication/stored_procedures_and_functions/__init__.py +10 -0
- square_database_structure-2.8.1/square_database_structure/square/authentication/tables.py +242 -0
- square_database_structure-2.8.1/square_database_structure/square/email/__init__.py +1 -0
- square_database_structure-2.8.1/square_database_structure/square/email/data.py +1 -0
- square_database_structure-2.8.1/square_database_structure/square/email/enums.py +11 -0
- square_database_structure-2.8.1/square_database_structure/square/email/stored_procedures_and_functions/__init__.py +10 -0
- square_database_structure-2.8.1/square_database_structure/square/email/tables.py +57 -0
- square_database_structure-2.8.1/square_database_structure/square/file_storage/__init__.py +1 -0
- square_database_structure-2.8.1/square_database_structure/square/file_storage/data.py +1 -0
- square_database_structure-2.8.1/square_database_structure/square/file_storage/enums.py +0 -0
- square_database_structure-2.8.1/square_database_structure/square/file_storage/stored_procedures_and_functions/__init__.py +10 -0
- square_database_structure-2.8.1/square_database_structure/square/file_storage/stored_procedures_and_functions/get_file_count.sql +11 -0
- square_database_structure-2.8.1/square_database_structure/square/file_storage/tables.py +40 -0
- square_database_structure-2.8.1/square_database_structure/square/greeting/__init__.py +1 -0
- square_database_structure-2.8.1/square_database_structure/square/greeting/data.py +1 -0
- square_database_structure-2.8.1/square_database_structure/square/greeting/enums.py +0 -0
- square_database_structure-2.8.1/square_database_structure/square/greeting/stored_procedures_and_functions/__init__.py +10 -0
- square_database_structure-2.8.1/square_database_structure/square/greeting/tables.py +35 -0
- square_database_structure-2.8.1/square_database_structure/square/public/__init__.py +1 -0
- square_database_structure-2.8.1/square_database_structure/square/public/data.py +7 -0
- square_database_structure-2.8.1/square_database_structure/square/public/enums.py +8 -0
- square_database_structure-2.8.1/square_database_structure/square/public/stored_procedures_and_functions/__init__.py +10 -0
- square_database_structure-2.8.1/square_database_structure/square/public/stored_procedures_and_functions/get_test_text.sql +12 -0
- square_database_structure-2.8.1/square_database_structure/square/public/tables.py +42 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: square_database_structure
|
|
3
|
+
Version: 2.8.1
|
|
4
|
+
Summary: database scheme for my personal server.
|
|
5
|
+
Keywords: database,sqlalchemy,utilities
|
|
6
|
+
Author: Parth Mukesh Mangtani
|
|
7
|
+
Author-email: Parth Mukesh Mangtani <thepmsquare@gmail.com>
|
|
8
|
+
License: GPLv3
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
+
Classifier: Topic :: Database
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Requires-Dist: sqlalchemy>=2.0.23
|
|
19
|
+
Requires-Dist: psycopg2-binary>=2.9.9
|
|
20
|
+
Requires-Dist: pytest>=8.0.0 ; extra == 'all'
|
|
21
|
+
Requires-Dist: pytest>=8.0.0 ; extra == 'test'
|
|
22
|
+
Requires-Python: >=3.12
|
|
23
|
+
Project-URL: homepage, https://github.com/thepmsquare/square_database_structure
|
|
24
|
+
Provides-Extra: all
|
|
25
|
+
Provides-Extra: test
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# square_database_structure
|
|
29
|
+
|
|
30
|
+
> 📌 versioning: see [CHANGELOG.md](./CHANGELOG.md).
|
|
31
|
+
|
|
32
|
+
## about
|
|
33
|
+
|
|
34
|
+
python module to define postgresql database schemas using sqlalchemy.
|
|
35
|
+
|
|
36
|
+
## goals
|
|
37
|
+
|
|
38
|
+
- clear database → schema → table hierarchy
|
|
39
|
+
- reusable (template) across multiple projects
|
|
40
|
+
- single source of truth for schema and data
|
|
41
|
+
|
|
42
|
+
## installation
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install square_database_structure
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## usage
|
|
49
|
+
|
|
50
|
+
this module organizes database schemas in a standardized folder structure where each top-level folder represents a
|
|
51
|
+
database, and subfolders within it represent schemas. all mandatory components, such as `__init__.py` and tables.py,
|
|
52
|
+
data.py, stored_procedures_and_functions need to follow this structure.
|
|
53
|
+
|
|
54
|
+
### folder structure
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
square_database_structure/
|
|
58
|
+
├───main.py # global definition file (mandatory)
|
|
59
|
+
├───create_database.py # global database creation file (mandatory)
|
|
60
|
+
└───database1/ # each folder corresponds to a separate database
|
|
61
|
+
├───__init__.py # contains the global name for the database (mandatory)
|
|
62
|
+
└───schema1/ # each subfolder corresponds to a schema within the database
|
|
63
|
+
├───__init__.py # contains the global name for the schema (mandatory)
|
|
64
|
+
├───data.py # contains the data for insertion for the schema (mandatory)
|
|
65
|
+
├───enums.py # defines enums to be used in the schema (optional)
|
|
66
|
+
├───tables.py # defines tables of the schema (mandatory)
|
|
67
|
+
└───stored_procedures_and_functions/ # contains stored procedures and functions for the schema (mandatory)
|
|
68
|
+
├───__init__.py # contains logic to discover sql files (mandatory)
|
|
69
|
+
└───function1.sql # function or stored procedure sql file (optional)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- top-level folders: represent individual databases (e.g., database1).
|
|
73
|
+
- subfolders: represent schemas within each database (e.g., public, schema1).
|
|
74
|
+
- mandatory files:
|
|
75
|
+
- `__init__.py` (both at the database and schema level).
|
|
76
|
+
- tables.py within each schema.
|
|
77
|
+
- data.py within each schema.
|
|
78
|
+
- stored_procedures_and_functions package within each schema.
|
|
79
|
+
|
|
80
|
+
### defining database and schema names in `__init__.py`
|
|
81
|
+
|
|
82
|
+
each database and schema folder must contain an `__init__.py` file where the database and schema names are defined
|
|
83
|
+
as global variables.
|
|
84
|
+
|
|
85
|
+
#### example for database:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
# database1/__init__.py
|
|
89
|
+
|
|
90
|
+
global_string_database_name = "database1" # mandatory: database name
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### example for schema:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
# database1/schema1/__init__.py
|
|
97
|
+
|
|
98
|
+
global_string_schema_name = "schema1" # mandatory: schema name
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### defining tables in tables.py
|
|
102
|
+
|
|
103
|
+
each schema folder must contain a tables.py file where:
|
|
104
|
+
|
|
105
|
+
- you must declare a Base object tied to the schema.
|
|
106
|
+
- you can define table classes, extending the Base object.
|
|
107
|
+
|
|
108
|
+
#### example tables.py:
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
# tables.py
|
|
112
|
+
from sqlalchemy import Column, Integer, String, MetaData
|
|
113
|
+
from sqlalchemy.ext.declarative import declarative_base
|
|
114
|
+
from square_database_structure.square.public import global_string_schema_name
|
|
115
|
+
|
|
116
|
+
# 1. mandatory: declare Base with metadata pointing to the schema
|
|
117
|
+
|
|
118
|
+
Base = declarative_base(metadata=MetaData(schema=global_string_schema_name))
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# 2.optional: define table classes by extending Base
|
|
122
|
+
|
|
123
|
+
class App(Base):
|
|
124
|
+
__tablename__ = 'app'
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
id = Column(Integer, primary_key=True)
|
|
128
|
+
app_name = Column(String, nullable=False)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### defining data in data.py
|
|
132
|
+
|
|
133
|
+
- you must declare a data_to_insert list to store optional data that may be inserted into the schema's tables.
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
from square_database_structure.square.public.tables import App
|
|
137
|
+
|
|
138
|
+
# 1. mandatory: initialize a list for optional data insertion
|
|
139
|
+
data_to_insert = []
|
|
140
|
+
# optional: append data to be inserted into the table
|
|
141
|
+
data_to_insert.append(App(app_name="example_app"))
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### defining function or stored procedure in stored_procedures_and_functions package
|
|
145
|
+
|
|
146
|
+
- paste this logic in the `__init__.py` of this package to discover all sql files.
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
from pathlib import Path
|
|
150
|
+
|
|
151
|
+
directory = Path(__file__).parent
|
|
152
|
+
stored_procedures_and_functions = []
|
|
153
|
+
|
|
154
|
+
for file_path in directory.iterdir():
|
|
155
|
+
if file_path.is_file() and file_path.suffix == ".sql":
|
|
156
|
+
with file_path.open("r") as file:
|
|
157
|
+
content = file.read()
|
|
158
|
+
stored_procedures_and_functions.append(content)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
- you can keep raw sql files each containing ideally 1 stored procedure or function.
|
|
162
|
+
- the name of the file should ideally correspond to the function / procedure name.
|
|
163
|
+
- this raw sql should be compatible with postgres database.
|
|
164
|
+
|
|
165
|
+
```sql
|
|
166
|
+
CREATE OR REPLACE FUNCTION add_user(
|
|
167
|
+
p_username VARCHAR,
|
|
168
|
+
p_email VARCHAR
|
|
169
|
+
) RETURNS TEXT AS $$
|
|
170
|
+
BEGIN
|
|
171
|
+
-- Insert a new user into the users table
|
|
172
|
+
INSERT INTO users (username, email)
|
|
173
|
+
VALUES (p_username, p_email);
|
|
174
|
+
|
|
175
|
+
-- Return a success message
|
|
176
|
+
RETURN 'User added successfully!';
|
|
177
|
+
END;
|
|
178
|
+
$$ LANGUAGE plpgsql;
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### centralized definitions in main.py
|
|
183
|
+
|
|
184
|
+
the main.py file is mandatory and contains a global list that maps databases to schemas and their corresponding table
|
|
185
|
+
definitions. this list is manually created by the user (for now).
|
|
186
|
+
|
|
187
|
+
#### example main.py:
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
# main.py
|
|
191
|
+
|
|
192
|
+
from square_database_structure.square.public import global_string_schema_name as schema1_name
|
|
193
|
+
from square_database_structure.square.public.tables import Base as Schema1Base
|
|
194
|
+
from square_database_structure.square.public.data import data_to_insert as schema1_data
|
|
195
|
+
from square_database_structure.square.public.stored_procedures_and_functions import (
|
|
196
|
+
stored_procedures_and_functions as schema1_stored_procedures_and_functions)
|
|
197
|
+
from square_database_structure.square import global_string_database_name as database1_name
|
|
198
|
+
|
|
199
|
+
# global list that maps databases and schemas
|
|
200
|
+
|
|
201
|
+
global_list_create = [
|
|
202
|
+
{
|
|
203
|
+
"database": database1_name, # mandatory: database name
|
|
204
|
+
"schemas": [
|
|
205
|
+
{
|
|
206
|
+
"schema": schema1_name, # mandatory: schema name
|
|
207
|
+
"base": Schema1Base, # mandatory: base for this schema
|
|
208
|
+
"data_to_insert": schema1_data, # mandatory: data to insert (even if empty)
|
|
209
|
+
"stored_procedures_and_functions": schema1_stored_procedures_and_functions,
|
|
210
|
+
# mandatory: stored procedures and functions (even if empty)
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
}
|
|
214
|
+
]
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
this file centralizes the definition of each database and schema, including the associated Base and data_to_insert for
|
|
218
|
+
table definitions.
|
|
219
|
+
|
|
220
|
+
### creating tables
|
|
221
|
+
|
|
222
|
+
once you have defined your databases, schemas, and tables, you can create them in your PostgreSQL database by using the
|
|
223
|
+
`create_database_and_tables` function.
|
|
224
|
+
|
|
225
|
+
```python
|
|
226
|
+
from square_database_structure import create_database_and_tables
|
|
227
|
+
|
|
228
|
+
# define the database connection details
|
|
229
|
+
db_username = "your_username"
|
|
230
|
+
db_password = "your_password"
|
|
231
|
+
db_ip = "localhost"
|
|
232
|
+
db_port = 5432
|
|
233
|
+
|
|
234
|
+
# call the function to create the database and tables
|
|
235
|
+
create_database_and_tables(db_username, db_password, db_ip, db_port)
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## env
|
|
239
|
+
|
|
240
|
+
- python>=3.12.0
|
|
241
|
+
- postgresql >= 13
|
|
242
|
+
|
|
243
|
+
> feedback is appreciated. thank you!
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# square_database_structure
|
|
2
|
+
|
|
3
|
+
> 📌 versioning: see [CHANGELOG.md](./CHANGELOG.md).
|
|
4
|
+
|
|
5
|
+
## about
|
|
6
|
+
|
|
7
|
+
python module to define postgresql database schemas using sqlalchemy.
|
|
8
|
+
|
|
9
|
+
## goals
|
|
10
|
+
|
|
11
|
+
- clear database → schema → table hierarchy
|
|
12
|
+
- reusable (template) across multiple projects
|
|
13
|
+
- single source of truth for schema and data
|
|
14
|
+
|
|
15
|
+
## installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install square_database_structure
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## usage
|
|
22
|
+
|
|
23
|
+
this module organizes database schemas in a standardized folder structure where each top-level folder represents a
|
|
24
|
+
database, and subfolders within it represent schemas. all mandatory components, such as `__init__.py` and tables.py,
|
|
25
|
+
data.py, stored_procedures_and_functions need to follow this structure.
|
|
26
|
+
|
|
27
|
+
### folder structure
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
square_database_structure/
|
|
31
|
+
├───main.py # global definition file (mandatory)
|
|
32
|
+
├───create_database.py # global database creation file (mandatory)
|
|
33
|
+
└───database1/ # each folder corresponds to a separate database
|
|
34
|
+
├───__init__.py # contains the global name for the database (mandatory)
|
|
35
|
+
└───schema1/ # each subfolder corresponds to a schema within the database
|
|
36
|
+
├───__init__.py # contains the global name for the schema (mandatory)
|
|
37
|
+
├───data.py # contains the data for insertion for the schema (mandatory)
|
|
38
|
+
├───enums.py # defines enums to be used in the schema (optional)
|
|
39
|
+
├───tables.py # defines tables of the schema (mandatory)
|
|
40
|
+
└───stored_procedures_and_functions/ # contains stored procedures and functions for the schema (mandatory)
|
|
41
|
+
├───__init__.py # contains logic to discover sql files (mandatory)
|
|
42
|
+
└───function1.sql # function or stored procedure sql file (optional)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
- top-level folders: represent individual databases (e.g., database1).
|
|
46
|
+
- subfolders: represent schemas within each database (e.g., public, schema1).
|
|
47
|
+
- mandatory files:
|
|
48
|
+
- `__init__.py` (both at the database and schema level).
|
|
49
|
+
- tables.py within each schema.
|
|
50
|
+
- data.py within each schema.
|
|
51
|
+
- stored_procedures_and_functions package within each schema.
|
|
52
|
+
|
|
53
|
+
### defining database and schema names in `__init__.py`
|
|
54
|
+
|
|
55
|
+
each database and schema folder must contain an `__init__.py` file where the database and schema names are defined
|
|
56
|
+
as global variables.
|
|
57
|
+
|
|
58
|
+
#### example for database:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
# database1/__init__.py
|
|
62
|
+
|
|
63
|
+
global_string_database_name = "database1" # mandatory: database name
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
#### example for schema:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
# database1/schema1/__init__.py
|
|
70
|
+
|
|
71
|
+
global_string_schema_name = "schema1" # mandatory: schema name
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### defining tables in tables.py
|
|
75
|
+
|
|
76
|
+
each schema folder must contain a tables.py file where:
|
|
77
|
+
|
|
78
|
+
- you must declare a Base object tied to the schema.
|
|
79
|
+
- you can define table classes, extending the Base object.
|
|
80
|
+
|
|
81
|
+
#### example tables.py:
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
# tables.py
|
|
85
|
+
from sqlalchemy import Column, Integer, String, MetaData
|
|
86
|
+
from sqlalchemy.ext.declarative import declarative_base
|
|
87
|
+
from square_database_structure.square.public import global_string_schema_name
|
|
88
|
+
|
|
89
|
+
# 1. mandatory: declare Base with metadata pointing to the schema
|
|
90
|
+
|
|
91
|
+
Base = declarative_base(metadata=MetaData(schema=global_string_schema_name))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# 2.optional: define table classes by extending Base
|
|
95
|
+
|
|
96
|
+
class App(Base):
|
|
97
|
+
__tablename__ = 'app'
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
id = Column(Integer, primary_key=True)
|
|
101
|
+
app_name = Column(String, nullable=False)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### defining data in data.py
|
|
105
|
+
|
|
106
|
+
- you must declare a data_to_insert list to store optional data that may be inserted into the schema's tables.
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
from square_database_structure.square.public.tables import App
|
|
110
|
+
|
|
111
|
+
# 1. mandatory: initialize a list for optional data insertion
|
|
112
|
+
data_to_insert = []
|
|
113
|
+
# optional: append data to be inserted into the table
|
|
114
|
+
data_to_insert.append(App(app_name="example_app"))
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### defining function or stored procedure in stored_procedures_and_functions package
|
|
118
|
+
|
|
119
|
+
- paste this logic in the `__init__.py` of this package to discover all sql files.
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from pathlib import Path
|
|
123
|
+
|
|
124
|
+
directory = Path(__file__).parent
|
|
125
|
+
stored_procedures_and_functions = []
|
|
126
|
+
|
|
127
|
+
for file_path in directory.iterdir():
|
|
128
|
+
if file_path.is_file() and file_path.suffix == ".sql":
|
|
129
|
+
with file_path.open("r") as file:
|
|
130
|
+
content = file.read()
|
|
131
|
+
stored_procedures_and_functions.append(content)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
- you can keep raw sql files each containing ideally 1 stored procedure or function.
|
|
135
|
+
- the name of the file should ideally correspond to the function / procedure name.
|
|
136
|
+
- this raw sql should be compatible with postgres database.
|
|
137
|
+
|
|
138
|
+
```sql
|
|
139
|
+
CREATE OR REPLACE FUNCTION add_user(
|
|
140
|
+
p_username VARCHAR,
|
|
141
|
+
p_email VARCHAR
|
|
142
|
+
) RETURNS TEXT AS $$
|
|
143
|
+
BEGIN
|
|
144
|
+
-- Insert a new user into the users table
|
|
145
|
+
INSERT INTO users (username, email)
|
|
146
|
+
VALUES (p_username, p_email);
|
|
147
|
+
|
|
148
|
+
-- Return a success message
|
|
149
|
+
RETURN 'User added successfully!';
|
|
150
|
+
END;
|
|
151
|
+
$$ LANGUAGE plpgsql;
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### centralized definitions in main.py
|
|
156
|
+
|
|
157
|
+
the main.py file is mandatory and contains a global list that maps databases to schemas and their corresponding table
|
|
158
|
+
definitions. this list is manually created by the user (for now).
|
|
159
|
+
|
|
160
|
+
#### example main.py:
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
# main.py
|
|
164
|
+
|
|
165
|
+
from square_database_structure.square.public import global_string_schema_name as schema1_name
|
|
166
|
+
from square_database_structure.square.public.tables import Base as Schema1Base
|
|
167
|
+
from square_database_structure.square.public.data import data_to_insert as schema1_data
|
|
168
|
+
from square_database_structure.square.public.stored_procedures_and_functions import (
|
|
169
|
+
stored_procedures_and_functions as schema1_stored_procedures_and_functions)
|
|
170
|
+
from square_database_structure.square import global_string_database_name as database1_name
|
|
171
|
+
|
|
172
|
+
# global list that maps databases and schemas
|
|
173
|
+
|
|
174
|
+
global_list_create = [
|
|
175
|
+
{
|
|
176
|
+
"database": database1_name, # mandatory: database name
|
|
177
|
+
"schemas": [
|
|
178
|
+
{
|
|
179
|
+
"schema": schema1_name, # mandatory: schema name
|
|
180
|
+
"base": Schema1Base, # mandatory: base for this schema
|
|
181
|
+
"data_to_insert": schema1_data, # mandatory: data to insert (even if empty)
|
|
182
|
+
"stored_procedures_and_functions": schema1_stored_procedures_and_functions,
|
|
183
|
+
# mandatory: stored procedures and functions (even if empty)
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
}
|
|
187
|
+
]
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
this file centralizes the definition of each database and schema, including the associated Base and data_to_insert for
|
|
191
|
+
table definitions.
|
|
192
|
+
|
|
193
|
+
### creating tables
|
|
194
|
+
|
|
195
|
+
once you have defined your databases, schemas, and tables, you can create them in your PostgreSQL database by using the
|
|
196
|
+
`create_database_and_tables` function.
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
from square_database_structure import create_database_and_tables
|
|
200
|
+
|
|
201
|
+
# define the database connection details
|
|
202
|
+
db_username = "your_username"
|
|
203
|
+
db_password = "your_password"
|
|
204
|
+
db_ip = "localhost"
|
|
205
|
+
db_port = 5432
|
|
206
|
+
|
|
207
|
+
# call the function to create the database and tables
|
|
208
|
+
create_database_and_tables(db_username, db_password, db_ip, db_port)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## env
|
|
212
|
+
|
|
213
|
+
- python>=3.12.0
|
|
214
|
+
- postgresql >= 13
|
|
215
|
+
|
|
216
|
+
> feedback is appreciated. thank you!
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["uv-build"]
|
|
3
|
+
build-backend = "uv_build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "square_database_structure"
|
|
7
|
+
version = "2.8.1"
|
|
8
|
+
description = "database scheme for my personal server."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
readme-content-type = "text/markdown"
|
|
11
|
+
requires-python = ">=3.12"
|
|
12
|
+
license = { text = "GPLv3" }
|
|
13
|
+
authors = [
|
|
14
|
+
{ name = "Parth Mukesh Mangtani", email = "thepmsquare@gmail.com" },
|
|
15
|
+
]
|
|
16
|
+
urls = { homepage = "https://github.com/thepmsquare/square_database_structure" }
|
|
17
|
+
keywords = ["database", "sqlalchemy", "utilities"]
|
|
18
|
+
dependencies = [
|
|
19
|
+
"sqlalchemy>=2.0.23",
|
|
20
|
+
"psycopg2-binary>=2.9.9",
|
|
21
|
+
]
|
|
22
|
+
optional-dependencies = { all = ["pytest>=8.0.0"], test = ["pytest>=8.0.0"] }
|
|
23
|
+
classifiers = [
|
|
24
|
+
"Development Status :: 3 - Alpha",
|
|
25
|
+
"Intended Audience :: Developers",
|
|
26
|
+
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
|
|
27
|
+
"Operating System :: OS Independent",
|
|
28
|
+
"Programming Language :: Python :: 3",
|
|
29
|
+
"Programming Language :: Python :: 3.12",
|
|
30
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
31
|
+
"Topic :: Database",
|
|
32
|
+
"Topic :: Software Development :: Libraries :: Python Modules"
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[tool.uv.build-backend]
|
|
36
|
+
module-name = "square_database_structure"
|
|
37
|
+
module-root = ""
|
|
38
|
+
source-include = ["square_database_structure/**/stored_procedures_and_functions/*.sql"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from square_database_structure.create_database import create_database_and_tables
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
from psycopg2.errors import DuplicateDatabase
|
|
2
|
+
from sqlalchemy import create_engine, inspect, text
|
|
3
|
+
from sqlalchemy.orm import sessionmaker
|
|
4
|
+
|
|
5
|
+
from square_database_structure.main import global_list_create
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def create_database_and_tables(
|
|
9
|
+
db_username: str,
|
|
10
|
+
db_password: str,
|
|
11
|
+
db_ip: str,
|
|
12
|
+
db_port: int,
|
|
13
|
+
drop_if_exists: bool = False,
|
|
14
|
+
) -> None:
|
|
15
|
+
try:
|
|
16
|
+
local_list_create = global_list_create
|
|
17
|
+
|
|
18
|
+
for local_dict_database in local_list_create:
|
|
19
|
+
local_str_database_name = local_dict_database["database"]
|
|
20
|
+
local_str_postgres_url = (
|
|
21
|
+
f"postgresql://{db_username}:{db_password}@" f"{db_ip}:{str(db_port)}/"
|
|
22
|
+
)
|
|
23
|
+
postgres_engine = create_engine(local_str_postgres_url)
|
|
24
|
+
# Create database if not exists
|
|
25
|
+
try:
|
|
26
|
+
with postgres_engine.connect() as postgres_connection:
|
|
27
|
+
postgres_connection.execute(text("commit"))
|
|
28
|
+
postgres_connection.execute(
|
|
29
|
+
text(f"CREATE DATABASE {local_str_database_name}")
|
|
30
|
+
)
|
|
31
|
+
except Exception as e:
|
|
32
|
+
if isinstance(getattr(e, "orig"), DuplicateDatabase):
|
|
33
|
+
if drop_if_exists:
|
|
34
|
+
with postgres_engine.connect() as postgres_connection:
|
|
35
|
+
postgres_connection.execute(text("commit"))
|
|
36
|
+
postgres_connection.execute(
|
|
37
|
+
text(
|
|
38
|
+
f"DROP DATABASE {local_str_database_name} WITH (FORCE)"
|
|
39
|
+
)
|
|
40
|
+
)
|
|
41
|
+
postgres_connection.execute(
|
|
42
|
+
text(f"CREATE DATABASE {local_str_database_name}")
|
|
43
|
+
)
|
|
44
|
+
else:
|
|
45
|
+
raise
|
|
46
|
+
# ===========================================
|
|
47
|
+
local_str_database_url = (
|
|
48
|
+
f"postgresql://{db_username}:{db_password}@"
|
|
49
|
+
f"{db_ip}:{str(db_port)}/{local_str_database_name}"
|
|
50
|
+
)
|
|
51
|
+
database_engine = create_engine(local_str_database_url)
|
|
52
|
+
with database_engine.connect() as database_connection:
|
|
53
|
+
for local_dict_schema in local_dict_database["schemas"]:
|
|
54
|
+
local_str_schema_name = local_dict_schema["schema"]
|
|
55
|
+
# Create schema if not exists
|
|
56
|
+
if not database_engine.dialect.has_schema(
|
|
57
|
+
database_connection, local_str_schema_name
|
|
58
|
+
):
|
|
59
|
+
database_connection.execute(text("commit"))
|
|
60
|
+
database_connection.execute(
|
|
61
|
+
text(f"CREATE SCHEMA {local_str_schema_name}")
|
|
62
|
+
)
|
|
63
|
+
else:
|
|
64
|
+
pass
|
|
65
|
+
# ===========================================
|
|
66
|
+
database_connection.execute(
|
|
67
|
+
text(f"SET search_path TO {local_str_schema_name}")
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
inspector = inspect(database_engine)
|
|
71
|
+
existing_table_names = inspector.get_table_names(
|
|
72
|
+
schema=local_str_schema_name
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
base = local_dict_schema["base"]
|
|
76
|
+
# Create tables if not exists
|
|
77
|
+
base.metadata.create_all(database_engine)
|
|
78
|
+
# ===========================================
|
|
79
|
+
data_to_insert = local_dict_schema["data_to_insert"]
|
|
80
|
+
local_object_session = sessionmaker(bind=database_engine)
|
|
81
|
+
session = local_object_session()
|
|
82
|
+
filtered_data_to_insert = [
|
|
83
|
+
x
|
|
84
|
+
for x in data_to_insert
|
|
85
|
+
if x.__tablename__ not in existing_table_names
|
|
86
|
+
]
|
|
87
|
+
# insert data for newly created tables
|
|
88
|
+
try:
|
|
89
|
+
session.add_all(filtered_data_to_insert)
|
|
90
|
+
# ===========================================
|
|
91
|
+
session.commit()
|
|
92
|
+
session.close()
|
|
93
|
+
except Exception:
|
|
94
|
+
session.rollback()
|
|
95
|
+
session.close()
|
|
96
|
+
raise
|
|
97
|
+
# create stored procedures
|
|
98
|
+
stored_procedures_and_functions = local_dict_schema[
|
|
99
|
+
"stored_procedures_and_functions"
|
|
100
|
+
]
|
|
101
|
+
for (
|
|
102
|
+
stored_procedures_and_function
|
|
103
|
+
) in stored_procedures_and_functions:
|
|
104
|
+
database_connection.execute(
|
|
105
|
+
text(stored_procedures_and_function)
|
|
106
|
+
)
|
|
107
|
+
except Exception:
|
|
108
|
+
raise
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from square_database_structure.square import (
|
|
2
|
+
global_string_database_name as local_string_square_database_name,
|
|
3
|
+
)
|
|
4
|
+
from square_database_structure.square.authentication import (
|
|
5
|
+
global_string_schema_name as local_string_square_authentication_schema_name,
|
|
6
|
+
)
|
|
7
|
+
from square_database_structure.square.authentication.data import (
|
|
8
|
+
data_to_insert as local_list_square_authentication_data_to_insert,
|
|
9
|
+
)
|
|
10
|
+
from square_database_structure.square.authentication.stored_procedures_and_functions import (
|
|
11
|
+
stored_procedures_and_functions as local_list_square_authentication_stored_procedures_and_functions,
|
|
12
|
+
)
|
|
13
|
+
from square_database_structure.square.authentication.tables import (
|
|
14
|
+
Base as SquareAuthenticationBase,
|
|
15
|
+
)
|
|
16
|
+
from square_database_structure.square.email import (
|
|
17
|
+
global_string_schema_name as local_string_square_email_schema_name,
|
|
18
|
+
)
|
|
19
|
+
from square_database_structure.square.email.data import (
|
|
20
|
+
data_to_insert as local_list_square_email_data_to_insert,
|
|
21
|
+
)
|
|
22
|
+
from square_database_structure.square.email.stored_procedures_and_functions import (
|
|
23
|
+
stored_procedures_and_functions as local_list_square_email_stored_procedures_and_functions,
|
|
24
|
+
)
|
|
25
|
+
from square_database_structure.square.email.tables import (
|
|
26
|
+
Base as SquareEmailBase,
|
|
27
|
+
)
|
|
28
|
+
from square_database_structure.square.file_storage import (
|
|
29
|
+
global_string_schema_name as local_string_square_file_storage_schema_name,
|
|
30
|
+
)
|
|
31
|
+
from square_database_structure.square.file_storage.data import (
|
|
32
|
+
data_to_insert as local_list_square_file_storage_data_to_insert,
|
|
33
|
+
)
|
|
34
|
+
from square_database_structure.square.file_storage.stored_procedures_and_functions import (
|
|
35
|
+
stored_procedures_and_functions as local_list_square_file_storage_stored_procedures_and_functions,
|
|
36
|
+
)
|
|
37
|
+
from square_database_structure.square.file_storage.tables import (
|
|
38
|
+
Base as SquareFileStorageBase,
|
|
39
|
+
)
|
|
40
|
+
from square_database_structure.square.greeting import (
|
|
41
|
+
global_string_schema_name as local_string_square_greeting_schema_name,
|
|
42
|
+
)
|
|
43
|
+
from square_database_structure.square.greeting.data import (
|
|
44
|
+
data_to_insert as local_list_square_greeting_data_to_insert,
|
|
45
|
+
)
|
|
46
|
+
from square_database_structure.square.greeting.stored_procedures_and_functions import (
|
|
47
|
+
stored_procedures_and_functions as local_list_square_greeting_stored_procedures_and_functions,
|
|
48
|
+
)
|
|
49
|
+
from square_database_structure.square.greeting.tables import (
|
|
50
|
+
Base as SquareGreetingBase,
|
|
51
|
+
)
|
|
52
|
+
from square_database_structure.square.public import (
|
|
53
|
+
global_string_schema_name as local_string_square_public_schema_name,
|
|
54
|
+
)
|
|
55
|
+
from square_database_structure.square.public.data import (
|
|
56
|
+
data_to_insert as local_list_square_public_data_to_insert,
|
|
57
|
+
)
|
|
58
|
+
from square_database_structure.square.public.stored_procedures_and_functions import (
|
|
59
|
+
stored_procedures_and_functions as local_list_square_public_stored_procedures_and_functions,
|
|
60
|
+
)
|
|
61
|
+
from square_database_structure.square.public.tables import (
|
|
62
|
+
Base as SquarePublicBase,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
global_list_create = [
|
|
66
|
+
{
|
|
67
|
+
"database": local_string_square_database_name,
|
|
68
|
+
"schemas": [
|
|
69
|
+
{
|
|
70
|
+
"schema": local_string_square_public_schema_name,
|
|
71
|
+
"base": SquarePublicBase,
|
|
72
|
+
"data_to_insert": local_list_square_public_data_to_insert,
|
|
73
|
+
"stored_procedures_and_functions": local_list_square_public_stored_procedures_and_functions,
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"schema": local_string_square_file_storage_schema_name,
|
|
77
|
+
"base": SquareFileStorageBase,
|
|
78
|
+
"data_to_insert": local_list_square_file_storage_data_to_insert,
|
|
79
|
+
"stored_procedures_and_functions": local_list_square_file_storage_stored_procedures_and_functions,
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"schema": local_string_square_authentication_schema_name,
|
|
83
|
+
"base": SquareAuthenticationBase,
|
|
84
|
+
"data_to_insert": local_list_square_authentication_data_to_insert,
|
|
85
|
+
"stored_procedures_and_functions": local_list_square_authentication_stored_procedures_and_functions,
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"schema": local_string_square_greeting_schema_name,
|
|
89
|
+
"base": SquareGreetingBase,
|
|
90
|
+
"data_to_insert": local_list_square_greeting_data_to_insert,
|
|
91
|
+
"stored_procedures_and_functions": local_list_square_greeting_stored_procedures_and_functions,
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"schema": local_string_square_email_schema_name,
|
|
95
|
+
"base": SquareEmailBase,
|
|
96
|
+
"data_to_insert": local_list_square_email_data_to_insert,
|
|
97
|
+
"stored_procedures_and_functions": local_list_square_email_stored_procedures_and_functions,
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
}
|
|
101
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
global_string_database_name = "square"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
global_string_schema_name = "authentication"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
data_to_insert = []
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class RecoveryMethodEnum(Enum):
|
|
5
|
+
EMAIL = "EMAIL"
|
|
6
|
+
BACKUP_CODE = "BACKUP_CODE"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class VerificationCodeTypeEnum(Enum):
|
|
10
|
+
EMAIL_VERIFICATION = "EMAIL_VERIFICATION"
|
|
11
|
+
EMAIL_RECOVERY = "EMAIL_RECOVERY"
|
|
12
|
+
BACKUP_CODE_RECOVERY = "BACKUP_CODE_RECOVERY"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class AuthProviderEnum(Enum):
|
|
16
|
+
SELF = "SELF"
|
|
17
|
+
GOOGLE = "GOOGLE"
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
directory = Path(__file__).parent
|
|
4
|
+
stored_procedures_and_functions = []
|
|
5
|
+
|
|
6
|
+
for file_path in directory.iterdir():
|
|
7
|
+
if file_path.is_file() and file_path.suffix == ".sql":
|
|
8
|
+
with file_path.open("r") as file:
|
|
9
|
+
content = file.read()
|
|
10
|
+
stored_procedures_and_functions.append(content)
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
from sqlalchemy import (
|
|
2
|
+
Column,
|
|
3
|
+
Integer,
|
|
4
|
+
MetaData,
|
|
5
|
+
DateTime,
|
|
6
|
+
text,
|
|
7
|
+
String,
|
|
8
|
+
ForeignKey,
|
|
9
|
+
Enum,
|
|
10
|
+
UniqueConstraint,
|
|
11
|
+
func,
|
|
12
|
+
)
|
|
13
|
+
from sqlalchemy.dialects.postgresql import UUID
|
|
14
|
+
from sqlalchemy.orm import declarative_base
|
|
15
|
+
|
|
16
|
+
from square_database_structure.square.authentication import global_string_schema_name
|
|
17
|
+
from square_database_structure.square.authentication.enums import (
|
|
18
|
+
RecoveryMethodEnum,
|
|
19
|
+
VerificationCodeTypeEnum,
|
|
20
|
+
AuthProviderEnum,
|
|
21
|
+
)
|
|
22
|
+
from square_database_structure.square.file_storage.tables import File
|
|
23
|
+
from square_database_structure.square.public.tables import App
|
|
24
|
+
|
|
25
|
+
Base = declarative_base(metadata=MetaData(schema=global_string_schema_name))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class User(Base):
|
|
29
|
+
__tablename__ = "user"
|
|
30
|
+
|
|
31
|
+
user_id = Column(
|
|
32
|
+
UUID,
|
|
33
|
+
primary_key=True,
|
|
34
|
+
nullable=False,
|
|
35
|
+
unique=True,
|
|
36
|
+
server_default=text("gen_random_uuid()"),
|
|
37
|
+
)
|
|
38
|
+
user_username = Column(String, nullable=False, unique=True, index=True)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class UserAuthProvider(Base):
|
|
42
|
+
__tablename__ = "user_auth_provider"
|
|
43
|
+
|
|
44
|
+
user_auth_provider_id = Column(
|
|
45
|
+
Integer, primary_key=True, nullable=False, unique=True, autoincrement=True
|
|
46
|
+
)
|
|
47
|
+
user_id = Column(
|
|
48
|
+
UUID,
|
|
49
|
+
ForeignKey(User.user_id, ondelete="CASCADE", onupdate="CASCADE"),
|
|
50
|
+
nullable=False,
|
|
51
|
+
)
|
|
52
|
+
auth_provider = Column(
|
|
53
|
+
Enum(AuthProviderEnum, schema=global_string_schema_name),
|
|
54
|
+
nullable=False,
|
|
55
|
+
)
|
|
56
|
+
auth_provider_user_id = Column(String, nullable=True)
|
|
57
|
+
__table_args__ = (
|
|
58
|
+
UniqueConstraint(
|
|
59
|
+
"user_id",
|
|
60
|
+
"auth_provider",
|
|
61
|
+
name="uq_user_id_auth_provider",
|
|
62
|
+
),
|
|
63
|
+
UniqueConstraint(
|
|
64
|
+
"auth_provider",
|
|
65
|
+
"auth_provider_user_id",
|
|
66
|
+
name="uq_auth_provider_auth_provider_user_id",
|
|
67
|
+
),
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class UserCredential(Base):
|
|
72
|
+
__tablename__ = "user_credential"
|
|
73
|
+
|
|
74
|
+
user_credential_id = Column(
|
|
75
|
+
Integer, primary_key=True, nullable=False, unique=True, autoincrement=True
|
|
76
|
+
)
|
|
77
|
+
user_id = Column(
|
|
78
|
+
UUID,
|
|
79
|
+
ForeignKey(User.user_id, ondelete="CASCADE", onupdate="CASCADE"),
|
|
80
|
+
nullable=False,
|
|
81
|
+
unique=True,
|
|
82
|
+
)
|
|
83
|
+
user_credential_hashed_password = Column(String, nullable=False)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class UserApp(Base):
|
|
87
|
+
__tablename__ = "user_app"
|
|
88
|
+
|
|
89
|
+
user_id = Column(
|
|
90
|
+
UUID,
|
|
91
|
+
ForeignKey(User.user_id, ondelete="CASCADE", onupdate="CASCADE"),
|
|
92
|
+
nullable=False,
|
|
93
|
+
primary_key=True,
|
|
94
|
+
)
|
|
95
|
+
app_id = Column(
|
|
96
|
+
Integer,
|
|
97
|
+
ForeignKey(App.app_id, ondelete="CASCADE", onupdate="CASCADE"),
|
|
98
|
+
nullable=False,
|
|
99
|
+
primary_key=True,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class UserSession(Base):
|
|
104
|
+
__tablename__ = "user_session"
|
|
105
|
+
|
|
106
|
+
user_session_id = Column(
|
|
107
|
+
Integer, primary_key=True, unique=True, nullable=False, autoincrement=True
|
|
108
|
+
)
|
|
109
|
+
user_id = Column(
|
|
110
|
+
UUID,
|
|
111
|
+
ForeignKey(User.user_id, ondelete="CASCADE", onupdate="CASCADE"),
|
|
112
|
+
nullable=False,
|
|
113
|
+
)
|
|
114
|
+
app_id = Column(
|
|
115
|
+
Integer,
|
|
116
|
+
ForeignKey(App.app_id, ondelete="CASCADE", onupdate="CASCADE"),
|
|
117
|
+
nullable=False,
|
|
118
|
+
)
|
|
119
|
+
user_session_refresh_token = Column(
|
|
120
|
+
String,
|
|
121
|
+
nullable=False,
|
|
122
|
+
unique=True,
|
|
123
|
+
)
|
|
124
|
+
user_session_expiry_time = Column(DateTime(timezone=True), nullable=False)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class UserProfile(Base):
|
|
128
|
+
__tablename__ = "user_profile"
|
|
129
|
+
|
|
130
|
+
user_profile_id = Column(
|
|
131
|
+
Integer, primary_key=True, unique=True, nullable=False, autoincrement=True
|
|
132
|
+
)
|
|
133
|
+
user_id = Column(
|
|
134
|
+
UUID,
|
|
135
|
+
ForeignKey(User.user_id, ondelete="CASCADE", onupdate="CASCADE"),
|
|
136
|
+
nullable=False,
|
|
137
|
+
unique=True,
|
|
138
|
+
)
|
|
139
|
+
user_profile_photo_storage_token = Column(
|
|
140
|
+
String,
|
|
141
|
+
ForeignKey(File.file_storage_token, ondelete="RESTRICT", onupdate="CASCADE"),
|
|
142
|
+
nullable=True,
|
|
143
|
+
unique=True,
|
|
144
|
+
default=None,
|
|
145
|
+
)
|
|
146
|
+
user_profile_email = Column(
|
|
147
|
+
String,
|
|
148
|
+
nullable=True,
|
|
149
|
+
unique=True,
|
|
150
|
+
default=None,
|
|
151
|
+
)
|
|
152
|
+
user_profile_email_verified = Column(
|
|
153
|
+
DateTime(timezone=True),
|
|
154
|
+
nullable=True,
|
|
155
|
+
default=None,
|
|
156
|
+
)
|
|
157
|
+
user_profile_phone_number_country_code = Column(
|
|
158
|
+
String,
|
|
159
|
+
nullable=True,
|
|
160
|
+
default=None,
|
|
161
|
+
)
|
|
162
|
+
user_profile_phone_number = Column(
|
|
163
|
+
String,
|
|
164
|
+
nullable=True,
|
|
165
|
+
default=None,
|
|
166
|
+
)
|
|
167
|
+
user_profile_first_name = Column(
|
|
168
|
+
String,
|
|
169
|
+
nullable=True,
|
|
170
|
+
default=None,
|
|
171
|
+
)
|
|
172
|
+
user_profile_last_name = Column(
|
|
173
|
+
String,
|
|
174
|
+
nullable=True,
|
|
175
|
+
default=None,
|
|
176
|
+
)
|
|
177
|
+
__table_args__ = (
|
|
178
|
+
UniqueConstraint(
|
|
179
|
+
"user_profile_phone_number_country_code",
|
|
180
|
+
"user_profile_phone_number",
|
|
181
|
+
name="uq_user_profile_phone_number",
|
|
182
|
+
),
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class UserRecoveryMethod(Base):
|
|
187
|
+
__tablename__ = "user_recovery_method"
|
|
188
|
+
|
|
189
|
+
user_recovery_method_id = Column(
|
|
190
|
+
Integer, primary_key=True, unique=True, nullable=False, autoincrement=True
|
|
191
|
+
)
|
|
192
|
+
user_id = Column(
|
|
193
|
+
UUID,
|
|
194
|
+
ForeignKey(User.user_id, ondelete="CASCADE", onupdate="CASCADE"),
|
|
195
|
+
nullable=False,
|
|
196
|
+
)
|
|
197
|
+
user_recovery_method_name = Column(
|
|
198
|
+
Enum(RecoveryMethodEnum, schema=global_string_schema_name),
|
|
199
|
+
nullable=False,
|
|
200
|
+
)
|
|
201
|
+
__table_args__ = (
|
|
202
|
+
UniqueConstraint(
|
|
203
|
+
"user_id",
|
|
204
|
+
"user_recovery_method_name",
|
|
205
|
+
name="uq_user_id_user_recovery_method",
|
|
206
|
+
),
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
class UserVerificationCode(Base):
|
|
211
|
+
__tablename__ = "user_verification_code"
|
|
212
|
+
|
|
213
|
+
user_verification_code_id = Column(
|
|
214
|
+
Integer, primary_key=True, unique=True, nullable=False, autoincrement=True
|
|
215
|
+
)
|
|
216
|
+
user_id = Column(
|
|
217
|
+
UUID,
|
|
218
|
+
ForeignKey(User.user_id, ondelete="CASCADE", onupdate="CASCADE"),
|
|
219
|
+
nullable=False,
|
|
220
|
+
)
|
|
221
|
+
user_verification_code_type = Column(
|
|
222
|
+
Enum(VerificationCodeTypeEnum, schema=global_string_schema_name),
|
|
223
|
+
nullable=False,
|
|
224
|
+
)
|
|
225
|
+
user_verification_code_hash = Column(
|
|
226
|
+
String,
|
|
227
|
+
unique=True,
|
|
228
|
+
nullable=False,
|
|
229
|
+
)
|
|
230
|
+
user_verification_code_created_at = Column(
|
|
231
|
+
DateTime(timezone=True),
|
|
232
|
+
nullable=False,
|
|
233
|
+
server_default=func.now(),
|
|
234
|
+
)
|
|
235
|
+
user_verification_code_expires_at = Column(
|
|
236
|
+
DateTime(timezone=True),
|
|
237
|
+
nullable=True,
|
|
238
|
+
)
|
|
239
|
+
user_verification_code_used_at = Column(
|
|
240
|
+
DateTime(timezone=True),
|
|
241
|
+
nullable=True,
|
|
242
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
global_string_schema_name = "email"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
data_to_insert = []
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
directory = Path(__file__).parent
|
|
4
|
+
stored_procedures_and_functions = []
|
|
5
|
+
|
|
6
|
+
for file_path in directory.iterdir():
|
|
7
|
+
if file_path.is_file() and file_path.suffix == ".sql":
|
|
8
|
+
with file_path.open("r") as file:
|
|
9
|
+
content = file.read()
|
|
10
|
+
stored_procedures_and_functions.append(content)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from sqlalchemy import (
|
|
2
|
+
Column,
|
|
3
|
+
Integer,
|
|
4
|
+
MetaData,
|
|
5
|
+
DateTime,
|
|
6
|
+
String,
|
|
7
|
+
ForeignKey,
|
|
8
|
+
Enum,
|
|
9
|
+
func,
|
|
10
|
+
)
|
|
11
|
+
from sqlalchemy.dialects.postgresql import UUID
|
|
12
|
+
from sqlalchemy.orm import declarative_base
|
|
13
|
+
|
|
14
|
+
from square_database_structure.square.authentication.tables import User
|
|
15
|
+
from square_database_structure.square.email import global_string_schema_name
|
|
16
|
+
from square_database_structure.square.email.enums import EmailTypeEnum, EmailStatusEnum
|
|
17
|
+
|
|
18
|
+
Base = declarative_base(metadata=MetaData(schema=global_string_schema_name))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class EmailLog(Base):
|
|
22
|
+
__tablename__ = "email_log"
|
|
23
|
+
|
|
24
|
+
email_log_id = Column(
|
|
25
|
+
Integer, primary_key=True, unique=True, nullable=False, autoincrement=True
|
|
26
|
+
)
|
|
27
|
+
user_id = Column(
|
|
28
|
+
UUID,
|
|
29
|
+
ForeignKey(User.user_id, ondelete="SET NULL", onupdate="CASCADE"),
|
|
30
|
+
nullable=True,
|
|
31
|
+
index=True,
|
|
32
|
+
)
|
|
33
|
+
recipient_email = Column(
|
|
34
|
+
String,
|
|
35
|
+
nullable=False,
|
|
36
|
+
index=True,
|
|
37
|
+
)
|
|
38
|
+
email_type = Column(
|
|
39
|
+
Enum(EmailTypeEnum, schema=global_string_schema_name),
|
|
40
|
+
nullable=False,
|
|
41
|
+
)
|
|
42
|
+
sent_at = Column(
|
|
43
|
+
DateTime(timezone=True),
|
|
44
|
+
nullable=False,
|
|
45
|
+
server_default=func.now(),
|
|
46
|
+
)
|
|
47
|
+
status = Column(
|
|
48
|
+
Enum(EmailStatusEnum, schema=global_string_schema_name),
|
|
49
|
+
nullable=False,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
third_party_message_id = Column(
|
|
53
|
+
String,
|
|
54
|
+
nullable=True,
|
|
55
|
+
unique=True,
|
|
56
|
+
index=True,
|
|
57
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
global_string_schema_name = "file_storage"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
data_to_insert = []
|
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
directory = Path(__file__).parent
|
|
4
|
+
stored_procedures_and_functions = []
|
|
5
|
+
|
|
6
|
+
for file_path in directory.iterdir():
|
|
7
|
+
if file_path.is_file() and file_path.suffix == ".sql":
|
|
8
|
+
with file_path.open("r") as file:
|
|
9
|
+
content = file.read()
|
|
10
|
+
stored_procedures_and_functions.append(content)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from sqlalchemy import (
|
|
2
|
+
Column,
|
|
3
|
+
DateTime,
|
|
4
|
+
Integer,
|
|
5
|
+
String,
|
|
6
|
+
MetaData,
|
|
7
|
+
ForeignKey,
|
|
8
|
+
)
|
|
9
|
+
from sqlalchemy.orm import declarative_base
|
|
10
|
+
from sqlalchemy.sql import func
|
|
11
|
+
|
|
12
|
+
from square_database_structure.square.file_storage import global_string_schema_name
|
|
13
|
+
from square_database_structure.square.public.tables import App
|
|
14
|
+
|
|
15
|
+
Base = declarative_base(metadata=MetaData(schema=global_string_schema_name))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class File(Base):
|
|
19
|
+
__tablename__ = "file"
|
|
20
|
+
|
|
21
|
+
file_id = Column(Integer, autoincrement=True, primary_key=True, index=True)
|
|
22
|
+
file_name_with_extension = Column(String, nullable=False)
|
|
23
|
+
file_content_type = Column(String, nullable=False, index=True)
|
|
24
|
+
file_date_created = Column(
|
|
25
|
+
DateTime(timezone=True), server_default=func.now(), nullable=False
|
|
26
|
+
)
|
|
27
|
+
file_last_modified = Column(
|
|
28
|
+
DateTime(timezone=True),
|
|
29
|
+
server_default=func.now(),
|
|
30
|
+
onupdate=func.now(),
|
|
31
|
+
nullable=False,
|
|
32
|
+
)
|
|
33
|
+
file_system_file_name_with_extension = Column(String, nullable=False)
|
|
34
|
+
file_system_relative_path = Column(String, server_default="", nullable=False)
|
|
35
|
+
file_storage_token = Column(String, nullable=False, unique=True, index=True)
|
|
36
|
+
app_id = Column(
|
|
37
|
+
Integer,
|
|
38
|
+
ForeignKey(App.app_id, ondelete="CASCADE", onupdate="CASCADE"),
|
|
39
|
+
nullable=True,
|
|
40
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
global_string_schema_name = "greeting"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
data_to_insert = []
|
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
directory = Path(__file__).parent
|
|
4
|
+
stored_procedures_and_functions = []
|
|
5
|
+
|
|
6
|
+
for file_path in directory.iterdir():
|
|
7
|
+
if file_path.is_file() and file_path.suffix == ".sql":
|
|
8
|
+
with file_path.open("r") as file:
|
|
9
|
+
content = file.read()
|
|
10
|
+
stored_procedures_and_functions.append(content)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from sqlalchemy import (
|
|
2
|
+
MetaData,
|
|
3
|
+
Column,
|
|
4
|
+
Integer,
|
|
5
|
+
String,
|
|
6
|
+
Boolean,
|
|
7
|
+
ForeignKey,
|
|
8
|
+
DateTime,
|
|
9
|
+
func,
|
|
10
|
+
)
|
|
11
|
+
from sqlalchemy.dialects.postgresql import UUID
|
|
12
|
+
from sqlalchemy.orm import declarative_base
|
|
13
|
+
|
|
14
|
+
from square_database_structure.square.authentication.tables import User
|
|
15
|
+
from square_database_structure.square.greeting import global_string_schema_name
|
|
16
|
+
|
|
17
|
+
Base = declarative_base(metadata=MetaData(schema=global_string_schema_name))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Greeting(Base):
|
|
21
|
+
__tablename__ = "greeting"
|
|
22
|
+
|
|
23
|
+
greeting_id = Column(
|
|
24
|
+
Integer, primary_key=True, nullable=False, unique=True, autoincrement=True
|
|
25
|
+
)
|
|
26
|
+
greeting_is_anonymous = Column(Boolean, nullable=False)
|
|
27
|
+
greeting_anonymous_sender_name = Column(String)
|
|
28
|
+
user_id = Column(
|
|
29
|
+
UUID,
|
|
30
|
+
ForeignKey(User.user_id, ondelete="CASCADE", onupdate="CASCADE"),
|
|
31
|
+
)
|
|
32
|
+
greeting_text = Column(String)
|
|
33
|
+
greeting_datetime = Column(
|
|
34
|
+
DateTime(timezone=True), server_default=func.now(), nullable=False
|
|
35
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
global_string_schema_name = "public"
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
from square_database_structure.square.public.tables import App
|
|
2
|
+
|
|
3
|
+
data_to_insert = []
|
|
4
|
+
data_to_insert.append(App(app_name="test"))
|
|
5
|
+
data_to_insert.append(App(app_name="square_admin"))
|
|
6
|
+
data_to_insert.append(App(app_name="ttthree"))
|
|
7
|
+
data_to_insert.append(App(app_name="square_wallet"))
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
directory = Path(__file__).parent
|
|
4
|
+
stored_procedures_and_functions = []
|
|
5
|
+
|
|
6
|
+
for file_path in directory.iterdir():
|
|
7
|
+
if file_path.is_file() and file_path.suffix == ".sql":
|
|
8
|
+
with file_path.open("r") as file:
|
|
9
|
+
content = file.read()
|
|
10
|
+
stored_procedures_and_functions.append(content)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
CREATE OR REPLACE FUNCTION get_test_text(input_test_id INTEGER)
|
|
2
|
+
RETURNS TEXT AS $$
|
|
3
|
+
DECLARE
|
|
4
|
+
test_text TEXT;
|
|
5
|
+
BEGIN
|
|
6
|
+
SELECT t.test_text INTO test_text
|
|
7
|
+
FROM test AS t
|
|
8
|
+
WHERE t.test_id = input_test_id;
|
|
9
|
+
|
|
10
|
+
RETURN test_text;
|
|
11
|
+
END;
|
|
12
|
+
$$ LANGUAGE plpgsql;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from sqlalchemy import (
|
|
2
|
+
Column,
|
|
3
|
+
Integer,
|
|
4
|
+
String,
|
|
5
|
+
DateTime,
|
|
6
|
+
Boolean,
|
|
7
|
+
Float,
|
|
8
|
+
JSON,
|
|
9
|
+
LargeBinary,
|
|
10
|
+
Enum,
|
|
11
|
+
MetaData,
|
|
12
|
+
)
|
|
13
|
+
from sqlalchemy.orm import declarative_base
|
|
14
|
+
|
|
15
|
+
from square_database_structure.square.public import global_string_schema_name
|
|
16
|
+
from square_database_structure.square.public.enums import TestEnumEnum
|
|
17
|
+
|
|
18
|
+
Base = declarative_base(metadata=MetaData(schema=global_string_schema_name))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Test(Base):
|
|
22
|
+
__tablename__ = "test"
|
|
23
|
+
|
|
24
|
+
test_id = Column(
|
|
25
|
+
Integer, primary_key=True, nullable=False, unique=True, autoincrement=True
|
|
26
|
+
)
|
|
27
|
+
test_text = Column(String, nullable=True, unique=True)
|
|
28
|
+
test_datetime = Column(DateTime, nullable=True)
|
|
29
|
+
test_bool = Column(Boolean, nullable=True)
|
|
30
|
+
test_enum_enum = Column(Enum(TestEnumEnum), nullable=True)
|
|
31
|
+
test_float = Column(Float, nullable=True)
|
|
32
|
+
test_json = Column(JSON, nullable=True)
|
|
33
|
+
test_blob = Column(LargeBinary, nullable=True)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class App(Base):
|
|
37
|
+
__tablename__ = "app"
|
|
38
|
+
|
|
39
|
+
app_id = Column(
|
|
40
|
+
Integer, primary_key=True, nullable=False, unique=True, autoincrement=True
|
|
41
|
+
)
|
|
42
|
+
app_name = Column(String, nullable=False, unique=True)
|