forked from UNC-Project-Open-AAC/OS-DPI
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdata.js
126 lines (121 loc) · 3.25 KB
/
data.js
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
import { evalInContext } from "./eval";
/** Implement comparison operators
* @typedef {function(string, string): boolean} Comparator
*
* @type {Object<string, Comparator>}
*/
export const comparators = {
equals: (f, v) =>
f.localeCompare(v, undefined, { sensitivity: "base" }) === 0 ||
f === "*" ||
v === "*",
"less than": (f, v) => f.localeCompare(v, undefined, { numeric: true }) < 0,
"starts with": (f, v) =>
f.toUpperCase().startsWith(v.toUpperCase()) || f === "*" || v === "*",
empty: (f) => !f,
"not empty": (f) => !!f,
};
/** Test a row with a filter
* @param {ContentFilter} filter
* @param {Row} row
* @returns {boolean}
*/
function match(filter, row) {
const field = row[filter.field.slice(1)] || "";
let value = filter.value || "";
const comparator = comparators[filter.operator];
if (!comparator) return true;
let r = comparator(field.toString(), value.toString());
return r;
}
export class Data {
/** @param {Rows} rows */
constructor(rows) {
this.allrows = (Array.isArray(rows) && rows) || [];
this.allFields = rows.reduce(
(previous, current) =>
Array.from(
new Set([
...previous,
...Object.keys(current).map((field) => "#" + field),
])
),
[]
);
this.loadTime = new Date();
}
/**
* Extract rows with the given filters
*
* @param {ContentFilter[]} filters - each filter must return true
* @param {State} state
* @param {RowCache} [cache]
* @return {Rows} Rows that pass the filters
*/
getMatchingRows(filters, state, cache) {
// all the filters must match the row
const boundFilters = filters.map((filter) =>
Object.assign({}, filter, {
value: evalInContext(filter.value, { state }),
})
);
if (cache) {
const newKey = JSON.stringify(boundFilters);
if (
cache.key == newKey &&
cache.loadTime == this.loadTime &&
cache.rows
) {
cache.updated = false;
return cache.rows;
}
cache.key = newKey;
}
const result = this.allrows.filter((row) =>
boundFilters.every((filter) => match(filter, row))
);
if (cache) {
cache.rows = result;
cache.updated = true;
cache.loadTime = this.loadTime;
}
// console.log("gtr result", result);
return result;
}
/**
* Test if any rows exist after filtering
*
* @param {ContentFilter[]} filters
* @param {State} state
* @param {RowCache} [cache]
* @return {Boolean} true if tag combination occurs
*/
hasMatchingRows(filters, state, cache) {
const boundFilters = filters.map((filter) =>
Object.assign({}, filter, {
value: evalInContext(filter.value, { state }),
})
);
if (cache) {
const newKey = JSON.stringify(boundFilters);
if (
cache.key == newKey &&
cache.loadTime == this.loadTime &&
cache.result
) {
cache.updated = false;
return cache.result;
}
cache.key = newKey;
}
const result = this.allrows.some((row) =>
boundFilters.every((filter) => match(filter, row))
);
if (cache) {
cache.result = result;
cache.updated = true;
cache.loadTime = this.loadTime;
}
return result;
}
}