db-attribute 2.1__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.
@@ -0,0 +1,176 @@
1
+ import db_attribute.db_types as db_types
2
+ import db_attribute.db_class as db_class
3
+ import db_attribute.db_work as db_work
4
+ import db_attribute.connector as connector
5
+ import db_attribute
6
+
7
+ class ConditionCore:
8
+ def __gt__(self, other):
9
+ return Condition(self.cls, self, other, '>')
10
+ def __ge__(self, other):
11
+ return Condition(self.cls, self, other, '>=')
12
+ def __lt__(self, other):
13
+ return Condition(self.cls, self, other, '<')
14
+ def __le__(self, other):
15
+ return Condition(self.cls, self, other, '<=')
16
+ def __eq__(self, other):
17
+ return Condition(self.cls, self, other, '=')
18
+ def __ne__(self, other):
19
+ return Condition(self.cls, self, other, '!=')
20
+ #def _like(self, other):
21
+ # return Condition(self.cls, self, other, 'Like')
22
+ def __add__(self, other):
23
+ return Condition(self.cls, self, other, '+', lambda a, b: a + b)
24
+ def __mul__(self, other):
25
+ return Condition(self.cls, self, other, '*', lambda a, b: a * b)
26
+ def __sub__(self, other):
27
+ return Condition(self.cls, self, other, '-', lambda a, b: a - b)
28
+ def __truediv__(self, other):
29
+ return Condition(self.cls, self, other, '/', lambda a, b: a / b)
30
+ def __mod__(self, other):
31
+ return Condition(self.cls, self, other, '%', lambda a, b: a % b)
32
+ def __lshift__(self, other):
33
+ return Condition(self.cls, self, other, '<<', lambda a, b: a << b)
34
+ def __rshift__(self, other):
35
+ return Condition(self.cls, self, other, '>>', lambda a, b: a >> b)
36
+ def __and__(self, other):
37
+ return Condition(self.cls, self, other, 'and', lambda a, b: a & b)
38
+ def __or__(self, other):
39
+ return Condition(self.cls, self, other, 'or', lambda a, b: a | b)
40
+ def __xor__(self, other):
41
+ return Condition(self.cls, self, other, '^', lambda a, b: a ^ b)
42
+
43
+
44
+ class AttributeObj(ConditionCore):
45
+ def __init__(self, cls, attr):
46
+ self.cls = cls
47
+ self.attr = attr
48
+
49
+ def _get_condition_repr(self):
50
+ field = self.cls.__db_fields__[self.attr]
51
+ default = field.get_default()
52
+ python_type = field.python_type
53
+ table_name = db_work.get_table_name(self.cls.__name__, self.attr)
54
+ sql_name = self.cls.__dbworkobj__.connobj.sql_name
55
+ scr_table_name = db_work.screening(table_name, sql_name)
56
+ scr_data = db_work.screening('data', sql_name)
57
+ if default is db_types.NotSet or default is db_types.MISSING:
58
+ return f'{scr_table_name}.{scr_data}'
59
+ temp = db_work.convert_attribute_value_to_mysql_value(default, python_type)
60
+ if temp['status_code'] != 200:
61
+ raise Exception(connector.status_cod[temp['status_code']])
62
+ sql_default = temp["data"]
63
+ return f'COALESCE({scr_table_name}.{scr_data}, {sql_default})'
64
+
65
+ def __repr__(self):
66
+ return f'{self.cls.__name__}.{self.attr}'
67
+
68
+
69
+ class Condition(ConditionCore):
70
+ def __init__(self, cls, left, right, operator:str, lambda_operator=None):
71
+ self.cls = cls
72
+ self.left = left
73
+ self.right = right
74
+ self.operator = operator
75
+ if lambda_operator:
76
+ self.lambda_operator = lambda_operator
77
+
78
+ def found(self):
79
+ temp = self.cls.__dbworkobj__.found_ids_by_condition(class_name=self.cls.__name__, condition=self._get_condition_repr())
80
+ if temp['status_code'] != 200:
81
+ return db_types.Ids()
82
+ return db_types.Ids(temp['data'])
83
+
84
+ def get_value(self, ID):
85
+ left = self.left.get_value(ID) if isinstance(self.left, ConditionCore) else self.left
86
+ right = self.right.get_value(ID) if isinstance(self.right, ConditionCore) else self.right
87
+ return self.lambda_operator(left, right)
88
+
89
+ def _get_condition_repr(self):
90
+ temp = db_work.convert_attribute_value_to_mysql_value(self.left, type(self.left))
91
+ left = temp['data']
92
+ temp = db_work.convert_attribute_value_to_mysql_value(self.right, type(self.right))
93
+ right = temp['data']
94
+ return f'({left} {self.operator} {right})'
95
+
96
+ def __repr__(self):
97
+ return f'({self.left} {self.operator} {self.right})'
98
+
99
+
100
+ class DbAttributeDiscriptor:
101
+ def __init__(self, owner=None, name:str=None):
102
+ self.public_name = name
103
+ self.private_name = name if name is None else '_' + name
104
+ self.cls = owner
105
+ self.field = None if self.cls is None else self.cls.__db_fields__[name]
106
+
107
+ def __set_name__(self, owner, name):
108
+ self.public_name = name
109
+ self.private_name = '_' + name
110
+ self.cls = owner
111
+ self.field = self.cls.__db_fields__[name]
112
+
113
+ def __get__(self, this, objtype=None):
114
+ if this is None:
115
+ return AttributeObj(self.cls, self.public_name)
116
+ if self.private_name in object.__getattribute__(this, '__dict__'):
117
+ return object.__getattribute__(this, self.private_name)
118
+ return self.get_attr_from_db(this)
119
+
120
+ def __set__(self, this, value):
121
+ if value is db_types.NotSet:
122
+ return
123
+ if self.private_name in object.__getattribute__(this, '__dict__'):
124
+ object.__setattr__(this, self.private_name, value)
125
+ return
126
+ self.dump_attr_to_db(this, value)
127
+
128
+ def __delete__(self, this):
129
+ if self.private_name in object.__getattribute__(this, '__dict__'):
130
+ object.__delattr__(this, self.private_name)
131
+ self.del_attr_from_db(this)
132
+
133
+ def __repr__(self):
134
+ return f'{self.cls}.{self.public_name}'
135
+
136
+ def get_default_value(self):
137
+ if self.field is db_types.NotSet or (self.field.default is db_types.MISSING and self.field.default_factory is db_types.MISSING): return db_types.NotSet
138
+ return self.field.get_default()
139
+
140
+ def dump_attr_to_db(self, this, value, cheak_exists_value=True, update_value=False):
141
+ attribute_type = self.cls.__db_fields__[self.public_name].python_type
142
+ obj = db_class.cheaker.create_db_class(value, attribute_type=attribute_type, _obj_dbattribute=this)
143
+ if db_work.get_table_name(self.cls.__name__, self.public_name) not in self.cls.__dbworkobj__.tables:
144
+ self.cls.__dbworkobj__.create_attribute_table(class_name=self.cls.__name__, attribute_name=self.public_name, attribute_type=attribute_type)
145
+ cheak_exists_value = False
146
+ ID = object.__getattribute__(this, 'id')
147
+ self.cls.__dbworkobj__.add_attribute_value(class_name=self.cls.__name__, attribute_name=self.public_name, ID=ID, data=obj, attribute_type=attribute_type)
148
+
149
+ def get_attr_from_db(self, this):
150
+ ID = object.__getattribute__(this, 'id')
151
+ temp_data = object.__getattribute__(self.cls, '__dbworkobj__').get_attribute_value(class_name=self.cls.__name__, attribute_name=self.public_name, ID=ID, _obj_dbattribute=this)
152
+ if temp_data['status_code'] == 302: #table is not create
153
+ object.__getattribute__(self.cls, '__dbworkobj__').create_attribute_table(class_name=self.cls.__name__, attribute_name=self.public_name, _cls_dbattribute=self.cls)
154
+ temp_data['status_code'] = 304
155
+ if temp_data['status_code'] == 304: #attr is not found
156
+ value = self.get_default_value()
157
+ if value is db_types.NotSet:
158
+ raise Exception(connector.status_cod[305]['eng'])
159
+ self.__set__(this, value)
160
+ return value
161
+ if temp_data['status_code'] != 200:
162
+ return None
163
+ return temp_data['data']
164
+
165
+ def dump_attr(self, this, cheak_exists=True):
166
+ if cheak_exists and (not hasattr(this, self.private_name)):
167
+ return
168
+ self.dump_attr_to_db(this, getattr(this, self.private_name))
169
+
170
+ def del_attr_from_db(self, this):
171
+ ID = object.__getattribute__(this, 'id')
172
+ return object.__getattribute__(self.cls, '__dbworkobj__').del_attribute_value(class_name=self.cls.__name__, attribute_name=self.public_name, ID=ID)
173
+
174
+ def container_update(self, this, data=None):
175
+ ID = object.__getattribute__(this, 'id')
176
+ self.cls.__dbworkobj__.add_attribute_value(class_name=self.cls.__name__, attribute_name=self.public_name, ID=ID, data=data, _cls_dbattribute=self.cls)
@@ -0,0 +1,398 @@
1
+ Metadata-Version: 2.4
2
+ Name: db_attribute
3
+ Version: 2.1
4
+ Summary: DataBase attribute package
5
+ Home-page: https://github.com/shutkanos/Db-Attribute
6
+ Author: Shutkanos
7
+ Author-email: Shutkanos <Shutkanos836926@mail.ru>
8
+ License: MIT
9
+ Project-URL: Homepage, https://github.com/shutkanos/Db-Attribute
10
+ Project-URL: Documentation, https://github.com/shutkanos/Db-Attribute/readme.md
11
+ Project-URL: Repository, https://github.com/shutkanos/Db-Attribute
12
+ Keywords: db,database,attribute,db_attribute,db attribute,DbAttribute,database attribute
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Requires-Python: >=3.9
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: mysql-connector-python>=1.4
21
+ Requires-Dist: orjson
22
+ Dynamic: author
23
+ Dynamic: home-page
24
+ Dynamic: license-file
25
+
26
+ DbAttribute - Database Attribute
27
+ =========================
28
+
29
+ This module allows you to save attributes of objects not in RAM, but in a database. the closest analogue is <a href='https://github.com/sqlalchemy/sqlalchemy'>SQLAlchemy</a>. Unlike SQLAlchemy, this module maximizes automatism, allowing the developer to focus on other details without worrying about working with the database.
30
+
31
+ * [Supported types](#supported-types)
32
+ * [Install](#install)
33
+ * [How it used](#how-it-used)
34
+ * [Create class](#create-class)
35
+ * [Options](#options)
36
+ * [Work with obj](#work-with-obj)
37
+ * [Create new obj / add obj do db](#create-new-obj--add-obj-do-db)
38
+ * [Found / get obj](#found--get-obj)
39
+ * [Iterations](#iterations)
40
+ * [Change attribute of obj](#change-attribute-of-obj)
41
+ * [Dump mode](#dump-mode)
42
+ * [Types](#types)
43
+ * [Db attribute](#db-attribute)
44
+ * [Db classes](#db-classes)
45
+ * [Json type](#json-type)
46
+ * [Speed Test](#speed-test)
47
+ * [Get attr](#get-attr)
48
+ * [Set attr](#set-attr)
49
+ * [Data base](#data-base)
50
+
51
+ # Supported types
52
+
53
+ This module supported standart types: `int`, `float`, `str`, `bool`, `None`, `tuple`, `list`, `set`, `dict`, `datetime`.
54
+
55
+ If developer needs other data types, he will need to write an adapter class.
56
+
57
+ # Install
58
+
59
+ Installation from source (requires git):
60
+
61
+ ```
62
+ $ pip install git+https://github.com/shutkanos/Db-Attribute.git
63
+ ```
64
+
65
+ # How it used
66
+
67
+ ## Create class
68
+
69
+ For create any classes (Tables):
70
+
71
+ * Set metaclass `DbAttributeMetaclass`
72
+ * Inheritance the `DbAttribute` (optional, since it inherits automatically when using a metaclass)
73
+ * Set dbworkobj for connect to database
74
+ * Create any fields / Annotations / DbFields for database
75
+
76
+ ```python
77
+ from db_attribute import DbAttribute, DbAttributeMetaclass, db_work, connector
78
+ from db_attribute.db_types import DbField
79
+
80
+ connect_obj = connector.Connection(host=*mysqlhost*, user=*user*, password=*password*, database=*databasename*)
81
+ db_work_obj = db_work.Db_work(connect_obj)
82
+
83
+ class User(DbAttribute, metaclass=DbAttributeMetaclass, __dbworkobj__=db_work_obj):
84
+ name: str = DbField(default='NotSet') # Ok
85
+ age: int = -1 # Ok
86
+ ban = DbField(default=False) # Ok
87
+ other_int_information = 100 # Need annotation or DbField - not error, but not saved
88
+ list_of_books = DbField(default_factory=lambda: ['name of first book']) # Ok
89
+ sittings: dict = DbField(default_factory=lambda: {}) # Ok
90
+ ```
91
+
92
+ Each class object has its own `id`. It is inherited from DbAttribute and stored in __dict__
93
+
94
+ ### Options
95
+
96
+ Options can be set in different ways:
97
+
98
+ ```python
99
+ class User(DbAttribute, metaclass=DbAttributeMetaclass, __dbworkobj__ = db_work_obj):
100
+ pass
101
+ ```
102
+ ```python
103
+ class User(DbAttribute, metaclass=DbAttributeMetaclass):
104
+ __dbworkobj__ = db_work_obj
105
+ ```
106
+ ```python
107
+ class User(DbAttribute, metaclass=DbAttributeMetaclass):
108
+ class Meta:
109
+ __dbworkobj__ = db_work_obj
110
+ ```
111
+ ```python
112
+ class BaseMeta:
113
+ __dbworkobj__ = dbworkobj
114
+ class User(DbAttribute, metaclass=DbAttributeMetaclass):
115
+ Meta = BaseMeta
116
+ ```
117
+
118
+ All options:
119
+
120
+ * `__dbworkobj__` - database work object (required parameter),
121
+ * `__max_repr_recursion_limit__` - maximum recursion limit for `__repr__` of DbAttribute
122
+ * `__repr_class_name__` - sets the name of this class when using the method `__repr__` of DbAttribute
123
+
124
+ ## Work with obj
125
+
126
+ ### Create new obj / add obj do db
127
+
128
+ For create obj use id (optional) and other fields (optional),
129
+
130
+ ```python
131
+ obj = User(id=3) # other field set to defaults value
132
+ print(obj) # User(id=3, name=*default value*)
133
+ ```
134
+ ```python
135
+ obj = User(name='Ben', id=3)
136
+ print(obj) # User(id=3, name='Ben')
137
+ ```
138
+ ```python
139
+ obj = User(name='Alica')
140
+ print(obj) # User(id=4, name='Alica')
141
+ obj = User(name='Alica')
142
+ print(obj) # User(id=5, name='Alica')
143
+ ```
144
+
145
+ If Developer need recreated obj, he can call DbAttribute cls with id.
146
+
147
+ ```python
148
+ obj = User(name='Ben', age=10, id=3) #insert obj to db
149
+ print(obj) #User(id=3, name='Ben', age=10)
150
+
151
+ obj = User(id=3)
152
+ print(obj) #User(id=3, name='Ben', age=10)
153
+
154
+ obj = User('Anna', id=3)
155
+ print(obj) #User(id=3, name='Anna', age=10)
156
+
157
+ obj = User(age=15, id=3)
158
+ print(obj) #User(id=3, name='Anna', age=15)
159
+
160
+ obj = User(id=3)
161
+ print(obj) #User(id=3, name='Anna', age=15)
162
+ ```
163
+
164
+ ### Found / get obj
165
+
166
+ if the developer needs to find an object, he can use the 'get' method.
167
+
168
+ if the 'get' method finds multiple search results, it selects the smallest id.
169
+ if the 'get' method does not find any search results, it returns None.
170
+
171
+ ```python
172
+ #create objs
173
+ obj = User(name='Bob', age=3, id=1)
174
+ obj = User(name='Bob', age=2, id=2)
175
+ obj = User(name='Anna', age=2, id=3)
176
+ #finds objs
177
+ print(User.get((User.age == 3) & (User.name == 'Bob'))) #User(id=1, name=Bob, age=3)
178
+ print(User.get(User.name == 'Anna')) #User(id=3, name=Anna, age=2)
179
+ print(User.get(User.name == 'Bob')) #User(id=1, name=Bob, age=3)
180
+ print(User.get(User.name == 'Other name')) #None
181
+ ```
182
+
183
+ To check the correctness of writing a logical expression, you can:
184
+
185
+ ```python
186
+ print(User.name == 'Anna') #(User.name = Anna)
187
+ print((User.age == 3) & (User.name == 'Bob')) #((User.age = 3) and (User.name = Bob))
188
+ ```
189
+
190
+ Use '&', '|' instead of the 'and', 'or' operators. The 'and' and 'or' operators are not supported
191
+
192
+ ### Iterations
193
+
194
+ If a developer needs to iterate through all the elements of a class, they can use standard Python tools.
195
+
196
+ ```python
197
+ print(list(User))
198
+ #[User(id=1, name=Bob, age=3), User(id=2, name=Bob, age=2), User(id=3, name=Anna, age=2)]
199
+
200
+ print([i.name for i in User])
201
+ #['Bob', 'Bob', 'Anna']
202
+
203
+ for i in User:
204
+ print(i)
205
+ #User(id=1, name=Bob, age=3)
206
+ #User(id=2, name=Bob, age=2)
207
+ #User(id=3, name=Anna, age=2)
208
+ ```
209
+
210
+ ### Change attribute of obj
211
+
212
+ ```python
213
+ obj = User(name='Bob', list_of_books=[], id=1)
214
+
215
+ print(obj) #User(id=1, name='Bob', list_of_books=[])
216
+
217
+ obj.name = 'Anna'
218
+ obj.list_of_books.append('Any name of book')
219
+
220
+ print(obj) #User(id=1, name='Anna', list_of_books=['Any name of book'])
221
+ ```
222
+
223
+ ### Dump mode
224
+
225
+ If in any function you will work with obj, you can activate manual_dump_mode (auto_dump_mode is default),
226
+
227
+ * `auto_dump_mode`: attributes don't save in self.__dict__, all changes automatic dump in db.
228
+ * `manual_dump_mode`: attributes save in self.__dict__, and won't dump in db until self.db_attribute_set_dump_mode is called. this helps to quickly perform operations on containers db attributes
229
+
230
+ DbAttribute.set_auto_dump_mode set auto_dump_mode and call dump
231
+
232
+ DbAttribute.set_manual_dump_mode set manual_dump_mode
233
+
234
+ ```python
235
+ user = User(id=1, any_db_data1=531, any_db_data2='string')
236
+ print(user.__dict__)
237
+ # {'id': 1}
238
+ user.set_manual_dump_mode()
239
+ print(user.__dict__)
240
+ # {'id': 1, '_any_db_data1': 531, '_any_db_data2': 'string'}
241
+ ```
242
+ Or set dump mod for individual attributes
243
+
244
+ ```python
245
+ user = User(id=1, any_db_data1=531, any_db_data2='string')
246
+ print(user.__dict__)
247
+ # {'id': 1}
248
+ user.set_manual_dump_mode({'any_db_data1'})
249
+ print(user.__dict__)
250
+ # {'id': 1, '_any_db_data1': 531}
251
+ ```
252
+
253
+ ```python
254
+ user = User(id=1, list_of_books=[])
255
+ user.set_manual_dump_mode()
256
+ for i in range(10 ** 5):
257
+ user.list_of_books.append(i)
258
+ user.set_auto_dump_mode()
259
+ ```
260
+ If Developer need dump attributes to db with manual_dump_mode, you can use DbAttribute.db_attribute_dump
261
+
262
+ ```python
263
+ user = User(id=1, list_of_books=[])
264
+ user.set_manual_dump_mode()
265
+ for i in range(10 ** 4):
266
+ user.list_of_books.append(i)
267
+ user.dump() # dump the list_of_books to db
268
+ for i in range(10 ** 4):
269
+ user.list_of_books.append(i)
270
+ user.set_auto_dump_mode()
271
+ ```
272
+
273
+ ## Types
274
+
275
+ ### Db attribute
276
+
277
+ Developer can set the Db attribute class as data type for another Db attribute class
278
+
279
+ ```python
280
+ from db_attribute.db_types import TableType
281
+
282
+ class Class_A(DbAttribute, metaclass=DbAttributeMetaclass):
283
+ Meta = BaseMeta
284
+ obj_b: TableType('Class_B')
285
+
286
+ class Class_B(DbAttribute, metaclass=DbAttributeMetaclass):
287
+ Meta = BaseMeta
288
+ obj_a: Class_A
289
+ ```
290
+ For create obj:
291
+ ```python
292
+ obj_a = Class_A(id=15, name='Anna', obj_b=1)
293
+ obj_b = Class_B(id=1, name='Bob', obj_a=15)
294
+ print(obj_b) #Class_B(id=1, name=Bob, obj_a=Class_A(id=15, name=Anna, obj_b=Class_B(id=1, ...)))
295
+ #or
296
+ obj_a = Class_A(id=15, name='Anna', obj_b=obj_b)
297
+ print(obj_a) #Class_A(id=15, name=Anna, obj_b=Class_B(id=1, name=Bob, obj_a=Class_A(id=15, ...)))
298
+ ```
299
+ For found obj:
300
+ ```python
301
+ Class_A(id=15, name='Anna', obj_b=1)
302
+ obj = Class_B(id=1, name='Bob', obj_a=15)
303
+ obj = Class_A.get(Class_A.obj_b == obj)
304
+ print(obj) #Class_A(id=15, name=Anna, obj_b=Class_B(id=1, name=Bob, obj_a=Class_A(id=15, ...)))
305
+ #And Found with use id of obj:
306
+ obj = Class_A.get(Class_A.obj_b == 1)
307
+ print(obj) #Class_A(id=15, name=Anna, obj_b=Class_B(id=1, name=Bob, obj_a=Class_A(id=15, ...)))
308
+ ```
309
+
310
+ ### Db classes
311
+ When collections are stored in memory, they converted to Db classes
312
+ ```python
313
+ obj = User(1, list_of_books=[1, 2, 3])
314
+ print(type(obj.list_of_books)) #DbList
315
+ ```
316
+ ```python
317
+ obj = User(1, times=[datetime(2024, 1, 1)])
318
+ print(type(obj.times[0])) #DbDatetime
319
+ ```
320
+ And when collections dumped to db, they converted to json
321
+ ```python
322
+ obj = User(1, list_of_books=[1, 2, 3])
323
+ print(obj.list_of_books.dumps()) #{"t": "DbList", "d": [1, 2, 3]}
324
+ ```
325
+ ```python
326
+ obj = User(1, times=[datetime(2024, 1, 1), datetime(2027, 7, 7)])
327
+ print(obj.list_of_books.dumps())
328
+ #{"t": "DbList", "d": [{"t": "DbDatetime", "d": "2024-01-01T00:00:00"}, {"t": "DbDatetime", "d": "2027-07-07T00:00:00"}]}
329
+ ```
330
+
331
+ ### Json type
332
+
333
+ Db attribute support `tuple`, `list`, `dict`, other collections, but this types slow, because uses Db classes (see [speed test](#speed-test)).
334
+
335
+ To solve this problem, use a Json convertation
336
+
337
+ ```python
338
+ from db_attribute.db_types import JsonType, DbField
339
+
340
+ class User(DbAttribute, metaclass=DbAttributeMetaclass):
341
+ Meta = BaseMeta
342
+ sittings: JsonType = DbField(default_factory=lambda: {})
343
+
344
+ obj = User(1, sittings={1: 2, 3: [4, 5]})
345
+ print(obj.sittings) # {'1': 2, '3': [4, 5]}
346
+ print(type(obj.sittings)) # dict
347
+ ```
348
+
349
+ * If Developer change obj with JsonType, this obj don't dump to db, you need set the new obj
350
+ * The json support only `dict`, `list`, `str`, `int`, `float`, `True`, `False`, `None`
351
+
352
+ ```python
353
+ obj = User(1, sittings={1: 2, 3: [4, 5]})
354
+ del obj.sittings['3'] # not changed
355
+ obj.sittings['1'] = 3 # not changed
356
+ obj.sittings |= {4: 5} # not changed
357
+ print(obj.sittings) #{'1': 2, '3': [4, 5]}
358
+ obj.sittings = {1: 3} # changed
359
+ print(obj.sittings) #{'1': 3}
360
+ ```
361
+
362
+ # Speed Test
363
+
364
+ The execution speed may vary from computer to computer, so you need to focus on the specified number of operations per second of a regular mysql
365
+
366
+ * mysql `select` - 12500 op/sec
367
+ * mysql `insert` - 8500 op/sec<br>
368
+
369
+ ## Get attr
370
+
371
+ Mysql `select` - 12500 op/sec
372
+
373
+ Type | Operation/seconds | How much slower is it
374
+ ----------|-------------------|---------------------------
375
+ int | 11658 op/sec | -6%
376
+ str | 11971 op/sec | -4%
377
+ tuple | 9685 op/sec | -22%
378
+ list | 9630 op/sec | -23%
379
+ dict | 9545 op/sec | -23%
380
+ JsonType | 11937 op/sec | -4%
381
+
382
+ ## Set attr
383
+
384
+ Mysql `insert` - 8500 op/sec<br>
385
+
386
+ Type | Operation/seconds | How much slower is it
387
+ ----------|-------------------|---------------------------
388
+ int | 8056 op/sec | -5%
389
+ str | 8173 op/sec | -3%
390
+ tuple | 6284 op/sec | -26%
391
+ list | 6043 op/sec | -28%
392
+ dict | 6354 op/sec | -25%
393
+ JsonType | 7297 op/sec | -14%
394
+
395
+ # Data base
396
+
397
+ this module used MySQL db (<a href="https://github.com/mysql/mysql-connector-python/blob/trunk/LICENSE.txt">Licanse</a>), and for use it, you need install <a href='https://www.mysql.com'>mysql</a>
398
+
@@ -0,0 +1,11 @@
1
+ db_attribute/__init__.py,sha256=w5yLqFHRRWUITQWaErMg3sx4ByI0R941Tr3NhGluhhk,14408
2
+ db_attribute/connector.py,sha256=Ttdjj5u4l8KJARjviF8vH8nF2Ijoqd0RjWyCevtNtu0,2291
3
+ db_attribute/db_class.py,sha256=mkQJ77XeMWdcnPNX73M2zg1eVjyUITGurVkRy7mtDWM,50735
4
+ db_attribute/db_types.py,sha256=x3gx3OEw0qqnUPYBd1eQRuljczQ5moBARpTMtmn4Cok,7186
5
+ db_attribute/db_work.py,sha256=fzk3RP0dU-I0Tk7KISdh6W6Gks0qu2b_7z2QI3JdTL8,19601
6
+ db_attribute/discriptor.py,sha256=LX8H-3vPabxUgp89By8DNYz3N_uaO3uYY0sfJOQyFD4,8306
7
+ db_attribute-2.1.dist-info/licenses/LICENSE,sha256=gheTd8aiLMcHyg8ZcZnpyFiXZB4liiCoDTqwta5KGP0,1095
8
+ db_attribute-2.1.dist-info/METADATA,sha256=WEEyEdjLfFxIWIEcFnaV9aEBRhekFA7-dOmFz4WU9IM,12851
9
+ db_attribute-2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
10
+ db_attribute-2.1.dist-info/top_level.txt,sha256=YLmpyp35GpOP49dt8-AGQsss3GxChU4224v7qgIcd7Y,13
11
+ db_attribute-2.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-present Shutkanos
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ db_attribute