PyAutomationIO 0.0.0__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.
Files changed (138) hide show
  1. automation/__init__.py +46 -0
  2. automation/alarms/__init__.py +563 -0
  3. automation/alarms/states.py +192 -0
  4. automation/alarms/trigger.py +64 -0
  5. automation/buffer.py +132 -0
  6. automation/core.py +1775 -0
  7. automation/dbmodels/__init__.py +23 -0
  8. automation/dbmodels/alarms.py +524 -0
  9. automation/dbmodels/core.py +86 -0
  10. automation/dbmodels/events.py +153 -0
  11. automation/dbmodels/logs.py +155 -0
  12. automation/dbmodels/machines.py +181 -0
  13. automation/dbmodels/opcua.py +81 -0
  14. automation/dbmodels/opcua_server.py +174 -0
  15. automation/dbmodels/tags.py +921 -0
  16. automation/dbmodels/users.py +259 -0
  17. automation/extensions/__init__.py +15 -0
  18. automation/extensions/api.py +149 -0
  19. automation/extensions/cors.py +18 -0
  20. automation/filter/__init__.py +19 -0
  21. automation/iad/__init__.py +3 -0
  22. automation/iad/frozen_data.py +54 -0
  23. automation/iad/out_of_range.py +51 -0
  24. automation/iad/outliers.py +51 -0
  25. automation/logger/__init__.py +0 -0
  26. automation/logger/alarms.py +426 -0
  27. automation/logger/core.py +265 -0
  28. automation/logger/datalogger.py +646 -0
  29. automation/logger/events.py +194 -0
  30. automation/logger/logdict.py +53 -0
  31. automation/logger/logs.py +203 -0
  32. automation/logger/machines.py +248 -0
  33. automation/logger/opcua_server.py +130 -0
  34. automation/logger/users.py +96 -0
  35. automation/managers/__init__.py +4 -0
  36. automation/managers/alarms.py +455 -0
  37. automation/managers/db.py +328 -0
  38. automation/managers/opcua_client.py +186 -0
  39. automation/managers/state_machine.py +183 -0
  40. automation/models.py +174 -0
  41. automation/modules/__init__.py +14 -0
  42. automation/modules/alarms/__init__.py +0 -0
  43. automation/modules/alarms/resources/__init__.py +10 -0
  44. automation/modules/alarms/resources/alarms.py +280 -0
  45. automation/modules/alarms/resources/summary.py +79 -0
  46. automation/modules/events/__init__.py +0 -0
  47. automation/modules/events/resources/__init__.py +10 -0
  48. automation/modules/events/resources/events.py +83 -0
  49. automation/modules/events/resources/logs.py +109 -0
  50. automation/modules/tags/__init__.py +0 -0
  51. automation/modules/tags/resources/__init__.py +8 -0
  52. automation/modules/tags/resources/tags.py +201 -0
  53. automation/modules/users/__init__.py +2 -0
  54. automation/modules/users/resources/__init__.py +10 -0
  55. automation/modules/users/resources/models/__init__.py +2 -0
  56. automation/modules/users/resources/models/roles.py +5 -0
  57. automation/modules/users/resources/models/users.py +14 -0
  58. automation/modules/users/resources/roles.py +38 -0
  59. automation/modules/users/resources/users.py +113 -0
  60. automation/modules/users/roles.py +121 -0
  61. automation/modules/users/users.py +335 -0
  62. automation/opcua/__init__.py +1 -0
  63. automation/opcua/models.py +541 -0
  64. automation/opcua/subscription.py +259 -0
  65. automation/pages/__init__.py +0 -0
  66. automation/pages/alarms.py +34 -0
  67. automation/pages/alarms_history.py +21 -0
  68. automation/pages/assets/styles.css +7 -0
  69. automation/pages/callbacks/__init__.py +28 -0
  70. automation/pages/callbacks/alarms.py +218 -0
  71. automation/pages/callbacks/alarms_summary.py +20 -0
  72. automation/pages/callbacks/db.py +222 -0
  73. automation/pages/callbacks/filter.py +238 -0
  74. automation/pages/callbacks/machines.py +29 -0
  75. automation/pages/callbacks/machines_detailed.py +581 -0
  76. automation/pages/callbacks/opcua.py +266 -0
  77. automation/pages/callbacks/opcua_server.py +244 -0
  78. automation/pages/callbacks/tags.py +495 -0
  79. automation/pages/callbacks/trends.py +119 -0
  80. automation/pages/communications.py +129 -0
  81. automation/pages/components/__init__.py +123 -0
  82. automation/pages/components/alarms.py +151 -0
  83. automation/pages/components/alarms_summary.py +45 -0
  84. automation/pages/components/database.py +128 -0
  85. automation/pages/components/gaussian_filter.py +69 -0
  86. automation/pages/components/machines.py +396 -0
  87. automation/pages/components/opcua.py +384 -0
  88. automation/pages/components/opcua_server.py +53 -0
  89. automation/pages/components/tags.py +253 -0
  90. automation/pages/components/trends.py +66 -0
  91. automation/pages/database.py +26 -0
  92. automation/pages/filter.py +55 -0
  93. automation/pages/machines.py +20 -0
  94. automation/pages/machines_detailed.py +41 -0
  95. automation/pages/main.py +63 -0
  96. automation/pages/opcua_server.py +28 -0
  97. automation/pages/tags.py +40 -0
  98. automation/pages/trends.py +35 -0
  99. automation/singleton.py +30 -0
  100. automation/state_machine.py +1672 -0
  101. automation/tags/__init__.py +2 -0
  102. automation/tags/cvt.py +1198 -0
  103. automation/tags/filter.py +55 -0
  104. automation/tags/tag.py +418 -0
  105. automation/tests/__init__.py +10 -0
  106. automation/tests/test_alarms.py +110 -0
  107. automation/tests/test_core.py +257 -0
  108. automation/tests/test_unit.py +21 -0
  109. automation/tests/test_user.py +155 -0
  110. automation/utils/__init__.py +164 -0
  111. automation/utils/decorators.py +222 -0
  112. automation/utils/npw.py +294 -0
  113. automation/utils/observer.py +21 -0
  114. automation/utils/units.py +118 -0
  115. automation/variables/__init__.py +55 -0
  116. automation/variables/adimentional.py +30 -0
  117. automation/variables/current.py +71 -0
  118. automation/variables/density.py +115 -0
  119. automation/variables/eng_time.py +68 -0
  120. automation/variables/force.py +90 -0
  121. automation/variables/length.py +104 -0
  122. automation/variables/mass.py +80 -0
  123. automation/variables/mass_flow.py +101 -0
  124. automation/variables/percentage.py +30 -0
  125. automation/variables/power.py +113 -0
  126. automation/variables/pressure.py +93 -0
  127. automation/variables/temperature.py +168 -0
  128. automation/variables/volume.py +70 -0
  129. automation/variables/volumetric_flow.py +100 -0
  130. automation/workers/__init__.py +2 -0
  131. automation/workers/logger.py +164 -0
  132. automation/workers/state_machine.py +207 -0
  133. automation/workers/worker.py +36 -0
  134. pyautomationio-0.0.0.dist-info/METADATA +198 -0
  135. pyautomationio-0.0.0.dist-info/RECORD +138 -0
  136. pyautomationio-0.0.0.dist-info/WHEEL +5 -0
  137. pyautomationio-0.0.0.dist-info/licenses/LICENSE +21 -0
  138. pyautomationio-0.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,23 @@
