11from dataclasses import dataclass
2- from typing import Any , List
2+ from typing import Any , Iterable , List , Tuple , TypeVar
33
44from feast .diff .property_diff import PropertyDiff , TransitionType
5+ from feast .infra .infra_object import (
6+ DATASTORE_INFRA_OBJECT_CLASS_TYPE ,
7+ DYNAMODB_INFRA_OBJECT_CLASS_TYPE ,
8+ SQLITE_INFRA_OBJECT_CLASS_TYPE ,
9+ InfraObject ,
10+ )
11+ from feast .protos .feast .core .DatastoreTable_pb2 import (
12+ DatastoreTable as DatastoreTableProto ,
13+ )
14+ from feast .protos .feast .core .DynamoDBTable_pb2 import (
15+ DynamoDBTable as DynamoDBTableProto ,
16+ )
17+ from feast .protos .feast .core .InfraObject_pb2 import Infra as InfraProto
18+ from feast .protos .feast .core .SqliteTable_pb2 import SqliteTable as SqliteTableProto
519
620
721@dataclass
822class InfraObjectDiff :
923 name : str
1024 infra_object_type : str
11- current_fco : Any
12- new_fco : Any
13- fco_property_diffs : List [PropertyDiff ]
25+ current_infra_object : Any
26+ new_infra_object : Any
27+ infra_object_property_diffs : List [PropertyDiff ]
1428 transition_type : TransitionType
1529
1630
@@ -26,3 +40,117 @@ def update(self):
2640
2741 def to_string (self ):
2842 pass
43+
44+
45+ U = TypeVar ("U" , DatastoreTableProto , DynamoDBTableProto , SqliteTableProto )
46+
47+
48+ def tag_infra_proto_objects_for_keep_delete_add (
49+ existing_objs : Iterable [U ], desired_objs : Iterable [U ]
50+ ) -> Tuple [Iterable [U ], Iterable [U ], Iterable [U ]]:
51+ existing_obj_names = {e .name for e in existing_objs }
52+ desired_obj_names = {e .name for e in desired_objs }
53+
54+ objs_to_add = [e for e in desired_objs if e .name not in existing_obj_names ]
55+ objs_to_keep = [e for e in desired_objs if e .name in existing_obj_names ]
56+ objs_to_delete = [e for e in existing_objs if e .name not in desired_obj_names ]
57+
58+ return objs_to_keep , objs_to_delete , objs_to_add
59+
60+
61+ def diff_infra_protos (
62+ current_infra_proto : InfraProto , new_infra_proto : InfraProto
63+ ) -> InfraDiff :
64+ infra_diff = InfraDiff ()
65+
66+ infra_object_class_types_to_str = {
67+ DATASTORE_INFRA_OBJECT_CLASS_TYPE : "datastore table" ,
68+ DYNAMODB_INFRA_OBJECT_CLASS_TYPE : "dynamodb table" ,
69+ SQLITE_INFRA_OBJECT_CLASS_TYPE : "sqlite table" ,
70+ }
71+
72+ for infra_object_class_type in infra_object_class_types_to_str :
73+ current_infra_objects = get_infra_object_protos_by_type (
74+ current_infra_proto , infra_object_class_type
75+ )
76+ new_infra_objects = get_infra_object_protos_by_type (
77+ new_infra_proto , infra_object_class_type
78+ )
79+ (
80+ infra_objects_to_keep ,
81+ infra_objects_to_delete ,
82+ infra_objects_to_add ,
83+ ) = tag_infra_proto_objects_for_keep_delete_add (
84+ current_infra_objects , new_infra_objects ,
85+ )
86+
87+ for e in infra_objects_to_add :
88+ infra_diff .infra_object_diffs .append (
89+ InfraObjectDiff (
90+ e .name ,
91+ infra_object_class_types_to_str [infra_object_class_type ],
92+ None ,
93+ e ,
94+ [],
95+ TransitionType .CREATE ,
96+ )
97+ )
98+ for e in infra_objects_to_delete :
99+ infra_diff .infra_object_diffs .append (
100+ InfraObjectDiff (
101+ e .name ,
102+ infra_object_class_types_to_str [infra_object_class_type ],
103+ e ,
104+ None ,
105+ [],
106+ TransitionType .DELETE ,
107+ )
108+ )
109+ for e in infra_objects_to_keep :
110+ current_infra_object = [
111+ _e for _e in current_infra_objects if _e .name == e .name
112+ ][0 ]
113+ infra_diff .infra_object_diffs .append (
114+ diff_between (
115+ current_infra_object ,
116+ e ,
117+ infra_object_class_types_to_str [infra_object_class_type ],
118+ )
119+ )
120+
121+ return infra_diff
122+
123+
124+ def get_infra_object_protos_by_type (
125+ infra_proto : InfraProto , infra_object_class_type : str
126+ ) -> List [U ]:
127+ return [
128+ InfraObject .from_infra_object_proto (infra_object ).to_proto ()
129+ for infra_object in infra_proto .infra_objects
130+ if infra_object .infra_object_class_type == infra_object_class_type
131+ ]
132+
133+
134+ FIELDS_TO_IGNORE = {"project" }
135+
136+
137+ def diff_between (current : U , new : U , infra_object_type : str ) -> InfraObjectDiff :
138+ assert current .DESCRIPTOR .full_name == new .DESCRIPTOR .full_name
139+ property_diffs = []
140+ transition : TransitionType = TransitionType .UNCHANGED
141+ if current != new :
142+ for _field in current .DESCRIPTOR .fields :
143+ if _field .name in FIELDS_TO_IGNORE :
144+ continue
145+ if getattr (current , _field .name ) != getattr (new , _field .name ):
146+ transition = TransitionType .UPDATE
147+ property_diffs .append (
148+ PropertyDiff (
149+ _field .name ,
150+ getattr (current , _field .name ),
151+ getattr (new , _field .name ),
152+ )
153+ )
154+ return InfraObjectDiff (
155+ new .name , infra_object_type , current , new , property_diffs , transition ,
156+ )
0 commit comments