""" Part of the BlackStar filesystem (bsfs) module. A copy of the license is provided with the project. Author: Matthias Baumgartner, 2022 """ # imports from collections import defaultdict import typing # bsfs imports from bsfs.utils import URI # exports __all__: typing.Sequence[str] = ( 'to_list_view', 'to_dict_view', ) ## code ## def to_list_view( triples, # aggregators node: bool, path: bool, value: bool, # pylint: disable=unused-argument ): """Return an iterator over results. Dependent on the *node*, *path*, and *value* flags, the respective component is omitted. """ if node and path: return iter(val for _, _, val in triples) if node: return iter((pred, val) for _, pred, val in triples) if path: return iter((subj, val) for subj, _, val in triples) return iter((subj, pred, val) for subj, pred, val in triples) def to_dict_view( triples, # context one_node: bool, one_path: bool, unique_paths: typing.Set[typing.Union[URI, typing.Iterable[URI]]], # aggregators node: bool, path: bool, value: bool, ) -> typing.Any: """Return a dict of results. Note that triples are materialized to create this view. The returned structure depends on the *node*, *path*, and *value* flags. If all flags are set to False, returns a dict(node -> dict(path -> set(values))). Setting a flag to true omits or simplifies the respective component (if possible). """ # NOTE: To create a dict, we need to materialize or make further assumptions # (e.g., sorted in a specific order). data: typing.Any # disable type checks on data since it's very flexibly typed. # FIXME: type of data can be overwritten later on (if value) if node and path: data = set() elif node ^ path: data = defaultdict(set) else: data = defaultdict(lambda: defaultdict(set)) for subj, pred, val in triples: unique = pred in unique_paths if node and path: if value and unique and one_node and one_path: return val data.add(val) elif node: # remove node from result, group by predicate if value and unique and one_node: data[pred] = val else: data[pred].add(val) elif path: # remove predicate from result, group by node if value and unique and one_path: data[subj] = val else: data[subj].add(val) else: if value and unique: data[subj][pred] = val else: data[subj][pred].add(val) # FIXME: Combine multiple Nodes instances into one? # convert defaultdict to ordinary dict if node and path: return data if node ^ path: return dict(data) return {key: dict(val) for key, val in data.items()} ## EOF ##