Index: charted/lib/charts/data_transformers/aggregation_item.dart |
diff --git a/charted/lib/charts/data_transformers/aggregation_item.dart b/charted/lib/charts/data_transformers/aggregation_item.dart |
deleted file mode 100644 |
index 17c641390b61efbd354453cf19fda302bf91aa99..0000000000000000000000000000000000000000 |
--- a/charted/lib/charts/data_transformers/aggregation_item.dart |
+++ /dev/null |
@@ -1,266 +0,0 @@ |
-/* |
- * Copyright 2014 Google Inc. All rights reserved. |
- * |
- * Use of this source code is governed by a BSD-style |
- * license that can be found in the LICENSE file or at |
- * https://developers.google.com/open-source/licenses/bsd |
- */ |
- |
-part of charted.charts; |
- |
-/** |
- * AggregationItem is created by [AggregationModel] to make access to facts |
- * observable. Users must use AggregationItem.isValid before trying to access |
- * the aggregations. |
- */ |
-abstract class AggregationItem extends ChangeNotifier { |
- /** |
- * List of dimension fields in effect |
- */ |
- List<String> dimensions; |
- |
- /** |
- * Check if this entity is valid. |
- * Currently the only case where an entity becomes invalid |
- * is when a groupBy is called on the model. |
- */ |
- bool get isValid; |
- |
- /** |
- * Fetch the fact from AggregationModel and return it |
- * Currently takes keys in the form of "sum(spend)", where sum is |
- * the aggregation type and spend is fact's field name. |
- * |
- * Currently, "sum", "count", "min", "max", "avg", "valid" and "avgOfValid" |
- * are supported as the operators. |
- */ |
- |
- operator[](String key); |
- |
- /** |
- * Check if we support a given key. |
- */ |
- bool containsKey(String key); |
- |
- /** |
- * List of valid field names for this entity. |
- * It's the combined list of accessors for individual items, items in |
- * the next dimension and all possible facts defined on the view. |
- */ |
- Iterable<String> get fieldNames; |
-} |
- |
-/* |
- * Implementation of AggregationItem |
- * Instances of _AggregationItemImpl are created only by AggregationModel |
- */ |
-class _AggregationItemImpl extends ChangeNotifier implements AggregationItem { |
- static final List<String> derivedAggregationTypes = ['count', 'avg']; |
- |
- AggregationModel model; |
- List<String> dimensions; |
- |
- String _key; |
- |
- int _factsOffset; |
- |
- /* |
- * Currently entities are created only when they have valid aggregations |
- */ |
- _AggregationItemImpl(this.model, this.dimensions, this._key) { |
- if (model == null) { |
- throw new ArgumentError('Model cannot be null'); |
- } |
- if (_key == null) { |
- _key = ''; |
- } |
- |
- // facts + list of items + list of children (drilldown) |
- _factsOffset = model._dimToAggrMap[_key]; |
- } |
- |
- /** |
- * _dimToAggrMap got updated on the model, update ourselves accordingly |
- */ |
- void update() { |
- _factsOffset = model._dimToAggrMap[_key]; |
- } |
- |
- /* |
- * Mark this entity as invalid. |
- */ |
- void clear() { |
- _factsOffset = null; |
- } |
- |
- bool get isValid => _factsOffset != null; |
- |
- dynamic operator[](String key) { |
- if (!isValid) { |
- throw new StateError('Entity is not valid anymore'); |
- } |
- |
- int argPos = key.indexOf('('); |
- if (argPos == -1) { |
- return _nonAggregationMember(key); |
- } |
- |
- String aggrFunc = key.substring(0, argPos); |
- int aggrFuncIndex = model.computedAggregationTypes.indexOf(aggrFunc); |
- if (aggrFuncIndex == -1 && !derivedAggregationTypes.contains(aggrFunc)) { |
- throw new ArgumentError('Unknown aggregation method: ${aggrFunc}'); |
- } |
- |
- String factName = key.substring(argPos + 1, key.lastIndexOf(')')); |
- int factIndex = model._factFields.indexOf(factName); |
- |
- // Try parsing int if every element in factFields is int. |
- if (model._factFields.every((e) => e is int)) { |
- factIndex = model._factFields.indexOf(int.parse(factName, |
- onError: (e) { |
- throw new ArgumentError('Type of factFields are int but factName' + |
- 'contains non int value'); |
- })); |
- } |
- if (factIndex == -1) { |
- throw new ArgumentError('Model not configured for ${factName}'); |
- } |
- |
- int offset = _factsOffset + factIndex * model._aggregationTypesCount; |
- // No items for the corresponding fact, so return null. |
- if (aggrFunc != 'count' && aggrFunc != 'avg' && |
- model._aggregations[offset + model._offsetCnt].toInt() == 0) { |
- return null; |
- } |
- |
- if (aggrFuncIndex != -1) { |
- return model._aggregations[offset + aggrFuncIndex]; |
- } else if (aggrFunc == 'count') { |
- return model._aggregations[_factsOffset + |
- model._offsetFilteredCount].toInt(); |
- } else if (aggrFunc == 'avg') { |
- return model._aggregations[offset + model._offsetSum] / |
- model._aggregations[_factsOffset + model._offsetFilteredCount]. |
- toInt(); |
- } else if (aggrFunc == 'avgOfValid') { |
- return model._aggregations[offset + model._offsetSum] / |
- model._aggregations[offset + model._offsetCnt].toInt(); |
- } |
- return null; |
- } |
- |
- dynamic _nonAggregationMember(String key) { |
- if (key == 'items') { |
- return new _AggregationItemsIterator(model, dimensions, _key); |
- } |
- if (key == 'aggregations') { |
- return _lowerAggregations(); |
- } |
- return null; |
- } |
- |
- List<AggregationItem> _lowerAggregations() { |
- List<AggregationItem> aggregations = new List<AggregationItem>(); |
- if (dimensions.length == model._dimFields.length) { |
- return aggregations; |
- } |
- |
- var lowerDimensionField = model._dimFields[dimensions.length]; |
- List lowerVals = model.valuesForDimension(lowerDimensionField); |
- |
- lowerVals.forEach((name) { |
- List lowerDims = new List.from(dimensions)..add(name); |
- AggregationItem entity = model.facts(lowerDims); |
- if (entity != null) { |
- aggregations.add(entity); |
- } |
- }); |
- |
- return aggregations; |
- } |
- |
- bool containsKey(String key) => fieldNames.contains(key); |
- |
- Iterable<String> get fieldNames { |
- if (!isValid) { |
- throw new StateError('Entity is not valid anymore'); |
- } |
- |
- if (model._itemFieldNamesCache == null) { |
- List<String> cache = new List<String>.from(['items', 'children']); |
- model._factFields.forEach((var name) { |
- AggregationModel.supportedAggregationTypes.forEach((String aggrType) { |
- cache.add('${aggrType}(${name})'); |
- }); |
- }); |
- model._itemFieldNamesCache = cache; |
- } |
- return model._itemFieldNamesCache; |
- } |
- |
- /* |
- * TODO(prsd): Implementation of [Observable] |
- */ |
- Stream<List<ChangeRecord>> get changes { |
- throw new UnimplementedError(); |
- } |
-} |
- |
-class _AggregationItemsIterator implements Iterator { |
- final AggregationModel model; |
- List<String> dimensions; |
- String key; |
- |
- int _current; |
- int _counter = 0; |
- |
- int _start; |
- int _count; |
- int _endOfRows; |
- |
- _AggregationItemsIterator(this.model, List<String> this.dimensions, |
- String this.key) { |
- int offset = model._dimToAggrMap[key]; |
- if (offset != null) { |
- int factsEndOffset = offset + |
- model._factFields.length * model._aggregationTypesCount; |
- _start = model._aggregations[factsEndOffset].toInt(); |
- _count = model._aggregations[factsEndOffset + 1].toInt(); |
- _endOfRows = model._rows.length; |
- } |
- } |
- |
- bool moveNext() { |
- if (_current == null) { |
- _current = _start; |
- } else { |
- ++_current; |
- } |
- |
- if (++_counter > _count) { |
- return false; |
- } |
- |
- /* |
- * If model had a filter applied, then check if _current points to a |
- * filtered-in row, else skip till we find one. |
- * Also, make sure (even if something else went wrong) we don't go |
- * beyond the number of items in the model. |
- */ |
- if (this.model._filterResults != null) { |
- while ((this.model._filterResults[_current ~/ AggregationModel.SMI_BITS] & |
- (1 << _current % AggregationModel.SMI_BITS)) == 0 && |
- _current <= _endOfRows) { |
- ++_current; |
- } |
- } |
- return (_current < _endOfRows); |
- } |
- |
- get current { |
- if (_current == null || _counter > _count) { |
- return null; |
- } |
- return model._rows[model._sorted[_current]]; |
- } |
-} |