Event Storage Layer
This change adds the storage layer interfaces necessary to implement the Event API. It also updates the get_events call to allow multiple trait filters. implements bp specify-event-api Change-Id: I7aef4a8fc9b88528479f6c0a9feab2c18945bae3
This commit is contained in:
@@ -918,90 +918,182 @@ class Connection(base.Connection):
|
||||
return problem_events
|
||||
|
||||
def get_events(self, event_filter):
|
||||
"""Return an iterable of model.Event objects. The event model objects
|
||||
have their Trait model objects available -- filtered by any traits
|
||||
in the event_filter.
|
||||
"""Return an iterable of model.Event objects.
|
||||
|
||||
:param event_filter: EventFilter instance
|
||||
"""
|
||||
|
||||
start = utils.dt_to_decimal(event_filter.start)
|
||||
end = utils.dt_to_decimal(event_filter.end)
|
||||
start = utils.dt_to_decimal(event_filter.start_time)
|
||||
end = utils.dt_to_decimal(event_filter.end_time)
|
||||
session = sqlalchemy_session.get_session()
|
||||
with session.begin():
|
||||
sub_query = session.query(models.Event.id)\
|
||||
.join(models.EventType,
|
||||
models.Event.event_type_id == models.EventType.id)\
|
||||
.join(models.Trait,
|
||||
models.Trait.event_id == models.Event.id)\
|
||||
.filter(models.Event.generated >= start,
|
||||
models.Event.generated <= end)
|
||||
event_query = session.query(models.Event)
|
||||
|
||||
# Build up the join conditions
|
||||
event_join_conditions = [models.EventType.id ==
|
||||
models.Event.event_type_id]
|
||||
|
||||
if event_filter.event_type:
|
||||
event_type = event_filter.event_type
|
||||
sub_query = sub_query\
|
||||
.filter(models.EventType.desc == event_type)
|
||||
event_join_conditions\
|
||||
.append(models.EventType.desc == event_filter.event_type)
|
||||
|
||||
event_query = event_query.join(models.EventType,
|
||||
and_(*event_join_conditions))
|
||||
|
||||
# Build up the where conditions
|
||||
event_filter_conditions = []
|
||||
if event_filter.message_id:
|
||||
event_filter_conditions\
|
||||
.append(models.Event.message_id == event_filter.message_id)
|
||||
if start:
|
||||
event_filter_conditions.append(models.Event.generated >= start)
|
||||
if end:
|
||||
event_filter_conditions.append(models.Event.generated <= end)
|
||||
|
||||
if event_filter_conditions:
|
||||
event_query = event_query\
|
||||
.filter(and_(*event_filter_conditions))
|
||||
|
||||
event_models_dict = {}
|
||||
if event_filter.traits:
|
||||
sub_query = sub_query.join(models.TraitType,
|
||||
models.TraitType.id ==
|
||||
models.Trait.trait_type_id)
|
||||
for key, value in event_filter.traits.iteritems():
|
||||
if key == 'key':
|
||||
sub_query = sub_query.filter(models.TraitType.desc ==
|
||||
value)
|
||||
elif key == 't_string':
|
||||
sub_query = sub_query.filter(
|
||||
models.Trait.t_string == value)
|
||||
elif key == 't_int':
|
||||
sub_query = sub_query.filter(
|
||||
models.Trait.t_int == value)
|
||||
elif key == 't_datetime':
|
||||
dt = utils.dt_to_decimal(value)
|
||||
sub_query = sub_query.filter(
|
||||
models.Trait.t_datetime == dt)
|
||||
elif key == 't_float':
|
||||
sub_query = sub_query.filter(
|
||||
models.Trait.t_datetime == value)
|
||||
if event_filter.traits_filter:
|
||||
for trait_filter in event_filter.traits_filter:
|
||||
|
||||
# Build a sub query that joins Trait to TraitType
|
||||
# where the trait name matches
|
||||
trait_name = trait_filter.pop('key')
|
||||
conditions = [models.Trait.trait_type_id ==
|
||||
models.TraitType.id,
|
||||
models.TraitType.desc == trait_name]
|
||||
|
||||
for key, value in trait_filter.iteritems():
|
||||
if key == 't_string':
|
||||
conditions.append(models.Trait.t_string == value)
|
||||
elif key == 't_int':
|
||||
conditions.append(models.Trait.t_int == value)
|
||||
elif key == 't_datetime':
|
||||
dt = utils.dt_to_decimal(value)
|
||||
conditions.append(models.Trait.t_datetime == dt)
|
||||
elif key == 't_float':
|
||||
conditions.append(models.Trait.t_float == value)
|
||||
|
||||
trait_query = session.query(models.Trait.event_id)\
|
||||
.join(models.TraitType, and_(*conditions)).subquery()
|
||||
|
||||
event_query = event_query\
|
||||
.join(trait_query,
|
||||
models.Event.id == trait_query.c.event_id)
|
||||
else:
|
||||
# Pre-populate event_models_dict to cover Events without traits
|
||||
events = session.query(models.Event)\
|
||||
.filter(models.Event.generated >= start)\
|
||||
.filter(models.Event.generated <= end)
|
||||
if event_filter.event_type:
|
||||
events = events\
|
||||
.join(models.EventType,
|
||||
models.EventType.id ==
|
||||
models.Event.event_type_id)\
|
||||
.filter(models.EventType.desc ==
|
||||
event_filter.event_type)
|
||||
for db_event in events.all():
|
||||
generated = utils.decimal_to_dt(db_event.generated)
|
||||
api_event = api_models.Event(db_event.message_id,
|
||||
db_event.event_type.desc,
|
||||
generated, [])
|
||||
event_models_dict[db_event.id] = api_event
|
||||
# If there are no trait filters, grab the events from the db
|
||||
query = session.query(models.Event.id,
|
||||
models.Event.generated,
|
||||
models.Event.message_id,
|
||||
models.EventType.desc)\
|
||||
.join(models.EventType,
|
||||
and_(*event_join_conditions))
|
||||
if event_filter_conditions:
|
||||
query = query.filter(and_(*event_filter_conditions))
|
||||
for (id, generated, message_id, desc) in query.all():
|
||||
event_models_dict[id] = api_models.Event(message_id,
|
||||
desc,
|
||||
generated,
|
||||
[])
|
||||
|
||||
sub_query = sub_query.subquery()
|
||||
|
||||
all_data = session.query(models.Trait)\
|
||||
.join(sub_query, models.Trait.event_id == sub_query.c.id)
|
||||
# Build event models for the events
|
||||
event_query = event_query.subquery()
|
||||
query = session.query(models.Trait)\
|
||||
.join(models.TraitType,
|
||||
models.Trait.trait_type_id == models.TraitType.id)\
|
||||
.join(event_query, models.Trait.event_id == event_query.c.id)
|
||||
|
||||
# Now convert the sqlalchemy objects back into Models ...
|
||||
for trait in all_data.all():
|
||||
for trait in query.all():
|
||||
event = event_models_dict.get(trait.event_id)
|
||||
if not event:
|
||||
generated = utils.decimal_to_dt(trait.event.generated)
|
||||
event = api_models.Event(trait.event.message_id,
|
||||
trait.event.event_type.desc,
|
||||
generated, [])
|
||||
event = api_models.Event(
|
||||
trait.event.message_id,
|
||||
trait.event.event_type.desc,
|
||||
generated, [])
|
||||
event_models_dict[trait.event_id] = event
|
||||
value = trait.get_value()
|
||||
trait_model = api_models.Trait(trait.trait_type.desc,
|
||||
trait.trait_type.data_type,
|
||||
value)
|
||||
trait.get_value())
|
||||
event.append_trait(trait_model)
|
||||
|
||||
event_models = event_models_dict.values()
|
||||
return sorted(event_models, key=operator.attrgetter('generated'))
|
||||
|
||||
@staticmethod
|
||||
def get_event_types():
|
||||
"""Return all event types as an iterable of strings.
|
||||
"""
|
||||
|
||||
session = sqlalchemy_session.get_session()
|
||||
with session.begin():
|
||||
query = session.query(models.EventType.desc)\
|
||||
.order_by(models.EventType.desc)
|
||||
for name in query.all():
|
||||
# The query returns a tuple with one element.
|
||||
yield name[0]
|
||||
|
||||
@staticmethod
|
||||
def get_trait_types(event_type):
|
||||
"""Return a dictionary containing the name and data type of
|
||||
the trait type. Only trait types for the provided event_type are
|
||||
returned.
|
||||
|
||||
:param event_type: the type of the Event
|
||||
"""
|
||||
session = sqlalchemy_session.get_session()
|
||||
|
||||
with session.begin():
|
||||
query = (session.query(models.TraitType.desc,
|
||||
models.TraitType.data_type)
|
||||
.join(models.Trait,
|
||||
models.Trait.trait_type_id ==
|
||||
models.TraitType.id)
|
||||
.join(models.Event,
|
||||
models.Event.id ==
|
||||
models.Trait.event_id)
|
||||
.join(models.EventType,
|
||||
and_(models.EventType.id ==
|
||||
models.Event.id,
|
||||
models.EventType.desc ==
|
||||
event_type))
|
||||
.group_by(models.TraitType.desc,
|
||||
models.TraitType.data_type)
|
||||
.distinct())
|
||||
|
||||
for desc, type in query.all():
|
||||
yield {'name': desc, 'data_type': type}
|
||||
|
||||
@staticmethod
|
||||
def get_traits(event_type, trait_type=None):
|
||||
"""Return all trait instances associated with an event_type. If
|
||||
trait_type is specified, only return instances of that trait type.
|
||||
|
||||
:param event_type: the type of the Event to filter by
|
||||
:param trait_type: the name of the Trait to filter by
|
||||
"""
|
||||
|
||||
session = sqlalchemy_session.get_session()
|
||||
with session.begin():
|
||||
trait_type_filters = [models.TraitType.id ==
|
||||
models.Trait.trait_type_id]
|
||||
if trait_type:
|
||||
trait_type_filters.append(models.TraitType.desc == trait_type)
|
||||
|
||||
query = (session.query(models.Trait)
|
||||
.join(models.TraitType, and_(*trait_type_filters))
|
||||
.join(models.Event,
|
||||
models.Event.id == models.Trait.event_id)
|
||||
.join(models.EventType,
|
||||
and_(models.EventType.id ==
|
||||
models.Event.event_type_id,
|
||||
models.EventType.desc == event_type)))
|
||||
|
||||
for trait in query.all():
|
||||
type = trait.trait_type
|
||||
yield api_models.Trait(name=type.desc,
|
||||
dtype=type.data_type,
|
||||
value=trait.get_value())
|
||||
|
Reference in New Issue
Block a user