This commit is contained in:
J. Nick Koston
2023-04-10 11:49:32 -10:00
parent 055667d403
commit 79078670dd

View File

@@ -15,6 +15,7 @@ from sqlalchemy import (
Subquery, Subquery,
and_, and_,
func, func,
lambda_stmt,
select, select,
union_all, union_all,
) )
@@ -76,7 +77,7 @@ _FIELD_MAP = {
def _stmt_and_join_attributes( def _stmt_and_join_attributes(
no_attributes: bool, include_last_changed: bool = True no_attributes: bool, include_last_changed: bool
) -> Select: ) -> Select:
"""Return the statement and if StateAttributes should be joined.""" """Return the statement and if StateAttributes should be joined."""
# If no_attributes was requested we do the query # If no_attributes was requested we do the query
@@ -213,7 +214,6 @@ def get_significant_states_with_session(
raise NotImplementedError("Filters are no longer supported") raise NotImplementedError("Filters are no longer supported")
if not entity_ids: if not entity_ids:
raise ValueError("entity_ids must be provided") raise ValueError("entity_ids must be provided")
metadata_ids: list[int] | None = None
entity_id_to_metadata_id: dict[str, int | None] | None = None entity_id_to_metadata_id: dict[str, int | None] | None = None
metadata_ids_in_significant_domains: list[int] = [] metadata_ids_in_significant_domains: list[int] = []
instance = recorder.get_instance(hass) instance = recorder.get_instance(hass)
@@ -221,8 +221,9 @@ def get_significant_states_with_session(
entity_id_to_metadata_id := instance.states_meta_manager.get_many( entity_id_to_metadata_id := instance.states_meta_manager.get_many(
entity_ids, session, False entity_ids, session, False
) )
) or not (metadata_ids := extract_metadata_ids(entity_id_to_metadata_id)): ) or not (possible_metadata_ids := extract_metadata_ids(entity_id_to_metadata_id)):
return {} return {}
metadata_ids = possible_metadata_ids
if significant_changes_only: if significant_changes_only:
metadata_ids_in_significant_domains = [ metadata_ids_in_significant_domains = [
metadata_id metadata_id
@@ -241,7 +242,8 @@ def get_significant_states_with_session(
include_start_time_state = False include_start_time_state = False
start_time_ts = dt_util.utc_to_timestamp(start_time) start_time_ts = dt_util.utc_to_timestamp(start_time)
end_time_ts = datetime_to_timestamp_or_none(end_time) end_time_ts = datetime_to_timestamp_or_none(end_time)
stmt = _significant_states_stmt( stmt = lambda_stmt(
lambda: _significant_states_stmt(
start_time_ts, start_time_ts,
end_time_ts, end_time_ts,
metadata_ids, metadata_ids,
@@ -250,6 +252,13 @@ def get_significant_states_with_session(
no_attributes, no_attributes,
include_start_time_state, include_start_time_state,
run_start_ts, run_start_ts,
),
track_on=[
bool(end_time_ts),
bool(significant_changes_only),
bool(no_attributes),
bool(include_start_time_state),
],
) )
states = execute_stmt_lambda_element(session, stmt, None, end_time) states = execute_stmt_lambda_element(session, stmt, None, end_time)
return _sorted_states_to_dict( return _sorted_states_to_dict(
@@ -298,6 +307,7 @@ def _state_changed_during_period_stmt(
start_time_ts: float, start_time_ts: float,
end_time_ts: float | None, end_time_ts: float | None,
metadata_id: int, metadata_id: int,
metadata_ids: list[int],
no_attributes: bool, no_attributes: bool,
descending: bool, descending: bool,
limit: int | None, limit: int | None,
@@ -305,7 +315,7 @@ def _state_changed_during_period_stmt(
run_start_ts: float | None, run_start_ts: float | None,
) -> Select | CompoundSelect: ) -> Select | CompoundSelect:
stmt = ( stmt = (
_stmt_and_join_attributes(no_attributes, include_last_changed=False) _stmt_and_join_attributes(no_attributes, False)
.filter( .filter(
( (
(States.last_changed_ts == States.last_updated_ts) (States.last_changed_ts == States.last_updated_ts)
@@ -333,7 +343,7 @@ def _state_changed_during_period_stmt(
union_all( union_all(
_select_from_subquery( _select_from_subquery(
_get_start_time_state_stmt( _get_start_time_state_stmt(
run_start_ts, start_time_ts, [metadata_id], no_attributes run_start_ts, start_time_ts, metadata_ids, no_attributes
).subquery(), ).subquery(),
no_attributes, no_attributes,
), ),
@@ -359,12 +369,14 @@ def state_changes_during_period(
entity_ids = [entity_id.lower()] entity_ids = [entity_id.lower()]
with session_scope(hass=hass, read_only=True) as session: with session_scope(hass=hass, read_only=True) as session:
metadata_id: int | None = None
instance = recorder.get_instance(hass) instance = recorder.get_instance(hass)
if not ( if not (
metadata_id := instance.states_meta_manager.get(entity_id, session, False) possible_metadata_id := instance.states_meta_manager.get(
entity_id, session, False
)
): ):
return {} return {}
metadata_id = possible_metadata_id
entity_id_to_metadata_id: dict[str, int | None] = {entity_id: metadata_id} entity_id_to_metadata_id: dict[str, int | None] = {entity_id: metadata_id}
run_start_ts: float | None = None run_start_ts: float | None = None
if include_start_time_state: if include_start_time_state:
@@ -377,15 +389,26 @@ def state_changes_during_period(
include_start_time_state = False include_start_time_state = False
start_time_ts = dt_util.utc_to_timestamp(start_time) start_time_ts = dt_util.utc_to_timestamp(start_time)
end_time_ts = datetime_to_timestamp_or_none(end_time) end_time_ts = datetime_to_timestamp_or_none(end_time)
stmt = _state_changed_during_period_stmt( metadata_ids = [metadata_id]
stmt = lambda_stmt(
lambda: _state_changed_during_period_stmt(
start_time_ts, start_time_ts,
end_time_ts, end_time_ts,
metadata_id, metadata_id,
metadata_ids,
no_attributes, no_attributes,
descending, descending,
limit, limit,
include_start_time_state, include_start_time_state,
run_start_ts, run_start_ts,
),
track_on=[
bool(end_time_ts),
no_attributes,
descending,
bool(limit),
bool(include_start_time_state),
],
) )
states = execute_stmt_lambda_element(session, stmt, None, end_time) states = execute_stmt_lambda_element(session, stmt, None, end_time)
return cast( return cast(
@@ -399,7 +422,7 @@ def state_changes_during_period(
def _get_last_state_changes_stmt(number_of_states: int, metadata_id: int) -> Select: def _get_last_state_changes_stmt(number_of_states: int, metadata_id: int) -> Select:
stmt = _stmt_and_join_attributes(False, include_last_changed=False) stmt = _stmt_and_join_attributes(False, False)
if number_of_states == 1: if number_of_states == 1:
stmt = stmt.join( stmt = stmt.join(
( (
@@ -452,11 +475,17 @@ def get_last_state_changes(
with session_scope(hass=hass, read_only=True) as session: with session_scope(hass=hass, read_only=True) as session:
instance = recorder.get_instance(hass) instance = recorder.get_instance(hass)
if not ( if not (
metadata_id := instance.states_meta_manager.get(entity_id, session, False) possible_metadata_id := instance.states_meta_manager.get(
entity_id, session, False
)
): ):
return {} return {}
metadata_id = possible_metadata_id
entity_id_to_metadata_id: dict[str, int | None] = {entity_id_lower: metadata_id} entity_id_to_metadata_id: dict[str, int | None] = {entity_id_lower: metadata_id}
stmt = _get_last_state_changes_stmt(number_of_states, metadata_id) stmt = lambda_stmt(
lambda: _get_last_state_changes_stmt(number_of_states, metadata_id),
track_on=[number_of_states == 1],
)
states = list(execute_stmt_lambda_element(session, stmt)) states = list(execute_stmt_lambda_element(session, stmt))
return cast( return cast(
MutableMapping[str, list[State]], MutableMapping[str, list[State]],
@@ -475,7 +504,7 @@ def _get_states_for_entities_stmt(
no_attributes: bool, no_attributes: bool,
) -> Select: ) -> Select:
"""Baked query to get states for specific entities.""" """Baked query to get states for specific entities."""
stmt = _stmt_and_join_attributes(no_attributes, include_last_changed=True) stmt = _stmt_and_join_attributes(no_attributes, True)
# We got an include-list of entities, accelerate the query by filtering already # We got an include-list of entities, accelerate the query by filtering already
# in the inner query. # in the inner query.
stmt = stmt.join( stmt = stmt.join(
@@ -527,7 +556,7 @@ def _get_start_time_state_stmt(
run_start_ts: float, run_start_ts: float,
epoch_time: float, epoch_time: float,
metadata_ids: list[int], metadata_ids: list[int],
no_attributes: bool = False, no_attributes: bool,
) -> Select: ) -> Select:
"""Return the states at a specific point in time.""" """Return the states at a specific point in time."""