Skip to content
This repository was archived by the owner on Jun 9, 2020. It is now read-only.

Commit 6c4177b

Browse files
committed
Prevent crossfilter to fail when data is missing. Replaced missing value with __missing__. Allow to pass missingValue in query
1 parent de7bc09 commit 6c4177b

File tree

6 files changed

+136
-7
lines changed

6 files changed

+136
-7
lines changed

src/column.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export default function(service) {
120120
column.type = getType(sample)
121121
}
122122

123-
return dimension.make(column.key, column.type, column.complex)
123+
return dimension.make(column.key, column.type, column.complex, column.missingValue)
124124
})
125125
.then(function(dim) {
126126
column.dimension = dim
@@ -136,7 +136,7 @@ export default function(service) {
136136
return Promise.resolve()
137137
}
138138

139-
var accessor = dimension.makeAccessor(column.key, column.complex)
139+
var accessor = dimension.makeAccessor(column.key, column.complex, column.missingValue)
140140
column.values = column.values || []
141141

142142
return new Promise(function(resolve, reject) {

src/dimension.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,20 @@ export default function(service) {
66
makeAccessor: makeAccessor,
77
}
88

9-
function make(key, type, complex) {
10-
var accessor = makeAccessor(key, complex)
9+
function make(key, type, complex, missingValue = '__missing__') {
10+
var accessor = makeAccessor(key, complex, missingValue)
1111
// Promise.resolve will handle promises or non promises, so
1212
// this crossfilter async is supported if present
1313
return Promise.resolve(service.cf.dimension(accessor, type === 'array'))
1414
}
1515

16-
function makeAccessor(key, complex) {
16+
function makeAccessor(key, complex, missingValue) {
1717
var accessorFunction
1818

1919
if (complex === 'string') {
2020
accessorFunction = function(d) {
21-
return _.get(d, key)
21+
const value = _.get(d, key)
22+
return value === undefined || isNaN(value) ? missingValue : value
2223
}
2324
} else if (complex === 'function') {
2425
accessorFunction = key
@@ -32,7 +33,10 @@ export default function(service) {
3233
// Index Dimension
3334
key === true ? (d, i) => i :
3435
// Value Accessor Dimension
35-
(d) => d[key]
36+
(d) => {
37+
const value = d[key]
38+
return value === undefined ? missingValue : value
39+
}
3640
}
3741
return accessorFunction
3842
}

src/query.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export default function(service) {
6262
key: query.original.groupBy,
6363
type: _.isUndefined(query.type) ? null : query.type,
6464
array: Boolean(query.array),
65+
missingValue: query.original.missingValue
6566
})
6667
.then(function() {
6768
// Attach the column to the query

test/column.spec.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import test from 'ava'
22

33
import universe from '../src/universe'
44
import data from './fixtures/data.json'
5+
import dataMissing from './fixtures/dataMissing.json'
56

67
test('has the columns properties', async t => {
78
const u = await universe(data)
@@ -45,6 +46,18 @@ test('can add a column with a complex key', async t => {
4546
t.is(typeof res.columns[0].dimension, 'object')
4647
})
4748

49+
test('can add a column with a complex key and missing value', async t => {
50+
const u = await universe(dataMissing)
51+
52+
const res = await u.column({
53+
key: ['type', 'total', 'quantity', 'tip']
54+
})
55+
56+
t.deepEqual(res.columns[0].key, ['type', 'total', 'quantity', 'tip'])
57+
t.is(res.columns[0].type, 'complex')
58+
t.is(typeof res.columns[0].dimension, 'object')
59+
})
60+
4861
test('can add a column with nested string format', async t => {
4962
const u = await universe(data)
5063

test/fixtures/dataMissing.json

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
[
2+
{
3+
"date": "2011-11-14T16:17:54Z",
4+
"quantity": 2,
5+
"total": 190,
6+
"tip": 100,
7+
"type": "tab",
8+
"productIDs": ["001"]
9+
},
10+
{
11+
"date": "2011-11-14T16:20:19Z",
12+
"quantity": 2,
13+
"total": 190,
14+
"tip": 100,
15+
"productIDs": ["001", "005"]
16+
},
17+
{
18+
"date": "2011-11-14T16:28:54Z",
19+
"quantity": 1,
20+
"total": 300,
21+
"tip": 200,
22+
"type": "visa",
23+
"productIDs": ["004", "005"]
24+
},
25+
{
26+
"date": "2011-11-14T16:30:43Z",
27+
"quantity": 2,
28+
"total": 90,
29+
"tip": 0,
30+
"productIDs": ["001", "002"]
31+
},
32+
{
33+
"date": "2011-11-14T16:48:46Z",
34+
"quantity": 2,
35+
"total": 90,
36+
"tip": 0,
37+
"type": "tab",
38+
"productIDs": ["005"]
39+
},
40+
{
41+
"date": "2011-11-14T16:53:41Z",
42+
"quantity": 2,
43+
"total": 90,
44+
"tip": 0,
45+
"type": "tab",
46+
"productIDs": ["001", "004", "005"]
47+
},
48+
{
49+
"date": "2011-11-14T16:54:06Z",
50+
"quantity": 1,
51+
"total": 100,
52+
"tip": 0,
53+
"type": "cash",
54+
"productIDs": ["001", "002", "003", "004", "005"]
55+
},
56+
{
57+
"date": "2011-11-14T16:58:03Z",
58+
"quantity": 2,
59+
"total": 90,
60+
"tip": 0,
61+
"type": "tab",
62+
"productIDs": ["001"]
63+
},
64+
{
65+
"date": "2011-11-14T17:07:21Z",
66+
"quantity": 2,
67+
"total": 90,
68+
"tip": 0,
69+
"type": "tab",
70+
"productIDs": ["004", "005"]
71+
},
72+
{
73+
"date": "2011-11-14T17:22:59Z",
74+
"quantity": 2,
75+
"total": 90,
76+
"tip": 0,
77+
"type": "tab",
78+
"productIDs": ["001", "002", "004", "005"]
79+
},
80+
{
81+
"date": "2011-11-14T17:25:45Z",
82+
"quantity": 2,
83+
"total": 200,
84+
"tip": 0,
85+
"type": "cash",
86+
"productIDs": ["002"]
87+
},
88+
{
89+
"date": "2011-11-14T17:29:52Z",
90+
"quantity": 1,
91+
"total": 200,
92+
"tip": 100,
93+
"type": "visa",
94+
"productIDs": ["004"]
95+
}]

test/query.spec.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import test from 'ava'
22

33
import universe from '../src/universe'
44
import data from './fixtures/data.json'
5+
import dataMissing from './fixtures/dataMissing.json'
56

67
test('has the query method', async t => {
78
const u = await universe(data)
@@ -198,6 +199,21 @@ test('supports groupBy', async t => {
198199
])
199200
})
200201

202+
test('supports groupBy - event with missing value', async t => {
203+
const u = await universe(dataMissing)
204+
205+
const q = await u.query({
206+
groupBy: 'type'
207+
})
208+
209+
t.deepEqual(q.data, [
210+
{key: '__missing__', value: {count: 2}},
211+
{key: 'cash', value: {count: 2}},
212+
{key: 'tab', value: {count: 6}},
213+
{key: 'visa', value: {count: 2}}
214+
])
215+
})
216+
201217
test('can query using the valueList aggregation', async t => {
202218
const u = await universe(data)
203219

0 commit comments

Comments
 (0)