plexus-python-pulse-demeter 1.1.126__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 (31) hide show
  1. plexus/pulse/demeter/__init__.py +6 -0
  2. plexus/pulse/demeter/app/__init__.py +0 -0
  3. plexus/pulse/demeter/app/api/__init__.py +44 -0
  4. plexus/pulse/demeter/app/api/archive_internal_endpoints.py +316 -0
  5. plexus/pulse/demeter/app/api/archive_public_endpoints.py +255 -0
  6. plexus/pulse/demeter/app/api/dataset_internal_endpoints.py +1043 -0
  7. plexus/pulse/demeter/app/api/dataset_public_endpoints.py +2161 -0
  8. plexus/pulse/demeter/app/api/dataset_workflow_endpoints.py +532 -0
  9. plexus/pulse/demeter/app/api/tagging_endpoints.py +323 -0
  10. plexus/pulse/demeter/app/api/user_endpoints.py +78 -0
  11. plexus/pulse/demeter/app/core/__init__.py +0 -0
  12. plexus/pulse/demeter/app/core/database.py +43 -0
  13. plexus/pulse/demeter/app/core/vault.py +29 -0
  14. plexus/pulse/demeter/app/main.py +16 -0
  15. plexus/pulse/demeter/app/models/__init__.py +33 -0
  16. plexus/pulse/demeter/app/models/local.py +249 -0
  17. plexus/pulse/demeter/app/models/registry/__init__.py +112 -0
  18. plexus/pulse/demeter/app/models/registry/archive.py +529 -0
  19. plexus/pulse/demeter/app/models/registry/dataset.py +1531 -0
  20. plexus/pulse/demeter/app/models/registry/tagging.py +478 -0
  21. plexus/pulse/demeter/app/models/registry/user.py +79 -0
  22. plexus/pulse/demeter/tools/__init__.py +0 -0
  23. plexus/pulse/demeter/tools/main.py +306 -0
  24. plexus/pulse/demeter/utils/__init__.py +0 -0
  25. plexus/pulse/demeter/utils/config.py +25 -0
  26. plexus/pulse/demeter/utils/datautils.py +436 -0
  27. plexus_python_pulse_demeter-1.1.126.dist-info/METADATA +36 -0
  28. plexus_python_pulse_demeter-1.1.126.dist-info/RECORD +31 -0
  29. plexus_python_pulse_demeter-1.1.126.dist-info/WHEEL +5 -0
  30. plexus_python_pulse_demeter-1.1.126.dist-info/entry_points.txt +2 -0
  31. plexus_python_pulse_demeter-1.1.126.dist-info/top_level.txt +1 -0
