Skip to content

Commit 680c5d6

Browse files
committed
fix: hydrate infra object in the sql registry proto() method
Signed-off-by: Achal Shah <achals@gmail.com>
1 parent 52a989b commit 680c5d6

1 file changed

Lines changed: 65 additions & 11 deletions

File tree

  • sdk/python/feast/infra/registry_stores

sdk/python/feast/infra/registry_stores/sql.py

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
from feast.feature_service import FeatureService
3333
from feast.feature_view import FeatureView
3434
from feast.infra.infra_object import Infra
35-
from feast.protos.feast.core.InfraObject_pb2 import Infra as InfraProto
3635
from feast.on_demand_feature_view import OnDemandFeatureView
3736
from feast.protos.feast.core.DataSource_pb2 import DataSource as DataSourceProto
3837
from feast.protos.feast.core.Entity_pb2 import Entity as EntityProto
@@ -149,6 +148,15 @@
149148
)
150149

151150

151+
feast_metadata = Table(
152+
"feast_metadata",
153+
metadata,
154+
Column("metadata_key", String(50), primary_key=True),
155+
Column("metadata_value", String(50), nullable=False),
156+
Column("last_updated_timestamp", BigInteger, nullable=False),
157+
)
158+
159+
152160
class SqlRegistry(BaseRegistry):
153161
def __init__(
154162
self, registry_config: Optional[RegistryConfig], repo_path: Optional[Path]
@@ -466,11 +474,16 @@ def apply_materialization(
466474
raise ValueError(
467475
f"Cannot apply materialization for feature {feature_view.name} of type {python_class}"
468476
)
469-
fv: Union[FeatureView, StreamFeatureView] = self._get_object(table, feature_view.name, project, proto_class,
470-
python_class,
471-
"feature_view_name",
472-
"feature_view_proto",
473-
FeatureViewNotFoundException)
477+
fv: Union[FeatureView, StreamFeatureView] = self._get_object(
478+
table,
479+
feature_view.name,
480+
project,
481+
proto_class,
482+
python_class,
483+
"feature_view_name",
484+
"feature_view_proto",
485+
FeatureViewNotFoundException,
486+
)
474487
fv.materialization_intervals.append((start_date, end_date))
475488
self._apply_object(table, "feature_view_name", fv, "feature_view_proto")
476489

@@ -571,7 +584,7 @@ def get_user_metadata(
571584
def proto(self) -> RegistryProto:
572585
r = RegistryProto()
573586
project = ""
574-
# TODO(achal): Support Infra object, and last_updated_timestamp.
587+
# TODO(achal): Support last_updated_timestamp.
575588
for lister, registry_proto_field in [
576589
(self.list_entities, r.entities),
577590
(self.list_feature_views, r.feature_views),
@@ -587,16 +600,18 @@ def proto(self) -> RegistryProto:
587600
if objs:
588601
registry_proto_field.extend([obj.to_proto() for obj in objs])
589602

603+
r.infra.CopyFrom(self.get_infra(project).to_proto())
604+
last_update_timestamp = self._get_last_updated_metadata()
605+
if last_update_timestamp:
606+
r.last_updated.FromDatetime(last_update_timestamp)
607+
590608
return r
591609

592610
def commit(self):
593611
# This method is a no-op since we're always writing values eagerly to the db.
594612
pass
595613

596-
def _apply_object(
597-
self, table, id_field_name, obj, proto_field_name,
598-
name=None
599-
):
614+
def _apply_object(self, table, id_field_name, obj, proto_field_name, name=None):
600615
name = name or obj.name
601616
with self.engine.connect() as conn:
602617
stmt = select(table).where(getattr(table.c, id_field_name) == name)
@@ -625,13 +640,15 @@ def _apply_object(
625640
}
626641
insert_stmt = insert(table).values(values,)
627642
conn.execute(insert_stmt)
643+
self._set_last_updated_metadata(update_datetime)
628644

629645
def _delete_object(self, table, name, project, id_field_name, not_found_exception):
630646
with self.engine.connect() as conn:
631647
stmt = delete(table).where(getattr(table.c, id_field_name) == name)
632648
rows = conn.execute(stmt)
633649
if rows.rowcount < 1 and not_found_exception:
634650
raise not_found_exception(name, project)
651+
self._set_last_updated_metadata(datetime.utcnow())
635652
return rows.rowcount
636653

637654
def _get_object(
@@ -665,3 +682,40 @@ def _list_objects(self, table, proto_class, python_class, proto_field_name):
665682
for row in rows
666683
]
667684
return []
685+
686+
def _set_last_updated_metadata(self, last_updated: datetime):
687+
with self.engine.connect() as conn:
688+
stmt = select(feast_metadata).where(
689+
feast_metadata.c.metadata_key == "last_updated_timestamp"
690+
)
691+
row = conn.execute(stmt).first()
692+
693+
update_time = int(last_updated.timestamp())
694+
695+
values = {
696+
"metadata_key": "last_updated_timestamp",
697+
"metadata_value": f"{update_time}",
698+
"last_updated_timestamp": update_time,
699+
}
700+
if row:
701+
update_stmt = (
702+
update(feast_metadata)
703+
.where(feast_metadata.c.metadata_key == "last_updated_timestamp")
704+
.values(values)
705+
)
706+
conn.execute(update_stmt)
707+
else:
708+
insert_stmt = insert(feast_metadata).values(values,)
709+
conn.execute(insert_stmt)
710+
711+
def _get_last_updated_metadata(self):
712+
with self.engine.connect() as conn:
713+
stmt = select(feast_metadata).where(
714+
feast_metadata.c.metadata_key == "last_updated_timestamp"
715+
)
716+
row = conn.execute(stmt).first()
717+
if not row:
718+
return None
719+
update_time = int(row["last_updated_timestamp"])
720+
721+
return datetime.utcfromtimestamp(update_time)

0 commit comments

Comments
 (0)