corvic-engine 0.3.0rc55__cp38-abi3-win_amd64.whl → 0.3.0rc57__cp38-abi3-win_amd64.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.
@@ -1,6 +1,6 @@
1
1
  import datetime
2
2
  from collections.abc import Callable, Sequence
3
- from typing import Any, Protocol, TypeVar, cast
3
+ from typing import Any, Protocol, TypeVar
4
4
 
5
5
  import sqlalchemy as sa
6
6
  import sqlalchemy.orm as sa_orm
@@ -14,26 +14,30 @@ from corvic_generated.orm.v1 import feature_view_pb2
14
14
 
15
15
  UNCOMMITTED_ID_PREFIX = "__uncommitted_object-"
16
16
 
17
- _Proto = TypeVar(
18
- "_Proto",
19
- models_pb2.Resource,
20
- models_pb2.Source,
21
- models_pb2.FeatureView,
22
- models_pb2.Space,
23
- models_pb2.FeatureViewSource,
24
- models_pb2.Agent,
25
- models_pb2.Pipeline,
26
- models_pb2.Room,
27
- models_pb2.CompletionModel,
28
- )
29
17
  ID = TypeVar("ID", bound=orm.BaseID[Any])
30
18
 
31
19
 
20
+ class _ModelProto(Protocol):
21
+ id: str
22
+ created_at: timestamp_pb2.Timestamp
23
+
24
+
25
+ class _ModelBelongsToOrgProto(_ModelProto, Protocol):
26
+ org_id: str
27
+
28
+
29
+ class _ModelBelongsToRoomProto(_ModelBelongsToOrgProto, Protocol):
30
+ room_id: str
31
+
32
+
33
+ ProtoObj = TypeVar("ProtoObj", bound=_ModelProto)
34
+ ProtoBelongsToOrgObj = TypeVar("ProtoBelongsToOrgObj", bound=_ModelBelongsToOrgProto)
35
+ ProtoBelongsToRoomObj = TypeVar("ProtoBelongsToRoomObj", bound=_ModelBelongsToRoomProto)
36
+
37
+
32
38
  class _OrmModel(Protocol[ID]):
33
39
  id: sa_orm.Mapped[ID | None]
34
40
 
35
- org_id: sa_orm.Mapped[orm.OrgID | None]
36
-
37
41
  @sa.ext.hybrid.hybrid_property
38
42
  def created_at(self) -> datetime.datetime | None: ...
39
43
 
@@ -42,7 +46,17 @@ class _OrmModel(Protocol[ID]):
42
46
  def _created_at_expression(cls): ...
43
47
 
44
48
 
49
+ class _OrmBelongsToOrgModel(_OrmModel[ID], Protocol):
50
+ org_id: sa_orm.Mapped[orm.OrgID | None]
51
+
52
+
53
+ class _OrmBelongsToRoomModel(_OrmBelongsToOrgModel[ID], Protocol):
54
+ room_id: sa_orm.Mapped[orm.RoomID | None]
55
+
56
+
45
57
  OrmObj = TypeVar("OrmObj", bound=_OrmModel[Any])
58
+ OrmBelongsToOrgObj = TypeVar("OrmBelongsToOrgObj", bound=_OrmBelongsToOrgModel[Any])
59
+ OrmBelongsToRoomObj = TypeVar("OrmBelongsToRoomObj", bound=_OrmBelongsToRoomModel[Any])
46
60
 
47
61
 