@@ -0,0 +1,529 @@
1
+ import datetime
2
+ import typing
3
+ import uuid as py_uuid
4
+ from typing import Self
5
+
6
+ import pydantic as pdt
7
+ import sqlalchemy as sa
8
+ import sqlalchemy.dialects.postgresql as sa_pg
9
+ import sqlalchemy.orm as sa_orm
10
+ from plexus.common.utils.jsonutils import JsonObject
11
+ from plexus.pulse.common.utils.datautils import (
12
+ validate_bag_name,
13
+ validate_colon_tag,
14
+ validate_dt_timezone,
15
+ validate_hex_string,
16
+ validate_json_type_dump_size,
17
+ validate_kebab_case,
18
+ validate_slash_tag,
19
+ validate_snake_case,
20
+ validate_strict_relpath,
21
+ validate_vehicle_name,
22
+ validate_vin_code,
23
+ )
24
+ from plexus.pulse.common.utils.jsonutils import json_datetime_encoder
25
+ from plexus.pulse.common.utils.ormutils import RevisionModelMixinProtocol
26
+ from plexus.pulse.common.utils.ormutils import make_revision_model_mixin, revision_model_mixin
27
+ from sqlmodel import Field, SQLModel
28
+
29
+ from plexus.pulse.demeter.app.models.registry import RegistryBase
30
+
31
+ __all__ = [
32
+ "VehicleTemplate",
33
+ "SensorTemplate",
34
+ "Vehicle",
35
+ "Sensor",
36
+ "RegisteredBag",
37
+ "VehicleTemplateTable",
38
+ "SensorTemplateTable",
39
+ "VehicleTable",
40
+ "SensorTable",
41
+ "RegisteredBagTable",
42
+ ]
43
+
44
+
45
+ class VehicleTemplate(RegistryBase):
46
+ uuid: py_uuid.UUID = Field(
47
+ sa_column=sa.Column(sa_pg.UUID(as_uuid=True), nullable=False),
48
+ description="UUID of the vehicle template",
49
+ )
50
+ vehicle_type: str = Field(
51
+ sa_column=sa.Column(sa_pg.VARCHAR(64), nullable=False),
52
+ description="Type of the vehicle template",
53
+ )
54
+ manufacturer: str = Field(
55
+ sa_column=sa.Column(sa_pg.VARCHAR(128), nullable=False),
56
+ description="Manufacturer of the vehicle template",
57
+ )
58
+ model_name: str = Field(
59
+ sa_column=sa.Column(sa_pg.VARCHAR(128), nullable=False),
60
+ description="Model name of the vehicle template",
61
+ )
62
+ model_code: str | None = Field(
63
+ sa_column=sa.Column(sa_pg.VARCHAR(64)),
64
+ default=None,
65
+ description="Model code of the vehicle template",
66
+ )
67
+ production_stage: str = Field(
68
+ sa_column=sa.Column(sa_pg.VARCHAR(64), nullable=False),
69
+ description="Production stage of the vehicle template",
70
+ )
71
+ specification: JsonObject = Field(
72
+ sa_column=sa.Column(sa_pg.JSONB, nullable=False),
73
+ description="Specification of the vehicle template in JSON format",
74
+ )
75
+
76
+ @pdt.field_validator("vehicle_type", mode="after")
77
+ @classmethod
78
+ def validate_vehicle_type(cls, v: str) -> str:
79
+ validate_slash_tag(v)
80
+ return v
81
+
82
+ @pdt.field_validator("manufacturer", mode="after")
83
+ @classmethod
84
+ def validate_manufacturer(cls, v: str) -> str:
85
+ validate_snake_case(v)
86
+ return v
87
+
88
+ @pdt.field_validator("model_name", mode="after")
89
+ @classmethod
90
+ def validate_model_name(cls, v: str) -> str:
91
+ validate_slash_tag(v)
92
+ return v
93
+
94
+ @pdt.field_validator("model_code", mode="after")
95
+ @classmethod
96
+ def validate_model_code(cls, v: str | None) -> str | None:
97
+ if v is not None:
98
+ validate_slash_tag(v)
99
+ return v
100
+
101
+ @pdt.field_validator("production_stage", mode="after")
102
+ @classmethod
103
+ def validate_production_stage(cls, v: str) -> str:
104
+ validate_snake_case(v)
105
+ return v
106
+
107
+
108
+ class SensorTemplate(RegistryBase):
109
+ uuid: py_uuid.UUID = Field(
110
+ sa_column=sa.Column(sa_pg.UUID(as_uuid=True), nullable=False),
111
+ description="UUID of the sensor template",
112
+ )
113
+ sensor_type: str = Field(
114
+ sa_column=sa.Column(sa_pg.VARCHAR(64), nullable=False),
115
+ description="Type of the sensor template",
116
+ )
117
+ manufacturer: str = Field(
118
+ sa_column=sa.Column(sa_pg.VARCHAR(128), nullable=False),
119
+ description="Manufacturer of the sensor template",
120
+ )
121
+ model_name: str = Field(
122
+ sa_column=sa.Column(sa_pg.VARCHAR(128), nullable=False),
123
+ description="Model name of the sensor template",
124
+ )
125
+ model_code: str | None = Field(
126
+ sa_column=sa.Column(sa_pg.VARCHAR(64)),
127
+ default=None,
128
+ description="Model code of the sensor template",
129
+ )
130
+ production_stage: str = Field(
131
+ sa_column=sa.Column(sa_pg.VARCHAR(64), nullable=False),
132
+ description="Production stage of the sensor template",
133
+ )
134
+ specification: JsonObject = Field(
135
+ sa_column=sa.Column(sa_pg.JSONB, nullable=False),
136
+ description="Specification of the sensor template in JSON format",
137
+ )
138
+
139
+ @pdt.field_validator("sensor_type", mode="after")
140
+ @classmethod
141
+ def validate_sensor_type(cls, v: str) -> str:
142
+ validate_slash_tag(v)
143
+ return v
144
+
145
+ @pdt.field_validator("manufacturer", mode="after")
146
+ @classmethod
147
+ def validate_manufacturer(cls, v: str) -> str:
148
+ validate_snake_case(v)
149
+ return v
150
+
151
+ @pdt.field_validator("model_name", mode="after")
152
+ @classmethod
153
+ def validate_model_name(cls, v: str) -> str:
154
+ validate_slash_tag(v)
155
+ return v
156
+
157
+ @pdt.field_validator("model_code", mode="after")
158
+ @classmethod
159
+ def validate_model_code(cls, v: str | None) -> str | None:
160
+ if v is not None:
161
+ validate_slash_tag(v)
162
+ return v
163
+
164
+ @pdt.field_validator("production_stage", mode="after")
165
+ @classmethod
166
+ def validate_production_stage(cls, v: str) -> str:
167
+ validate_snake_case(v)
168
+ return v
169
+
170
+
171
+ class Vehicle(RegistryBase):
172
+ vin_code: str = Field(
173
+ sa_column=sa.Column(sa_pg.CHAR(17), nullable=False),
174
+ description="Vehicle Identification Number (VIN) of the vehicle",
175
+ )
176
+ asset_id: str | None = Field(
177
+ sa_column=sa.Column(sa_pg.VARCHAR(128)),
178
+ default=None,
179
+ description="Asset ID of the vehicle",
180
+ )
181
+ vehicle_template_uuid: py_uuid.UUID = Field(
182
+ sa_column=sa.Column(sa_pg.UUID(as_uuid=True), nullable=False),
183
+ description="UUID of the associated vehicle template",
184
+ )
185
+ name: str = Field(
186
+ sa_column=sa.Column(sa_pg.VARCHAR(256), nullable=False),
187
+ description="Name of the vehicle",
188
+ )
189
+ purchase_date: datetime.date | None = Field(
190
+ sa_column=sa.Column(sa_pg.DATE),
191
+ default=None,
192
+ description="Date of purchase of the vehicle",
193
+ )
194
+ tags: list[str] | None = Field(
195
+ sa_column=sa.Column(sa_pg.ARRAY(sa_pg.VARCHAR(64))),
196
+ default=None,
197
+ description="Array of tags for categorization",
198
+ )
199
+ props: JsonObject | None = Field(
200
+ sa_column=sa.Column(sa_pg.JSONB),
201
+ default=None,
202
+ description="Additional JSON properties",
203
+ )
204
+
205
+ @pdt.field_validator("vin_code", mode="after")
206
+ @classmethod
207
+ def validate_vin_code(cls, v: str) -> str:
208
+ validate_vin_code(v)
209
+ return v
210
+
211
+ @pdt.field_validator("asset_id", mode="after")
212
+ @classmethod
213
+ def validate_asset_id(cls, v: str | None) -> str | None:
214
+ if v is not None:
215
+ validate_kebab_case(v)
216
+ return v
217
+
218
+ @pdt.field_validator("name", mode="after")
219
+ @classmethod
220
+ def validate_name(cls, v: str) -> str:
221
+ validate_vehicle_name(v)
222
+ return v
223
+
224
+ @pdt.field_validator("tags", mode="after")
225
+ @classmethod
226
+ def validate_colon_tags(cls, v: list[str] | None) -> list[str] | None:
227
+ for tag in (v or []):
228
+ validate_colon_tag(tag)
229
+ return v
230
+
231
+ @pdt.field_validator("props", mode="after")
232
+ @classmethod
233
+ def validate_props(cls, v: JsonObject | None) -> JsonObject | None:
234
+ if v is not None:
235
+ validate_json_type_dump_size(v, 10000)
236
+ return v
237
+
238
+
239
+ class Sensor(RegistryBase):
240
+ uuid: py_uuid.UUID = Field(
241
+ sa_column=sa.Column(sa_pg.UUID(as_uuid=True), nullable=False),
242
+ description="UUID of the sensor",
243
+ )
244
+ asset_id: str | None = Field(
245
+ sa_column=sa.Column(sa_pg.VARCHAR(128)),
246
+ default=None,
247
+ description="Asset ID of the sensor",
248
+ )
249
+ sensor_template_uuid: py_uuid.UUID = Field(
250
+ sa_column=sa.Column(sa_pg.UUID(as_uuid=True), nullable=False),
251
+ description="UUID of the associated sensor template",
252
+ )
253
+ serial_number: str | None = Field(
254
+ sa_column=sa.Column(sa_pg.VARCHAR(128), nullable=False),
255
+ description="Serial number of the sensor",
256
+ )
257
+ purchase_date: datetime.date | None = Field(
258
+ sa_column=sa.Column(sa_pg.DATE),
259
+ default=None,
260
+ description="Date of purchase of the sensor",
261
+ )
262
+ tags: list[str] | None = Field(
263
+ sa_column=sa.Column(sa_pg.ARRAY(sa_pg.VARCHAR(64))),
264
+ default=None,
265
+ description="Array of tags for categorization",
266
+ )
267
+ props: JsonObject | None = Field(
268
+ sa_column=sa.Column(sa_pg.JSONB),
269
+ default=None,
270
+ description="Additional JSON properties",
271
+ )
272
+
273
+ @pdt.field_validator("asset_id", mode="after")
274
+ @classmethod
275
+ def validate_asset_id(cls, v: str | None) -> str | None:
276
+ if v is not None:
277
+ validate_kebab_case(v)
278
+ return v
279
+
280
+ @pdt.field_validator("props", mode="after")
281
+ @classmethod
282
+ def validate_props(cls, v: JsonObject | None) -> JsonObject | None:
283
+ if v is not None:
284
+ validate_json_type_dump_size(v, 10000)
285
+ return v
286
+
287
+
288
+ class RegisteredBag(RegistryBase):
289
+ name: str = Field(
290
+ sa_column=sa.Column(sa_pg.VARCHAR(256), nullable=False),
291
+ description="Name of the bag",
292
+ )
293
+ path: str = Field(
294
+ sa_column=sa.Column(sa_pg.VARCHAR(512), nullable=False),
295
+ description="Stored path of the bag",
296
+ )
297
+ vehicle_vin_code: str = Field(
298
+ sa_column=sa.Column(sa_pg.CHAR(17), nullable=False),
299
+ description="Vehicle Identification Number (VIN) of the associated vehicle",
300
+ )
301
+ vehicle_name: str = Field(
302
+ sa_column=sa.Column(sa_pg.VARCHAR(256), nullable=False),
303
+ description="Name of the associated vehicle",
304
+ )
305
+ begin_at: datetime.datetime = Field(
306
+ sa_column=sa.Column(sa_pg.TIMESTAMP(timezone=True), nullable=False),
307
+ description="Begin datetime of the data capture",
308
+ )
309
+ end_at: datetime.datetime = Field(
310
+ sa_column=sa.Column(sa_pg.TIMESTAMP(timezone=True), nullable=False),
311
+ description="End datetime of the data capture",
312
+ )
313
+ file_size: int = Field(
314
+ sa_column=sa.Column(sa_pg.BIGINT, nullable=False),
315
+ description="Size of the bag file in bytes",
316
+ )
317
+ file_checksum: str = Field(
318
+ sa_column=sa.Column(sa_pg.VARCHAR(256), nullable=False),
319
+ description="SHA256 checksum of the bag file",
320
+ )
321
+ flags: int = Field(
322
+ sa_column=sa.Column(sa_pg.BIGINT),
323
+ default=0,
324
+ description="Integer bitmask storing status or metadata flags for this record",
325
+ )
326
+ tags: list[str] | None = Field(
327
+ sa_column=sa.Column(sa_pg.ARRAY(sa_pg.VARCHAR(64))),
328
+ default=None,
329
+ description="Array of tags for categorization",
330
+ )
331
+ props: JsonObject | None = Field(
332
+ sa_column=sa.Column(sa_pg.JSONB),
333
+ default=None,
334
+ description="Additional JSON properties",
335
+ )
336
+
337
+ @pdt.field_validator("name", mode="after")
338
+ @classmethod
339
+ def validate_name(cls, v: str) -> str:
340
+ validate_bag_name(v)
341
+ return v
342
+
343
+ @pdt.field_validator("path", mode="after")
344
+ @classmethod
345
+ def validate_path(cls, v: str) -> str:
346
+ validate_strict_relpath(v)
347
+ return v
348
+
349
+ @pdt.field_validator("vehicle_vin_code", mode="after")
350
+ @classmethod
351
+ def validate_vehicle_vin_code(cls, v: str) -> str:
352
+ validate_vin_code(v)
353
+ return v
354
+
355
+ @pdt.field_validator("vehicle_name", mode="after")
356
+ @classmethod
357
+ def validate_vehicle_name(cls, v: str) -> str:
358
+ validate_vehicle_name(v)
359
+ return v
360
+
361
+ @pdt.field_validator("begin_at", mode="after")
362
+ @classmethod
363
+ def validate_begin_at(cls, v: datetime.datetime) -> datetime.datetime:
364
+ validate_dt_timezone(v)
365
+ return v
366
+
367
+ @pdt.field_validator("end_at", mode="after")
368
+ @classmethod
369
+ def validate_end_at(cls, v: datetime.datetime) -> datetime.datetime:
370
+ validate_dt_timezone(v)
371
+ return v
372
+
373
+ @pdt.model_validator(mode="after")
374
+ def validate_begin_at_end_at(self) -> Self:
375
+ if self.begin_at > self.end_at:
376
+ raise ValueError(f"begin_at '{self.begin_at}' is greater than end_at '{self.end_at}'")
377
+ return self
378
+
379
+ @pdt.field_validator("file_checksum", mode="after")
380
+ @classmethod
381
+ def validate_file_checksum(cls, v: str) -> str:
382
+ validate_hex_string(v)
383
+ return v
384
+
385
+ @pdt.field_validator("tags", mode="after")
386
+ @classmethod
387
+ def validate_colon_tags(cls, v: list[str] | None) -> list[str] | None:
388
+ for tag in (v or []):
389
+ validate_colon_tag(tag)
390
+ return v
391
+
392
+ @pdt.field_validator("props", mode="after")
393
+ @classmethod
394
+ def validate_props(cls, v: JsonObject | None) -> JsonObject | None:
395
+ if v is not None:
396
+ validate_json_type_dump_size(v, 10000)
397
+ return v
398
+
399
+ @pdt.field_serializer("begin_at", mode="plain")
400
+ def serialize_begin_at(self, v: datetime.datetime) -> str:
401
+ return json_datetime_encoder(v)
402
+
403
+ @pdt.field_serializer("end_at", mode="plain")
404
+ def serialize_end_at(self, v: datetime.datetime) -> str:
405
+ return json_datetime_encoder(v)
406
+
407
+
408
+ class VehicleTemplateTable(VehicleTemplate, make_revision_model_mixin(), table=True):
409
+ __tablename__ = "vehicle_template"
410
+ __table_args__ = (
411
+ revision_model_mixin.make_index_created_at_updated_at_expired_at(
412
+ "ix_vehicle_template_created_at_updated_at_expired_at"),
413
+ revision_model_mixin.make_unique_index_record_sqn_revision("ix_u_vehicle_template_record_sqn_revision"),
414
+ revision_model_mixin.make_active_unique_index_record_sqn("ix_ua_vehicle_template_record_sqn"),
415
+ revision_model_mixin.make_active_unique_index_for("ix_ua_vehicle_template_uuid", "uuid"),
416
+ sa.Index("ix_vehicle_template_uuid", "uuid", postgresql_using="hash"),
417
+ )
418
+
419
+
420
+ class SensorTemplateTable(SensorTemplate, make_revision_model_mixin(), table=True):
421
+ __tablename__ = "sensor_template"
422
+ __table_args__ = (
423
+ revision_model_mixin.make_index_created_at_updated_at_expired_at(
424
+ "ix_sensor_template_created_at_updated_at_expired_at"),
425
+ revision_model_mixin.make_unique_index_record_sqn_revision("ix_u_sensor_template_record_sqn_revision"),
426
+ revision_model_mixin.make_active_unique_index_record_sqn("ix_ua_sensor_template_record_sqn"),
427
+ revision_model_mixin.make_active_unique_index_for("ix_ua_sensor_template_uuid", "uuid"),
428
+ sa.Index("ix_sensor_template_uuid", "uuid", postgresql_using="hash"),
429
+ )
430
+
431
+
432
+ class VehicleTable(Vehicle, make_revision_model_mixin(), table=True):
433
+ __tablename__ = "vehicle"
434
+ __table_args__ = (
435
+ revision_model_mixin.make_index_created_at_updated_at_expired_at("ix_vehicle_created_at_updated_at_expired_at"),
436
+ revision_model_mixin.make_unique_index_record_sqn_revision("ix_u_vehicle_record_sqn_revision"),
437
+ revision_model_mixin.make_active_unique_index_record_sqn("ix_ua_vehicle_record_sqn"),
438
+ revision_model_mixin.make_active_unique_index_for("ix_ua_vehicle_vin_code", "vin_code"),
439
+ revision_model_mixin.make_active_unique_index_for("ix_ua_vehicle_asset_id", "asset_id"),
440
+ revision_model_mixin.make_active_unique_index_for("ix_ua_vehicle_name", "name"),
441
+ sa.Index("ix_vehicle_vin_code", "vin_code", postgresql_using="hash"),
442
+ sa.Index("ix_vehicle_asset_id", "asset_id", postgresql_using="hash"),
443
+ sa.Index("ix_vehicle_name", "name", postgresql_using="hash"),
444
+ )
445
+
446
+
447
+ class SensorTable(Sensor, make_revision_model_mixin(), table=True):
448
+ __tablename__ = "sensor"
449
+ __table_args__ = (
450
+ revision_model_mixin.make_index_created_at_updated_at_expired_at("ix_sensor_created_at_updated_at_expired_at"),
451
+ revision_model_mixin.make_unique_index_record_sqn_revision("ix_u_sensor_record_sqn_revision"),
452
+ revision_model_mixin.make_active_unique_index_record_sqn("ix_ua_sensor_record_sqn"),
453
+ revision_model_mixin.make_active_unique_index_for("ix_ua_sensor_uuid", "uuid"),
454
+ revision_model_mixin.make_active_unique_index_for("ix_ua_sensor_asset_id", "asset_id"),
455
+ sa.Index("ix_sensor_uuid", "uuid", postgresql_using="hash"),
456
+ sa.Index("ix_sensor_asset_id", "asset_id", postgresql_using="hash"),
457
+ )
458
+
459
+
460
+ class RegisteredBagTable(RegisteredBag, make_revision_model_mixin(), table=True):
461
+ __tablename__ = "registered_bag"
462
+ __table_args__ = (
463
+ revision_model_mixin.make_index_created_at_updated_at_expired_at(
464
+ "ix_registered_bag_created_at_updated_at_expired_at"),
465
+ revision_model_mixin.make_unique_index_record_sqn_revision("ix_u_registered_bag_record_sqn_revision"),
466
+ revision_model_mixin.make_active_unique_index_record_sqn("ix_ua_registered_bag_record_sqn"),
467
+ revision_model_mixin.make_active_unique_index_for("ix_ua_registered_bag_name", "name"),
468
+ sa.Index("ix_registered_bag_name", "name", postgresql_using="hash"),
469
+ sa.Index("ix_registered_bag_begin_at_end_at", "begin_at", "end_at"),
470
+ sa.Index("ix_registered_bag_file_checksum", "file_checksum", postgresql_using="hash"),
471
+ sa.Index("ix_registered_bag_tags", "tags", postgresql_using="gin"),
472
+ )
473
+
474
+
475
+ if typing.TYPE_CHECKING:
476
+ RegistryBase = SQLModel
477
+
478
+
479
+ class VehicleTemplateTable(RegistryBase, RevisionModelMixinProtocol):
480
+ uuid: sa_orm.Mapped[py_uuid.UUID] = ...
481
+ vehicle_type: sa_orm.Mapped[str] = ...
482
+ manufacturer: sa_orm.Mapped[str] = ...
483
+ model_name: sa_orm.Mapped[str] = ...
484
+ model_code: sa_orm.Mapped[str | None] = ...
485
+ production_stage: sa_orm.Mapped[str] = ...
486
+ specification: sa_orm.Mapped[JsonObject] = ...
487
+
488
+
489
+ class SensorTemplateTable(RegistryBase, RevisionModelMixinProtocol):
490
+ uuid: sa_orm.Mapped[py_uuid.UUID] = ...
491
+ sensor_type: sa_orm.Mapped[str] = ...
492
+ manufacturer: sa_orm.Mapped[str] = ...
493
+ model_name: sa_orm.Mapped[str] = ...
494
+ model_code: sa_orm.Mapped[str | None] = ...
495
+ production_stage: sa_orm.Mapped[str] = ...
496
+ specification: sa_orm.Mapped[JsonObject] = ...
497
+
498
+
499
+ class VehicleTable(RegistryBase, RevisionModelMixinProtocol):
500
+ vin_code: sa_orm.Mapped[str] = ...
501
+ asset_id: sa_orm.Mapped[str | None] = ...
502
+ vehicle_template_uuid: sa_orm.Mapped[py_uuid.UUID] = ...
503
+ name: sa_orm.Mapped[str] = ...
504
+ purchase_date: sa_orm.Mapped[datetime.date | None] = ...
505
+ tags: sa_orm.Mapped[list[str] | None] = ...
506
+
507
+
508
+ class SensorTable(RegistryBase, RevisionModelMixinProtocol):
509
+ uuid: sa_orm.Mapped[py_uuid.UUID] = ...
510
+ asset_id: sa_orm.Mapped[str | None] = ...
511
+ sensor_template_uuid: sa_orm.Mapped[py_uuid.UUID] = ...
512
+ serial_number: sa_orm.Mapped[str | None] = ...
513
+ purchase_date: sa_orm.Mapped[datetime.date | None] = ...
514
+ tags: sa_orm.Mapped[list[str] | None] = ...
515
+ props: sa_orm.Mapped[JsonObject | None] = ...
516
+
517
+
518
+ class RegisteredBagTable(RegistryBase, RevisionModelMixinProtocol):
519
+ name: sa_orm.Mapped[str] = ...
520
+ path: sa_orm.Mapped[str] = ...
521
+ vehicle_vin_code: sa_orm.Mapped[str] = ...
522
+ vehicle_name: sa_orm.Mapped[str] = ...
523
+ begin_at: sa_orm.Mapped[datetime.datetime] = ...
524
+ end_at: sa_orm.Mapped[datetime.datetime] = ...
525
+ file_size: sa_orm.Mapped[int] = ...
526
+ file_checksum: sa_orm.Mapped[str] = ...
527
+ flags: sa_orm.Mapped[int] = ...
528
+ tags: sa_orm.Mapped[list[str] | None] = ...
529
+ props: sa_orm.Mapped[JsonObject | None] = ...