1
+ from .core import BaseModel, proxy
2
+ from .tags import (
3
+ Manufacturer,
4
+ Segment,
5
+ Tags,
6
+ TagValue,
7
+ Variables,
8
+ Units,
9
+ DataTypes
10
+ )
11
+ from .alarms import (
12
+ AlarmStates,
13
+ AlarmTypes,
14
+ Alarms,
15
+ AlarmSummary
16
+ )
17
+
18
+ from .opcua import OPCUA
19
+ from .users import Roles, Users
20
+ from .events import Events
21
+ from .logs import Logs
22
+ from .machines import Machines, TagsMachines
23
+ from .opcua_server import AccessType, OPCUAServer
@@ -0,0 +1,524 @@
1
+ import pytz
2
+ from peewee import CharField, FloatField, ForeignKeyField, TimestampField
3
+ from ..dbmodels.core import BaseModel
4
+ from datetime import datetime
5
+ from .tags import Tags
6
+ from ..alarms.states import States
7
+ from ..tags.cvt import CVTEngine
8
+
9
+ tag_engine = CVTEngine()
10
+
11
+ class AlarmTypes(BaseModel):
12
+
13
+ name = CharField(unique=True) # high-high , high , bool , low , low-low
14
+
15
+ @classmethod
16
+ def create(cls, name:str)-> dict:
17
+ r"""
18
+ You can use Model.create() to create a new model instance. This method accepts keyword arguments, where the keys correspond
19
+ to the names of the model's fields. A new instance is returned and a row is added to the table.
20
+
21
+ ```python
22
+ >>> AlarmsType.create(name='High-High')
23
+ {
24
+ 'message': (str)
25
+ 'data': (dict) {
26
+ 'name': 'HIGH-HIGH'
27
+ }
28
+ }
29
+ ```
30
+
31
+ This will INSERT a new row into the database. The primary key will automatically be retrieved and stored on the model instance.
32
+
33
+ **Parameters**
34
+
35
+ * **name:** (str), Industrial protocol name
36
+
37
+ **Returns**
38
+
39
+ * **result:** (dict) --> {'message': (str), 'data': (dict) row serialized}
40
+
41
+ """
42
+ result = dict()
43
+ data = dict()
44
+ name = name.upper()
45
+
46
+ if not cls.name_exist(name):
47
+
48
+ query = cls(name=name)
49
+ query.save()
50
+
51
+ message = f"Alarm type {name} created successfully"
52
+ data.update(query.serialize())
53
+
54
+ result.update(
55
+ {
56
+ 'message': message,
57
+ 'data': data
58
+ }
59
+ )
60
+ return result
61
+
62
+ message = f"Alarm type {name} is already into database"
63
+ result.update(
64
+ {
65
+ 'message': message,
66
+ 'data': data
67
+ }
68
+ )
69
+ return result
70
+
71
+ @classmethod
72
+ def read_by_name(cls, name:str):
73
+ r"""
74
+ Get instance by its a name
75
+
76
+ **Parameters**
77
+
78
+ * **name:** (str) Alarm type name
79
+
80
+ **Returns**
81
+
82
+ * **bool:** If True, name exist into database
83
+ """
84
+ return cls.get_or_none(name=name.upper())
85
+
86
+ @classmethod
87
+ def name_exist(cls, name:str)->bool:
88
+ r"""
89
+ Verify is a name exist into database
90
+
91
+ **Parameters**
92
+
93
+ * **name:** (str) Alarm type name
94
+
95
+ **Returns**
96
+
97
+ * **bool:** If True, name exist into database
98
+ """
99
+ query = cls.get_or_none(name=name.upper())
100
+
101
+ if query is not None:
102
+
103
+ return True
104
+
105
+ return False
106
+
107
+ def serialize(self)-> dict:
108
+ r"""
109
+ Serialize database record to a jsonable object
110
+ """
111
+
112
+ return {
113
+ "id": self.id,
114
+ "name": self.name
115
+ }
116
+
117
+
118
+ class AlarmStates(BaseModel):
119
+ r"""
120
+ Based on ISA 18.2
121
+ """
122
+ name = CharField(unique=True)
123
+ mnemonic = CharField(max_length=20)
124
+ condition = CharField(max_length=20)
125
+ status = CharField(max_length=20)
126
+
127
+ @classmethod
128
+ def create(cls, name:str, mnemonic:str, condition:str, status:str)-> dict:
129
+ r"""
130
+ You can use Model.create() to create a new model instance. This method accepts keyword arguments, where the keys correspond
131
+ to the names of the model's fields. A new instance is returned and a row is added to the table.
132
+
133
+ ```python
134
+ >>> AlarmsType.create(name='Unacknowledged', mnemonic='UNACKED', description='Alarm unacknowledged')
135
+ {
136
+ 'message': (str)
137
+ 'data': (dict) {
138
+ 'id': 1,
139
+ 'name': 'unacknowledged',
140
+ 'mnemonic': 'UNACKED',
141
+ 'description': 'Alarm unacknowledged'
142
+ }
143
+ }
144
+ ```
145
+
146
+ This will INSERT a new row into the database. The primary key will automatically be retrieved and stored on the model instance.
147
+
148
+ **Parameters**
149
+
150
+ * **name:** (str), Industrial protocol name
151
+
152
+ **Returns**
153
+
154
+ * **result:** (dict) --> {'message': (str), 'data': (dict) row serialized}
155
+
156
+ """
157
+
158
+ if not cls.name_exist(name):
159
+
160
+ query = cls(name=name, mnemonic=mnemonic, condition=condition, status=status)
161
+ query.save()
162
+
163
+ return query
164
+
165
+ @classmethod
166
+ def read_by_name(cls, name:str)->bool:
167
+ r"""
168
+ Get instance by its a name
169
+
170
+ **Parameters**
171
+
172
+ * **name:** (str) Alarm type name
173
+
174
+ **Returns**
175
+
176
+ * **bool:** If True, name exist into database
177
+ """
178
+ return cls.get_or_none(name=name)
179
+
180
+ @classmethod
181
+ def name_exist(cls, name:str)->bool:
182
+ r"""
183
+ Verify is a name exist into database
184
+
185
+ **Parameters**
186
+
187
+ * **name:** (str) Alarm type name
188
+
189
+ **Returns**
190
+
191
+ * **bool:** If True, name exist into database
192
+ """
193
+ query = cls.get_or_none(name=name)
194
+
195
+ if query is not None:
196
+
197
+ return True
198
+
199
+ return False
200
+
201
+ def serialize(self)-> dict:
202
+ r"""
203
+ Serialize database record to a jsonable object
204
+ """
205
+
206
+ return {
207
+ "id": self.id,
208
+ "name": self.name,
209
+ "mnemonic": self.mnemonic,
210
+ "condition": self.condition,
211
+ "status": self.status
212
+ }
213
+
214
+
215
+ class Alarms(BaseModel):
216
+
217
+ identifier = CharField(unique=True)
218
+ name = CharField(unique=True, max_length=128)
219
+ tag = ForeignKeyField(Tags, backref='alarms')
220
+ trigger_type = ForeignKeyField(AlarmTypes, backref='alarms')
221
+ trigger_value = FloatField()
222
+ description = CharField(null=True, max_length=256)
223
+ state = ForeignKeyField(AlarmStates, backref='alarms')
224
+ timestamp = TimestampField(utc=True, null=True)
225
+
226
+ @classmethod
227
+ def create(
228
+ cls,
229
+ identifier:str,
230
+ name:str,
231
+ tag:str,
232
+ trigger_type:str,
233
+ trigger_value:float,
234
+ description:str=None,
235
+ state:str=States.NORM.value,
236
+ timestamp:datetime=None
237
+ ):
238
+ r"""Documentation here
239
+
240
+ # Parameters
241
+
242
+ -
243
+
244
+ # Returns
245
+
246
+ -
247
+ """
248
+ trigger_type = AlarmTypes.read_by_name(name=trigger_type)
249
+ tag = Tags.read_by_name(name=tag)
250
+ state = AlarmStates.read_by_name(name=state)
251
+ if not cls.name_exists(name):
252
+
253
+ alarm = super().create(
254
+ identifier=identifier,
255
+ name=name,
256
+ tag=tag,
257
+ trigger_type=trigger_type,
258
+ trigger_value=trigger_value,
259
+ description=description,
260
+ state=state,
261
+ timestamp=timestamp
262
+ )
263
+ alarm.save()
264
+
265
+ return alarm
266
+
267
+ @classmethod
268
+ def name_exists(cls, name:str)->bool|None:
269
+ r"""Documentation here
270
+
271
+ # Parameters
272
+
273
+ -
274
+
275
+ # Returns
276
+
277
+ -
278
+ """
279
+ tag = cls.get_or_none(name=name)
280
+ if tag:
281
+
282
+ return True
283
+
284
+ @classmethod
285
+ def read(cls, id:str):
286
+ r"""Documentation here
287
+
288
+ # Parameters
289
+
290
+ -
291
+
292
+ # Returns
293
+
294
+ -
295
+ """
296
+ return cls.get_or_none(id=id)
297
+
298
+ @classmethod
299
+ def read_by_identifier(cls, identifier:str):
300
+ r"""Documentation here
301
+
302
+ # Parameters
303
+
304
+ -
305
+
306
+ # Returns
307
+
308
+ -
309
+ """
310
+ return cls.get_or_none(identifier=identifier)
311
+
312
+ @classmethod
313
+ def read_by_name(cls, name:str):
314
+ r"""Documentation here
315
+
316
+ # Parameters
317
+
318
+ -
319
+
320
+ # Returns
321
+
322
+ -
323
+ """
324
+ return cls.get_or_none(name=name)
325
+
326
+ def serialize(self):
327
+ r"""Documentation here
328
+
329
+ # Parameters
330
+
331
+ -
332
+
333
+ # Returns
334
+
335
+ -
336
+ """
337
+ timestamp = self.timestamp
338
+ if timestamp:
339
+
340
+ timestamp = timestamp.strftime(tag_engine.DATETIME_FORMAT)
341
+
342
+ return {
343
+ 'identifier': self.identifier,
344
+ 'name': self.name,
345
+ 'tag': self.tag.name,
346
+ 'alarm_type': self.trigger_type.name,
347
+ 'trigger_value': self.trigger_value,
348
+ 'description': self.description,
349
+ 'state': self.state.name,
350
+ 'timestamp': timestamp
351
+ }
352
+
353
+
354
+ class AlarmSummary(BaseModel):
355
+
356
+ alarm = ForeignKeyField(Alarms, backref='summary')
357
+ state = ForeignKeyField(AlarmStates, backref='summary')
358
+ alarm_time = TimestampField(utc=True)
359
+ ack_time = TimestampField(utc=True, null=True)
360
+
361
+ @classmethod
362
+ def create(cls, name:str, state:str, timestamp:datetime, ack_timestamp:datetime=None):
363
+ _alarm = Alarms.read_by_name(name=name)
364
+ _state = AlarmStates.read_by_name(name=state)
365
+
366
+ if _alarm:
367
+
368
+ if _state:
369
+
370
+ # Create record
371
+ query = cls(alarm=_alarm.id, state=_state.id, alarm_time=timestamp, ack_time=ack_timestamp)
372
+ query.save()
373
+
374
+ return query
375
+
376
+ @classmethod
377
+ def read_by_name(cls, name:str)->bool:
378
+ r"""
379
+ Get instance by its a name
380
+
381
+ **Parameters**
382
+
383
+ * **name:** (str) Alarm type name
384
+
385
+ **Returns**
386
+
387
+ * **bool:** If True, name exist into database
388
+ """
389
+ alarm = Alarms.read_by_name(name=name)
390
+ return cls.select().where(cls.alarm==alarm).order_by(cls.id.desc()).get_or_none()
391
+
392
+ @classmethod
393
+ def read_by_alarm_id(cls, alarm_id:int)->bool:
394
+ r"""
395
+ Get instance by its a name
396
+
397
+ **Parameters**
398
+
399
+ * **name:** (str) Alarm type name
400
+
401
+ **Returns**
402
+
403
+ * **bool:** If True, name exist into database
404
+ """
405
+ alarm = Alarms.read(id=alarm_id)
406
+ return cls.select().where(cls.alarm==alarm).order_by(cls.id.desc()).get_or_none()
407
+
408
+ @classmethod
409
+ def read_all(cls):
410
+ r"""
411
+ Select all records
412
+
413
+ You can use this method to retrieve all instances matching in the database.
414
+
415
+ This method is a shortcut that calls Model.select() with the given query.
416
+
417
+ **Parameters**
418
+
419
+ **Returns**
420
+
421
+ * **result:** (dict) --> {'message': (str), 'data': (list) row serialized}
422
+ """
423
+ data = list()
424
+
425
+ try:
426
+ data = [query.serialize() for query in cls.select().order_by(cls.id.desc())]
427
+
428
+ return data
429
+
430
+ except Exception as _err:
431
+
432
+ return data
433
+
434
+ @classmethod
435
+ def read_lasts(cls, lasts:int=1):
436
+ r"""
437
+ Documentation here
438
+ """
439
+ alarms = cls.select().order_by(cls.id.desc()).limit(lasts)
440
+
441
+ return [alarm.serialize() for alarm in alarms]
442
+
443
+ @classmethod
444
+ def filter_by(
445
+ cls,
446
+ states:list[str]=None,
447
+ names:list[str]=None,
448
+ tags:list[str]=None,
449
+ greater_than_timestamp:datetime=None,
450
+ less_than_timestamp:datetime=None,
451
+ timezone:str='UTC'
452
+ ):
453
+ r"""
454
+ Documentation here
455
+ """
456
+ _timezone = pytz.timezone(timezone)
457
+ query = cls.select()
458
+
459
+ if states:
460
+ subquery = AlarmStates.select(AlarmStates.id).where(AlarmStates.name.in_(states))
461
+ query = query.join(AlarmStates).where(AlarmStates.id.in_(subquery))
462
+
463
+ if names:
464
+ subquery = Alarms.select(Alarms.id).where(Alarms.name.in_(names))
465
+ query = query.join(Alarms).where(Alarms.id.in_(subquery))
466
+
467
+ if tags:
468
+ subquery = Tags.select(Tags.id).where(Tags.name.in_(tags))
469
+ subquery = Alarms.select(Alarms.id).join(Tags).where(Tags.id.in_(subquery))
470
+ query = query.join(Alarms).where(Alarms.id.in_(subquery))
471
+
472
+ if greater_than_timestamp:
473
+ greater_than_timestamp = _timezone.localize(datetime.strptime(greater_than_timestamp, '%Y-%m-%d %H:%M:%S.%f')).astimezone(pytz.UTC)
474
+ query = query.where(cls.alarm_time > greater_than_timestamp)
475
+
476
+ if less_than_timestamp:
477
+ less_than_timestamp = _timezone.localize(datetime.strptime(less_than_timestamp, '%Y-%m-%d %H:%M:%S.%f')).astimezone(pytz.UTC)
478
+ query = query.where(cls.alarm_time < less_than_timestamp)
479
+
480
+ query = query.order_by(cls.id.desc())
481
+ if not query.exists():
482
+
483
+ return []
484
+
485
+ return [alarm.serialize() for alarm in query]
486
+
487
+ @classmethod
488
+ def get_alarm_summary_comments(cls, id:int):
489
+ r"""
490
+ Documentation here
491
+ """
492
+ query = cls.read(id=id)
493
+
494
+ return [comment.serialize() for comment in query.logs]
495
+
496
+ def serialize(self):
497
+ r"""
498
+ Documentation here
499
+ """
500
+ from .. import TIMEZONE
501
+
502
+ ack_time = None
503
+ if self.ack_time:
504
+ ack_time = self.ack_time
505
+ ack_time = pytz.UTC.localize(ack_time).astimezone(TIMEZONE)
506
+ ack_time = ack_time.strftime(tag_engine.DATETIME_FORMAT)
507
+
508
+ alarm_time = self.alarm_time
509
+ alarm_time = pytz.UTC.localize(alarm_time).astimezone(TIMEZONE)
510
+ alarm_time = alarm_time.strftime(tag_engine.DATETIME_FORMAT)
511
+
512
+ return {
513
+ 'id': self.id,
514
+ 'name': self.alarm.name,
515
+ 'tag': self.alarm.tag.name,
516
+ 'description': self.alarm.description,
517
+ 'state': self.state.name,
518
+ 'mnemonic': self.state.mnemonic,
519
+ 'status': self.state.status,
520
+ 'alarm_time': alarm_time,
521
+ 'ack_time': ack_time,
522
+ 'has_comments': True if self.logs else False
523
+ }
524
+
@@ -0,0 +1,86 @@
1
+ from peewee import Proxy, Model
2
+
3
+ proxy = Proxy()
4
+
5
+ SQLITE = 'sqlite'
6
+ MYSQL = 'mysql'
7
+ POSTGRESQL = 'postgresql'
8
+
9
+
10
+ class BaseModel(Model):
11
+
12
+ @classmethod
13
+ def read(cls, id:int|str):
14
+ r"""
15
+ Select a single record
16
+
17
+ You can use this method to retrieve a single instance matching the given query.
18
+
19
+ This method is a shortcut that calls Model.select() with the given query, but limits the result set to a single row.
20
+ Additionally, if no model matches the given query, a DoesNotExist exception will be raised.
21
+
22
+ **Parameters**
23
+
24
+ * **id:** (int), Record ID
25
+
26
+ **Returns**
27
+
28
+ * **result:** (dict) --> {'message': (str), 'data': (list) row serialized}
29
+
30
+ """
31
+ query = cls.select().where(cls.id == id).get_or_none()
32
+
33
+ if query:
34
+
35
+ return query
36
+
37
+ @classmethod
38
+ def read_all(cls):
39
+ r"""
40
+ Select all records
41
+
42
+ You can use this method to retrieve all instances matching in the database.
43
+
44
+ This method is a shortcut that calls Model.select() with the given query.
45
+
46
+ **Parameters**
47
+
48
+ **Returns**
49
+
50
+ * **result:** (dict) --> {'message': (str), 'data': (list) row serialized}
51
+ """
52
+ data = [query.serialize() for query in cls.select()]
53
+
54
+ return data
55
+
56
+ @classmethod
57
+ def put(cls, id:str, **fields):
58
+ r""""
59
+ Update a single record
60
+
61
+ Once a model instance has a primary key, you UPDATE a field by its id.
62
+ The model's primary key will not change:
63
+ """
64
+ if cls.id_exists(id):
65
+
66
+ query = cls.update(**fields).where(cls.id == id)
67
+ query.execute()
68
+ return query
69
+
70
+ @classmethod
71
+ def id_exists(cls, id:str|int)->bool|None:
72
+ r"""
73
+ Verify if a record exist by its id
74
+
75
+ **Parameters**
76
+
77
+ * **id:** (int) Record ID
78
+
79
+ **Returns**
80
+
81
+ * **bool:** If True, so id record exist into database
82
+ """
83
+ return True if cls.get_or_none(id=id) else False
84
+
85
+ class Meta:
86
+ database = proxy