@@ -4621,6 +4621,40 @@ def convert_or_ignore(rvid):
4621
4621
)
4622
4622
return out
4623
4623
4624
+ @classmethod
4625
+ async def set_deployed_multi (
4626
+ cls ,
4627
+ environment : uuid .UUID ,
4628
+ resource_ids : Sequence [m .ResourceIdStr ],
4629
+ version : int ,
4630
+ connection : Optional [asyncpg .connection .Connection ] = None ,
4631
+ ) -> None :
4632
+ query = "UPDATE resource SET status='deployed' WHERE environment=$1 AND model=$2 AND resource_id =ANY($3) "
4633
+ async with cls .get_connection (connection ) as connection :
4634
+ await connection .execute (query , environment , version , resource_ids )
4635
+
4636
+ @classmethod
4637
+ async def get_resource_ids_with_status (
4638
+ cls ,
4639
+ environment : uuid .UUID ,
4640
+ resource_version_ids : list [m .ResourceIdStr ],
4641
+ version : int ,
4642
+ statuses : Sequence [const .ResourceState ],
4643
+ lock : Optional [RowLockMode ] = None ,
4644
+ connection : Optional [asyncpg .connection .Connection ] = None ,
4645
+ ) -> list [m .ResourceIdStr ]:
4646
+ query = (
4647
+ "SELECT resource_id as resource_id FROM resource WHERE "
4648
+ "environment=$1 AND model=$2 AND status = ANY($3) and resource_id =ANY($4) "
4649
+ )
4650
+ if lock :
4651
+ query += lock .value
4652
+ async with cls .get_connection (connection ) as connection :
4653
+ return [
4654
+ m .ResourceIdStr (cast (str , r ["resource_id" ]))
4655
+ for r in await connection .fetch (query , environment , version , statuses , resource_version_ids )
4656
+ ]
4657
+
4624
4658
@classmethod
4625
4659
async def get_undeployable (cls , environment : uuid .UUID , version : int ) -> list ["Resource" ]:
4626
4660
"""
@@ -4794,29 +4828,42 @@ async def get_resources_for_version_raw_with_persistent_state(
4794
4828
cls ,
4795
4829
environment : uuid .UUID ,
4796
4830
version : int ,
4797
- projection : Optional [list [str ]],
4798
- projection_presistent : Optional [list [str ]],
4831
+ projection : Optional [list [typing .LiteralString ]],
4832
+ projection_presistent : Optional [list [typing .LiteralString ]],
4833
+ project_attributes : Optional [list [typing .LiteralString ]] = None ,
4799
4834
* ,
4800
4835
connection : Optional [Connection ] = None ,
4801
4836
) -> list [dict [str , object ]]:
4802
- """This method performs none of the mangling required to produce valid resources!"""
4837
+ """This method performs none of the mangling required to produce valid resources!
4838
+
4839
+ project_attributes performs a projection on the json attributes of the resources table
4840
+
4841
+ all projections must be disjoint, as they become named fields in the output record
4842
+ """
4803
4843
4804
4844
def collect_projection (projection : Optional [list [str ]], prefix : str ) -> str :
4805
4845
if not projection :
4806
4846
return f"{ prefix } .*"
4807
4847
else :
4808
4848
return "," .join (f"{ prefix } .{ field } " for field in projection )
4809
4849
4850
+ if project_attributes :
4851
+ json_projection = "," + "," .join (f"r.attributes->'{ v } ' as { v } " for v in project_attributes )
4852
+ else :
4853
+ json_projection = ""
4854
+
4810
4855
query = f"""
4811
- SELECT { collect_projection (projection , 'r' )} , { collect_projection (projection_presistent , 'ps' )}
4856
+ SELECT { collect_projection (projection , 'r' )} , { collect_projection (projection_presistent , 'ps' )} { json_projection }
4812
4857
FROM { cls .table_name ()} r JOIN resource_persistent_state ps ON r.resource_id = ps.resource_id
4813
4858
WHERE r.environment=$1 AND ps.environment = $1 and r.model = $2;"""
4814
4859
4815
4860
resource_records = await cls ._fetch_query (query , environment , version , connection = connection )
4816
4861
resources = [dict (record ) for record in resource_records ]
4817
4862
for res in resources :
4818
- if "attributes" in res :
4819
- res ["attributes" ] = json .loads (res ["attributes" ])
4863
+ if project_attributes :
4864
+ for k in project_attributes :
4865
+ if res [k ]:
4866
+ res [k ] = json .loads (res [k ])
4820
4867
return resources
4821
4868
4822
4869
@classmethod
@@ -5403,6 +5450,7 @@ async def get_list(
5403
5450
no_obj : Optional [bool ] = None ,
5404
5451
lock : Optional [RowLockMode ] = None ,
5405
5452
connection : Optional [asyncpg .connection .Connection ] = None ,
5453
+ no_status : bool = False , # don't load the status field
5406
5454
** query : object ,
5407
5455
) -> list ["ConfigurationModel" ]:
5408
5456
# sanitize and validate order parameters
@@ -5446,14 +5494,21 @@ async def get_list(
5446
5494
{ lock_statement } """
5447
5495
query_result = await cls ._fetch_query (query_string , * values , connection = connection )
5448
5496
result = []
5449
- for record in query_result :
5450
- record = dict (record )
5497
+ for in_record in query_result :
5498
+ record = dict (in_record )
5451
5499
if no_obj :
5452
- record ["status" ] = await cls ._get_status_field (record ["environment" ], record ["status" ])
5500
+ if no_status :
5501
+ record ["status" ] = {}
5502
+ else :
5503
+ record ["status" ] = await cls ._get_status_field (record ["environment" ], record ["status" ])
5453
5504
result .append (record )
5454
5505
else :
5455
5506
done = record .pop ("done" )
5456
- status = await cls ._get_status_field (record ["environment" ], record .pop ("status" ))
5507
+ if no_status :
5508
+ status = {}
5509
+ record .pop ("status" )
5510
+ else :
5511
+ status = await cls ._get_status_field (record ["environment" ], record .pop ("status" ))
5457
5512
obj = cls (from_postgres = True , ** record )
5458
5513
obj ._done = done
5459
5514
obj ._status = status
@@ -5703,23 +5758,23 @@ async def get_increment(
5703
5758
deployed and different hash -> increment
5704
5759
"""
5705
5760
# Depends on deploying
5706
- projection_a_resource = [
5761
+ projection_a_resource : list [ typing . LiteralString ] = [
5707
5762
"resource_id" ,
5708
5763
"attribute_hash" ,
5709
- "attributes" ,
5710
5764
"status" ,
5711
5765
]
5712
- projection_a_state = [
5766
+ projection_a_state : list [ typing . LiteralString ] = [
5713
5767
"last_success" ,
5714
5768
"last_produced_events" ,
5715
5769
"last_deployed_attribute_hash" ,
5716
5770
"last_non_deploying_status" ,
5717
5771
]
5718
- projection = ["resource_id" , "status" , "attribute_hash" ]
5772
+ projection_a_attributes : list [typing .LiteralString ] = ["requires" , "send_event" ]
5773
+ projection : list [typing .LiteralString ] = ["resource_id" , "status" , "attribute_hash" ]
5719
5774
5720
5775
# get resources for agent
5721
5776
resources = await Resource .get_resources_for_version_raw_with_persistent_state (
5722
- environment , version , projection_a_resource , projection_a_state , connection = connection
5777
+ environment , version , projection_a_resource , projection_a_state , projection_a_attributes , connection = connection
5723
5778
)
5724
5779
5725
5780
# to increment
@@ -5740,20 +5795,11 @@ async def get_increment(
5740
5795
continue
5741
5796
# Now outstanding events
5742
5797
last_success = resource ["last_success" ] or DATETIME_MIN_UTC
5743
- attributes = resource ["attributes" ]
5744
- assert isinstance (attributes , dict ) # mypy
5745
- for req in attributes ["requires" ]:
5798
+ for req in resource ["requires" ]:
5746
5799
req_res = id_to_resource [req ]
5747
5800
assert req_res is not None # todo
5748
- req_res_attributes = req_res ["attributes" ]
5749
- assert isinstance (req_res_attributes , dict ) # mypy
5750
5801
last_produced_events = req_res ["last_produced_events" ]
5751
- if (
5752
- last_produced_events is not None
5753
- and last_produced_events > last_success
5754
- and "send_event" in req_res_attributes
5755
- and req_res_attributes ["send_event" ]
5756
- ):
5802
+ if last_produced_events is not None and last_produced_events > last_success and req_res ["send_event" ]:
5757
5803
in_increment = True
5758
5804
break
5759
5805
@@ -5839,9 +5885,9 @@ async def get_increment(
5839
5885
5840
5886
# build lookup tables
5841
5887
for res in resources :
5842
- for req in res ["attributes" ][ " requires" ]:
5888
+ for req in res ["requires" ]:
5843
5889
original_provides [req ].append (res ["resource_id" ])
5844
- if "send_event" in res [ "attributes" ] and res [ "attributes" ] ["send_event" ]:
5890
+ if res ["send_event" ]:
5845
5891
send_events .append (res ["resource_id" ])
5846
5892
5847
5893
# recursively include stuff potentially receiving events from nodes in the increment
0 commit comments