-
Notifications
You must be signed in to change notification settings - Fork 20
/
klass.py
154 lines (118 loc) · 4.55 KB
/
klass.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import itertools
from fireant.utils import immutable
from fireant.queries.builder import (
DataSetQueryBuilder,
DimensionChoicesQueryBuilder,
DimensionLatestQueryBuilder,
)
class _Container(object):
"""
This is a list of dataset elements, metrics or dimensions, used for accessing an element by key with a dot syntax.
Example:
.. code-block:: python
dataset = DataSet(
dimensions=[
Dimension(key='my_dimension1')
]
)
dataset.dimensions.my_dimension1
"""
def __init__(self, items=()):
self._items = list(items)
for item in items:
setattr(self, item.alias, item)
def __copy__(self):
return type(self)(self._items)
def __deepcopy__(self, memodict):
for field in self:
memodict[id(field)] = field
return type(self)(self._items)
def __iter__(self):
return iter(self._items)
def __getitem__(self, item):
return getattr(self, item)
def __contains__(self, item):
from .fields import Field
if isinstance(item, str):
return hasattr(self, item)
if not isinstance(item, Field):
return False
self_item = getattr(self, item.alias, None)
return item is self_item
def __hash__(self):
return hash((item for item in self._items))
def __eq__(self, other):
"""
Checks if the other object is an instance of _Container and has the same number of items with matching keys.
"""
return isinstance(other, _Container) and all(
[
a is not None and b is not None and a.alias == b.alias
for a, b in itertools.zip_longest(
self._items, getattr(other, "_items", ())
)
]
)
def append(self, item):
self._items.append(item)
setattr(self, item.alias, item)
class DataSet:
"""
The DataSet class abstracts the query generation, given the fields and what not that were provided, and the
fetching of the aforementioned query's data.
"""
class Fields(_Container):
pass
def __init__(
self, table, database, joins=(), fields=(), always_query_all_metrics=False
):
"""
Constructor for a dataset. Contains all the fields to initialize the dataset.
:param table: (Required)
A pypika Table reference. The primary table that this dataset will retrieve data from.
:param database: (Required)
A Database reference. Holds the connection details used by this dataset to execute queries.
:param fields: (Required: At least one)
A list of fields mapping definitions of data in the data set. Fields are similar to a column in a database
query result set. They are the values
:param joins: (Optional)
A list of join descriptions for joining additional tables. Joined tables are only used when querying a
metric or dimension which requires it.
:param always_query_all_metrics: (Default: False)
When true, all metrics will be included in database queries in order to increase cache hits.
"""
self.table = table
self.database = database
self.joins = list(joins)
self.fields = DataSet.Fields(fields)
# add query builder entry points
self.query = DataSetQueryBuilder(self)
self.latest = DimensionLatestQueryBuilder(self)
self.always_query_all_metrics = always_query_all_metrics
for field in fields:
if not field.definition.is_aggregate:
field.choices = DimensionChoicesQueryBuilder(self, field)
def __eq__(self, other):
return isinstance(other, DataSet) and self.fields == other.fields
def __repr__(self):
return "DataSet(fields=[{}])".format(",".join([repr(f) for f in self.fields]))
def __hash__(self):
return hash(
(
self.table,
self.database.database,
tuple(self.joins),
self.fields,
self.always_query_all_metrics,
)
)
@immutable
def extra_fields(self, *fields):
for field in fields:
self.fields.append(field)
def blend(self, other):
"""
Returns a Data Set blender which enables to execute queries on multiple data sets and combine them.
"""
from .data_blending import DataSetBlenderBuilder
return DataSetBlenderBuilder(self, other)