48
62
  def _translate_orm_id(
@@ -58,39 +72,6 @@ def _translate_orm_id(
58
72
  return Ok(parsed_obj_id)
59
73
 
60
74
 
61
- def _translate_orm_ids(
62
- proto_obj: _Proto, obj_id_class: type[ID]
63
- ) -> Ok[tuple[ID | None, orm.RoomID | None]] | orm.InvalidORMIdentifierError:
64
- match _translate_orm_id(proto_obj.id, obj_id_class):
65
- case orm.InvalidORMIdentifierError() as err:
66
- return err
67
- case Ok(obj_id):
68
- pass
69
-
70
- match proto_obj:
71
- case (
72
- models_pb2.Resource()
73
- | models_pb2.Source()
74
- | models_pb2.FeatureView()
75
- | models_pb2.Space()
76
- | models_pb2.Agent()
77
- | models_pb2.Pipeline()
78
- | models_pb2.FeatureViewSource()
79
- ):
80
- room_id = orm.RoomID(proto_obj.room_id)
81
- match room_id.to_db():
82
- case orm.InvalidORMIdentifierError() as err:
83
- return err
84
- case Ok():
85
- pass
86
- case models_pb2.CompletionModel():
87
- room_id = None
88
- case models_pb2.Room():
89
- room_id = cast(orm.RoomID, obj_id)
90
-
91
- return Ok((obj_id, room_id))
92
-
93
-
94
75
  def timestamp_orm_to_proto(
95
76
  timestamp_orm: datetime.datetime | None,
96
77
  ) -> timestamp_pb2.Timestamp | None:
@@ -247,43 +228,51 @@ def completion_model_orm_to_proto(
247
228
  )
248
229
 
249
230
 
250
- def _add_orm_to_session(
251
- orm_obj: OrmObj, org_id: str, session: sa_orm.Session
252
- ) -> OrmObj:
253
- if org_id:
254
- orm_obj.org_id = orm.OrgID(org_id)
231
+ def add_orm_org_mixin_to_session(
232
+ orm_obj: OrmBelongsToOrgObj,
233
+ proto_obj: _ModelBelongsToOrgProto,
234
+ id_class: type[ID],
235
+ session: sa_orm.Session,
236
+ ) -> Ok[OrmBelongsToOrgObj] | orm.InvalidORMIdentifierError:
237
+ match _translate_orm_id(proto_obj.id, id_class):
238
+ case Ok(orm_id):
239
+ orm_obj.id = orm_id
240
+ case orm.InvalidORMIdentifierError() as err:
241
+ return err
242
+ if proto_obj.org_id:
243
+ org_id = orm.OrgID(proto_obj.org_id)
244
+ match org_id.to_db():
245
+ case Ok():
246
+ orm_obj.org_id = org_id
247
+ case orm.InvalidORMIdentifierError() as err:
248
+ return err
249
+ orm_obj.org_id = org_id
255
250
  if not orm_obj.id:
256
251
  session.add(orm_obj)
257
252
  else:
258
253
  orm_obj = session.merge(orm_obj)
259
- return orm_obj
254
+ return Ok(orm_obj)
260
255
 
261
256
 
262
- def resource_proto_to_orm(
263
- proto_obj: models_pb2.Resource, session: sa_orm.Session
264
- ) -> Ok[orm.Resource] | InvalidArgumentError:
265
- match _translate_orm_ids(proto_obj, orm.ResourceID):
257
+ def add_orm_room_mixin_to_session(
258
+ orm_obj: OrmBelongsToRoomObj,
259
+ proto_obj: _ModelBelongsToRoomProto,
260
+ id_class: type[ID],
261
+ session: sa_orm.Session,
262
+ ) -> Ok[OrmBelongsToRoomObj] | orm.InvalidORMIdentifierError:
263
+ room_id = orm.RoomID(proto_obj.room_id)
264
+ match room_id.to_db():
265
+ case Ok():
266
+ pass
266
267
  case orm.InvalidORMIdentifierError() as err:
267
268
  return err
268
- case Ok((obj_id, room_id)):
269
- pass
270
- if not room_id:
271
- return InvalidArgumentError("room id required to commit")
269
+ orm_obj.room_id = orm.RoomID(proto_obj.room_id)
270
+ return add_orm_org_mixin_to_session(orm_obj, proto_obj, id_class, session)
272
271
 
273
- orm_obj = orm.Resource(
274
- id=obj_id,
275
- name=proto_obj.name,
276
- description=proto_obj.description,
277
- mime_type=proto_obj.mime_type,
278
- md5=proto_obj.md5,
279
- url=proto_obj.url,
280
- size=proto_obj.size,
281
- original_path=proto_obj.original_path,
282
- latest_event=proto_obj.recent_events[-1] if proto_obj.recent_events else None,
283
- room_id=room_id,
284
- )
285
- _add_orm_to_session(orm_obj, proto_obj.org_id, session)
286
272
 
273
+ def _resource_pipeline_to_orm(
274
+ proto_obj: models_pb2.Resource, orm_obj: orm.Resource, session: sa_orm.Session
275
+ ) -> Ok[None] | InvalidArgumentError:
287
276
  if proto_obj.pipeline_id:
288
277
  match _translate_orm_id(proto_obj.pipeline_id, orm.PipelineID):
289
278
  case orm.InvalidORMIdentifierError() as err:
@@ -299,18 +288,41 @@ def resource_proto_to_orm(
299
288
  resource_id=orm_obj.id,
300
289
  name=proto_obj.pipeline_input_name,
301
290
  pipeline_id=pipeline_id,
302
- room_id=room_id,
291
+ room_id=orm_obj.room_id,
303
292
  )
304
293
  if orm_obj.org_id:
305
294
  pipeline_input.org_id = orm_obj.org_id
306
295
  orm_obj.pipeline_ref = session.merge(pipeline_input)
296
+ return Ok(None)
307
297
 
308
- return Ok(orm_obj)
298
+
299
+ def resource_proto_to_orm(
300
+ proto_obj: models_pb2.Resource, session: sa_orm.Session
301
+ ) -> Ok[orm.Resource] | InvalidArgumentError:
302
+ orm_obj = orm.Resource(
303
+ name=proto_obj.name,
304
+ description=proto_obj.description,
305
+ mime_type=proto_obj.mime_type,
306
+ md5=proto_obj.md5,
307
+ url=proto_obj.url,
308
+ size=proto_obj.size,
309
+ original_path=proto_obj.original_path,
310
+ latest_event=proto_obj.recent_events[-1] if proto_obj.recent_events else None,
311
+ )
312
+ add_orm_room_mixin_to_session(orm_obj, proto_obj, orm.ResourceID, session)
313
+
314
+ match _resource_pipeline_to_orm(proto_obj, orm_obj, session):
315
+ case Ok(None):
316
+ return Ok(orm_obj)
317
+ case InvalidArgumentError() as err:
318
+ return err
309
319
 
310
320
 
311
321
  def _ensure_id(
312
- proto_obj: _Proto,
313
- proto_to_orm: Callable[[_Proto, sa_orm.Session], Ok[OrmObj] | InvalidArgumentError],
322
+ proto_obj: ProtoObj,
323
+ proto_to_orm: Callable[
324
+ [ProtoObj, sa_orm.Session], Ok[OrmObj] | InvalidArgumentError
325
+ ],
314
326
  id_type: type[ID],
315
327
  session: sa_orm.Session,
316
328
  ) -> Ok[ID] | orm.InvalidORMIdentifierError | InvalidArgumentError:
@@ -333,23 +345,19 @@ def _ensure_id(
333
345
  def pipeline_proto_to_orm( # noqa: C901
334
346
  proto_obj: models_pb2.Pipeline, session: sa_orm.Session
335
347
  ) -> Ok[orm.Pipeline] | orm.InvalidORMIdentifierError | InvalidArgumentError:
336
- match _translate_orm_ids(proto_obj, orm.PipelineID):
337
- case orm.InvalidORMIdentifierError() as err:
338
- return err
339
- case Ok((obj_id, room_id)):
340
- pass
341
- if not room_id:
342
- return InvalidArgumentError("room id required to commit")
343
-
344
348
  inputs = list[orm.PipelineInput]()
345
349
  orm_obj = orm.Pipeline(
346
- id=obj_id,
347
350
  name=proto_obj.name,
348
- room_id=room_id,
349
351
  transformation=proto_obj.pipeline_transformation,
350
352
  description=proto_obj.description,
351
353
  )
352
- orm_obj = _add_orm_to_session(orm_obj, proto_obj.org_id, session)
354
+ if proto_obj.org_id:
355
+ orm_obj.org_id = orm.OrgID(proto_obj.org_id)
356
+ match add_orm_room_mixin_to_session(orm_obj, proto_obj, orm.PipelineID, session):
357
+ case Ok(orm_obj):
358
+ pass
359
+ case orm.InvalidORMIdentifierError() as err:
360
+ return err
353
361
  session.flush()
354
362
 
355
363
  if not orm_obj.id:
@@ -364,7 +372,10 @@ def pipeline_proto_to_orm( # noqa: C901
364
372
  pass
365
373
  outputs.append(
366
374
  orm.PipelineOutput(
367
- source_id=source_id, name=name, pipeline_id=orm_obj.id, room_id=room_id
375
+ source_id=source_id,
376
+ name=name,
377
+ pipeline_id=orm_obj.id,
378
+ room_id=orm_obj.room_id,
368
379
  )
369
380
  )
370
381
 
@@ -380,21 +391,11 @@ def pipeline_proto_to_orm( # noqa: C901
380
391
  def source_proto_to_orm(
381
392
  proto_obj: models_pb2.Source, session: sa_orm.Session
382
393
  ) -> Ok[orm.Source] | orm.InvalidORMIdentifierError | InvalidArgumentError:
383
- match _translate_orm_ids(proto_obj, orm.SourceID):
384
- case orm.InvalidORMIdentifierError() as err:
385
- return err
386
- case Ok((obj_id, room_id)):
387
- pass
388
- if not room_id:
389
- return InvalidArgumentError("room id required to commit")
390
-
391
394
  orm_obj = orm.Source(
392
- id=obj_id,
393
395
  name=proto_obj.name,
394
396
  table_op_graph=proto_obj.table_op_graph,
395
- room_id=room_id,
396
397
  )
397
- return Ok(_add_orm_to_session(orm_obj, proto_obj.org_id, session))
398
+ return add_orm_room_mixin_to_session(orm_obj, proto_obj, orm.SourceID, session)
398
399
 
399
400
 
400
401
  def _update_agent_associations(
@@ -431,21 +432,15 @@ def _update_agent_associations(
431
432
  def agent_proto_to_orm(
432
433
  proto_obj: models_pb2.Agent, session: sa_orm.Session
433
434
  ) -> Ok[orm.Agent] | orm.InvalidORMIdentifierError | InvalidArgumentError:
434
- match _translate_orm_ids(proto_obj, orm.AgentID):
435
- case orm.InvalidORMIdentifierError() as err:
436
- return err
437
- case Ok((obj_id, room_id)):
438
- pass
439
- if not room_id:
440
- return InvalidArgumentError("room id required to commit")
441
-
442
435
  orm_obj = orm.Agent(
443
- id=obj_id,
444
436
  name=proto_obj.name,
445
437
  parameters=proto_obj.agent_parameters,
446
- room_id=room_id,
447
438
  )
448
- agent = _add_orm_to_session(orm_obj, proto_obj.org_id, session)
439
+ match add_orm_room_mixin_to_session(orm_obj, proto_obj, orm.AgentID, session):
440
+ case Ok(agent):
441
+ pass
442
+ case orm.InvalidORMIdentifierError() as err:
443
+ return err
449
444
  session.flush()
450
445
 
451
446
  if not agent.id:
@@ -462,14 +457,6 @@ def agent_proto_to_orm(
462
457
  def space_proto_to_orm(
463
458
  proto_obj: models_pb2.Space, session: sa_orm.Session
464
459
  ) -> Ok[orm.Space] | orm.InvalidORMIdentifierError | InvalidArgumentError:
465
- match _translate_orm_ids(proto_obj, orm.SpaceID):
466
- case orm.InvalidORMIdentifierError() as err:
467
- return err
468
- case Ok((obj_id, room_id)):
469
- pass
470
- if not room_id:
471
- return InvalidArgumentError("room id required to commit")
472
-
473
460
  match _ensure_id(
474
461
  proto_obj.feature_view, feature_view_proto_to_orm, orm.FeatureViewID, session
475
462
  ):
@@ -482,38 +469,29 @@ def space_proto_to_orm(
482
469
  raise InternalError("internal assertion did not hold")
483
470
 
484
471
  orm_obj = orm.Space(
485
- id=obj_id,
486
472
  name=proto_obj.name,
487
473
  description=proto_obj.description,
488
- room_id=room_id,
489
474
  feature_view_id=feature_view_id,
490
475
  parameters=proto_obj.space_parameters,
491
476
  auto_sync=proto_obj.auto_sync,
492
477
  )
493
- return Ok(_add_orm_to_session(orm_obj, proto_obj.org_id, session))
478
+ return add_orm_room_mixin_to_session(orm_obj, proto_obj, orm.SpaceID, session)
494
479
 
495
480
 
496
- def feature_view_proto_to_orm( # noqa: C901
481
+ def feature_view_proto_to_orm(
497
482
  proto_obj: models_pb2.FeatureView, session: sa_orm.Session
498
483
  ) -> Ok[orm.FeatureView] | orm.InvalidORMIdentifierError | InvalidArgumentError:
499
- match _translate_orm_ids(proto_obj, orm.FeatureViewID):
500
- case orm.InvalidORMIdentifierError() as err:
501
- return err
502
- case Ok((obj_id, room_id)):
503
- pass
504
- if not room_id:
505
- return InvalidArgumentError("room id required to commit")
506
-
507
484
  orm_obj = orm.FeatureView(
508
- id=obj_id,
509
485
  name=proto_obj.name,
510
486
  description=proto_obj.description,
511
- room_id=room_id,
512
487
  )
513
488
  if proto_obj.org_id:
514
489
  orm_obj.org_id = orm.OrgID(proto_obj.org_id)
515
-
516
- orm_obj = _add_orm_to_session(orm_obj, proto_obj.org_id, session)
490
+ match add_orm_room_mixin_to_session(orm_obj, proto_obj, orm.FeatureViewID, session):
491
+ case Ok(orm_obj):
492
+ pass
493
+ case orm.InvalidORMIdentifierError() as err:
494
+ return err
517
495
  session.flush()
518
496
 
519
497
  if not orm_obj.id:
@@ -573,57 +551,38 @@ def _feature_view_source_proto_to_orm(
573
551
  return err
574
552
  case Ok(source_id):
575
553
  pass
576
- match _translate_orm_id(proto_obj.id, orm.FeatureViewSourceID):
577
- case orm.InvalidORMIdentifierError() as err:
578
- return err
579
- case Ok(obj_id):
580
- pass
581
554
 
582
555
  orm_obj = orm.FeatureViewSource(
583
- room_id=orm.RoomID(proto_obj.room_id),
584
- id=obj_id,
585
556
  table_op_graph=proto_obj.table_op_graph,
586
557
  drop_disconnected=proto_obj.drop_disconnected,
587
558
  source_id=source_id,
588
559
  feature_view_id=feature_view_id,
589
560
  )
590
- return Ok(_add_orm_to_session(orm_obj, proto_obj.org_id, session))
561
+ return add_orm_room_mixin_to_session(
562
+ orm_obj, proto_obj, orm.FeatureViewSourceID, session
563
+ )
591
564
 
592
565
 
593
566
  def room_proto_to_orm(
594
567
  proto_obj: models_pb2.Room, session: sa_orm.Session
595
568
  ) -> Ok[orm.Room] | orm.InvalidORMIdentifierError | InvalidArgumentError:
596
- match _translate_orm_ids(proto_obj, orm.RoomID):
597
- case orm.InvalidORMIdentifierError() as err:
598
- return err
599
- case Ok((obj_id, _)):
600
- pass
601
-
602
- orm_obj = orm.Room(
603
- id=obj_id,
604
- name=proto_obj.name,
605
- )
606
- return Ok(_add_orm_to_session(orm_obj, proto_obj.org_id, session))
569
+ orm_obj = orm.Room(name=proto_obj.name)
570
+ return add_orm_org_mixin_to_session(orm_obj, proto_obj, orm.RoomID, session)
607
571
 
608
572
 
609
573
  def completion_model_proto_to_orm(
610
574
  proto_obj: models_pb2.CompletionModel, session: sa_orm.Session
611
575
  ) -> Ok[orm.CompletionModel] | InvalidArgumentError:
612
- match _translate_orm_ids(proto_obj, orm.CompletionModelID):
613
- case orm.InvalidORMIdentifierError() as err:
614
- return err
615
- case Ok((obj_id, _)):
616
- pass
617
-
618
576
  orm_obj = orm.CompletionModel(
619
- id=obj_id,
620
577
  name=proto_obj.name,
621
578
  description=proto_obj.description,
622
579
  parameters=proto_obj.parameters,
623
580
  secret_api_key=proto_obj.secret_api_key,
624
581
  last_validation_time=proto_obj.last_validation_time.ToDatetime(),
625
582
  )
626
- return Ok(_add_orm_to_session(orm_obj, proto_obj.org_id, session))
583
+ return add_orm_org_mixin_to_session(
584
+ orm_obj, proto_obj, orm.CompletionModelID, session
585
+ )
627
586
 
628
587
 
629
588
  def source_delete_orms(
corvic/model/_resource.py CHANGED
@@ -15,7 +15,7 @@ from sqlalchemy.orm.interfaces import LoaderOption
15
15
  from typing_extensions import Self
16
16
 
17
17
  from corvic import orm, system
18
- from corvic.model._base_model import BaseModel
18
+ from corvic.model._base_model import BelongsToRoomModel
19
19
  from corvic.model._defaults import Defaults
20
20
  from corvic.model._proto_orm_convert import (
21
21
  resource_delete_orms,
@@ -32,7 +32,7 @@ RoomID: TypeAlias = orm.RoomID
32
32
  PipelineID: TypeAlias = orm.PipelineID
33
33
 
34
34
 
35
- class Resource(BaseModel[ResourceID, models_pb2.Resource, orm.Resource]):
35
+ class Resource(BelongsToRoomModel[ResourceID, models_pb2.Resource, orm.Resource]):
36
36
  """Resources represent import data."""
37
37
 
38
38
  @classmethod
@@ -67,10 +67,6 @@ class Resource(BaseModel[ResourceID, models_pb2.Resource, orm.Resource]):
67
67
  def name(self) -> str:
68
68
  return self.proto_self.name
69
69
 
70
- @property
71
- def room_id(self) -> RoomID:
72
- return RoomID(self.proto_self.room_id)
73
-
74
70
  @property
75
71
  def pipeline_id(self) -> PipelineID | None:
76
72
  return PipelineID(self.proto_self.pipeline_id) or None
corvic/model/_room.py CHANGED
@@ -8,7 +8,7 @@ from typing import TypeAlias
8
8
  import structlog
9
9
 
10
10
  from corvic import orm, system
11
- from corvic.model._base_model import BaseModel
11
+ from corvic.model._base_model import BelongsToOrgModel
12
12
  from corvic.model._defaults import Defaults
13
13
  from corvic.model._proto_orm_convert import (
14
14
  room_delete_orms,
@@ -25,7 +25,7 @@ RoomID: TypeAlias = orm.RoomID
25
25
  FeatureViewID: TypeAlias = orm.FeatureViewID
26
26
 
27
27
 
28
- class Room(BaseModel[RoomID, models_pb2.Room, orm.Room]):
28
+ class Room(BelongsToOrgModel[RoomID, models_pb2.Room, orm.Room]):
29
29
  """Rooms contain conversations and tables."""
30
30
 
31
31
  @classmethod
corvic/model/_source.py CHANGED
@@ -15,7 +15,7 @@ from sqlalchemy.orm.interfaces import LoaderOption
15
15
  from typing_extensions import Self
16
16
 
17
17
  from corvic import op_graph, orm, system
18
- from corvic.model._base_model import BaseModel
18
+ from corvic.model._base_model import BelongsToRoomModel
19
19
  from corvic.model._defaults import Defaults
20
20
  from corvic.model._proto_orm_convert import (
21
21
  source_delete_orms,
@@ -46,7 +46,7 @@ def foreign_key(
46
46
  )
47
47
 
48
48
 
49
- class Source(BaseModel[SourceID, models_pb2.Source, orm.Source]):
49
+ class Source(BelongsToRoomModel[SourceID, models_pb2.Source, orm.Source]):
50
50
  """Sources describe how resources should be treated.
51
51
 
52
52
  Example:
@@ -269,14 +269,18 @@ class Source(BaseModel[SourceID, models_pb2.Source, orm.Source]):
269
269
  self.client, op_graph.op.from_proto(self.proto_self.table_op_graph)
270
270
  )
271
271
 
272
+ @functools.cached_property
273
+ def prop_table(self):
274
+ if self.proto_self.prop_table_op_graph is None:
275
+ return None
276
+ return Table.from_ops(
277
+ self.client, op_graph.op.from_proto(self.proto_self.prop_table_op_graph)
278
+ )
279
+
272
280
  @property
273
281
  def name(self) -> str:
274
282
  return self.proto_self.name
275
283
 
276
- @property
277
- def room_id(self) -> RoomID:
278
- return RoomID(self.proto_self.room_id)
279
-
280
284
  @property
281
285
  def pipeline_id(self) -> PipelineID | None:
282
286
  return PipelineID(self.proto_self.pipeline_id) or None
corvic/model/_space.py CHANGED
@@ -14,7 +14,7 @@ from sqlalchemy import orm as sa_orm
14
14
  from typing_extensions import Self
15
15
 
16
16
  from corvic import op_graph, orm, system
17
- from corvic.model._base_model import BaseModel
17
+ from corvic.model._base_model import BelongsToRoomModel
18
18
  from corvic.model._defaults import Defaults
19
19
  from corvic.model._feature_view import FeatureView, FeatureViewEdgeTableMetadata
20
20
  from corvic.model._proto_orm_convert import (
@@ -61,7 +61,7 @@ name_to_proto_image_model = {
61
61
  }
62
62
 
63
63
 
64
- class Space(BaseModel[SpaceID, models_pb2.Space, orm.Space]):
64
+ class Space(BelongsToRoomModel[SpaceID, models_pb2.Space, orm.Space]):
65
65
  """Spaces apply embedding methods to FeatureViews.
66
66
 
67
67
  Example:
@@ -105,10 +105,6 @@ class Space(BaseModel[SpaceID, models_pb2.Space, orm.Space]):
105
105
  def name(self):
106
106
  return self.proto_self.name
107
107
 
108
- @property
109
- def room_id(self):
110
- return RoomID(self.proto_self.room_id)
111
-
112
108
  @property
113
109
  def description(self):
114
110
  return self.proto_self.description
@@ -840,13 +836,20 @@ class TabularSpace(Space):
840
836
  pa.string(),
841
837
  )
842
838
 
843
- op = (
844
- op.concat_list(
839
+ if len(embedding_column_tmp_names):
840
+ op = op.concat_list(
845
841
  column_names=embedding_column_tmp_names,
846
842
  concat_list_column_name=embedding_column_tmp_name,
843
+ ).and_then(reduce_dimension)
844
+ else:
845
+ op = op.add_literal_column(
846
+ column_name=embedding_column_tmp_name,
847
+ literal=[],
848
+ dtype=pa.large_list(pa.float32()),
849
+ ftype=op_graph.feature_type.embedding(),
847
850
  )
848
- .and_then(reduce_dimension)
849
- .and_then(select_columns)
851
+ op = (
852
+ op.and_then(select_columns)
850
853
  .and_then(update_feature_types)
851
854
  .and_then(rename_columns)
852
855
  .and_then(add_literal_column)
@@ -2,8 +2,6 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from collections.abc import Sequence
6
-
7
5
  import polars as pl
8
6
  import pyarrow as pa
9
7
 
@@ -14,7 +12,7 @@ from corvic.op_graph.feature_types import FeatureType
14
12
 
15
13
  def _infer_possible_feature_types(
16
14
  data_type: pa.DataType,
17
- ) -> Sequence[FeatureType]:
15
+ ) -> list[FeatureType]:
18
16
  if pa.types.is_integer(data_type):
19
17
  # TODO(thunt): Add multi-categorical in future versions
20
18
  return [
@@ -168,6 +166,6 @@ class Field:
168
166
  def rename(self, new_name: str) -> Field:
169
167
  return Field(new_name, self.dtype, self.ftype)
170
168
 
171
- def possible_feature_types(self) -> Sequence[FeatureType]:
169
+ def possible_feature_types(self) -> list[FeatureType]:
172
170
  """Infer possible feature types given the data type."""
173
171
  return _infer_possible_feature_types(self.dtype)