-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDataFilters.html
More file actions
275 lines (273 loc) · 41.6 KB
/
DataFilters.html
File metadata and controls
275 lines (273 loc) · 41.6 KB
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
<html><style>body { overflow:hidden;}
h1 { font-family: Arial, sans-serif; font-size: 24px; color: #44a; }
p { margin:0; padding:0; }
br { margin:0; padding:0; }
.line {
white-space: nowrap;
height:16px;
}
.line>span {
display:inline-block; background-color:#eef; height:100%;
margin: 0 5px 0 0; padding-right: 5px; color:#999;
}
comment {color: #080;} module {color: #804;}
quote {color: #008;} comment>quote {color: #080;}
.listing { margin: 10px; border: 1px solid #ccc;
font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, Courier, monospace;
font-size: 14px;
overflow:scroll;
height:90%;
}
code { padding: 5px 0;}</style></html><body>
<h1>DataFilters.ts</h1>
<div class='listing'><code><p id=1 class="line"><span> 1</span></p>
<p id=2 class="line"><span> 2</span><comment>/**</comment></p>
<p id=3 class="line"><span> 3</span><comment>* Use the {@link filter `filter`} function to executes a queries on a {@link Data `Data`} object. </comment></p>
<p id=4 class="line"><span> 4</span><comment>* Each row in the data is checked and those for which `conditions` holds true are returned as a new `Data` object. </comment></p>
<p id=5 class="line"><span> 5</span><comment>* </comment></p>
<p id=6 class="line"><span> 6</span><comment>* # Condition construction</comment></p>
<p id=7 class="line"><span> 7</span><comment>* </comment></p>
<p id=8 class="line"><span> 8</span><comment>* ### General Condition</comment></p>
<p id=9 class="line"><span> 9</span><comment>* ```</comment></p>
<p id=10 class="line"><span> 10</span><comment>* Condition = </comment></p>
<p id=11 class="line"><span> 11</span><comment>* IndexCondition -> conditions on the row index</comment></p>
<p id=12 class="line"><span> 12</span><comment>* || RecursiveCondition -> (set of) conditions on column values</comment></p>
<p id=13 class="line"><span> 13</span><comment>* ```</comment></p>
<p id=14 class="line"><span> 14</span><comment>* </comment></p>
<p id=15 class="line"><span> 15</span><comment>* ### IndexCondition</comment></p>
<p id=16 class="line"><span> 16</span><comment>* ```</comment></p>
<p id=17 class="line"><span> 17</span><comment>* IndexCondition =</comment></p>
<p id=18 class="line"><span> 18</span><comment>* rowIndex:number -> true if row index matches</comment></p>
<p id=19 class="line"><span> 19</span><comment>* ```</comment></p>
<p id=20 class="line"><span> 20</span><comment>* </comment></p>
<p id=21 class="line"><span> 21</span><comment>* ### RecursiveCondition</comment></p>
<p id=22 class="line"><span> 22</span><comment>* ```</comment></p>
<p id=23 class="line"><span> 23</span><comment>* RecursiveCondition =</comment></p>
<p id=24 class="line"><span> 24</span><comment>* OrCondition -> OR: true if any compound condition is true</comment></p>
<p id=25 class="line"><span> 25</span><comment>* || AndCondition -> AND: true if all compound conditions are true</comment></p>
<p id=26 class="line"><span> 26</span><comment>* </comment></p>
<p id=27 class="line"><span> 27</span><comment>* OrCondition = -> OR: true if</comment></p>
<p id=28 class="line"><span> 28</span><comment>* AndCondition[] -> any of the AndConditions are true</comment></p>
<p id=29 class="line"><span> 29</span><comment>* || IndexCondition[] -> any of thr IndexConditions are true</comment></p>
<p id=30 class="line"><span> 30</span><comment>* </comment></p>
<p id=31 class="line"><span> 31</span><comment>* AndCondition = -> AND: true if</comment></p>
<p id=32 class="line"><span> 32</span><comment>* SetAndCondition -> all SetAndConditions are true</comment></p>
<p id=33 class="line"><span> 33</span><comment>* || TermAndCondition -> or if all TermAndConditions are true</comment></p>
<p id=34 class="line"><span> 34</span><comment>*</comment></p>
<p id=35 class="line"><span> 35</span><comment>* SetAndCondition = { -> AND: true if all sub-conditions are true</comment></p>
<p id=36 class="line"><span> 36</span><comment>* <quote>'or'</quote>: RecursiveCondition -> true if any RecursiveCondition is true</comment></p>
<p id=37 class="line"><span> 37</span><comment>* || <quote>'and'</quote>: RecursiveCondition -> true if all RecursiveCondition are true</comment></p>
<p id=38 class="line"><span> 38</span><comment>* || <quote>'not'</quote>: RecursiveCondition -> true if the condition is false</comment></p>
<p id=39 class="line"><span> 39</span><comment>*</comment></p>
<p id=40 class="line"><span> 40</span><comment>* TermAndCondition = { -> Terminal AND: true if all terminal sub-conditions are true</comment></p>
<p id=41 class="line"><span> 41</span><comment>* colDesc:colValue -> true if colValue matches </comment></p>
<p id=42 class="line"><span> 42</span><comment>* || colDesc:[colValue, ...] -> true if any of the colValues match</comment></p>
<p id=43 class="line"><span> 43</span><comment>* || colDesc:function(value,row) -> true if function returns true </comment></p>
<p id=44 class="line"><span> 44</span><comment>* }</comment></p>
<p id=45 class="line"><span> 45</span><comment>* </comment></p>
<p id=46 class="line"><span> 46</span><comment>* colDesc = either column name or index</comment></p>
<p id=47 class="line"><span> 47</span><comment>* ```</comment></p>
<p id=48 class="line"><span> 48</span><comment>* </comment></p>
<p id=49 class="line"><span> 49</span><comment>* ### Practical Tips</comment></p>
<p id=50 class="line"><span> 50</span><comment>* ```</comment></p>
<p id=51 class="line"><span> 51</span><comment>* {<quote>'or'</quote>: [recurCond, ...]} -> OR, same as [recurCond, ...]</comment></p>
<p id=52 class="line"><span> 52</span><comment>* || {<quote>'or'</quote>: {SetCond, ...}} -> OR, same as [SetCond, ...]</comment></p>
<p id=53 class="line"><span> 53</span><comment>* || {<quote>'and'</quote>: [recurCond, ...]} -> AND, true if all recurCond are true</comment></p>
<p id=54 class="line"><span> 54</span><comment>* || {<quote>'and'</quote>: {SetCond, ...}} -> AND, same as {SetCond, ...}</comment></p>
<p id=55 class="line"><span> 55</span><comment>* || {<quote>'not'</quote>: {SetCond, ...}} -> NAND: true if the SetCond are true</comment></p>
<p id=56 class="line"><span> 56</span><comment>* || {<quote>'not'</quote>: [recurCond, ...]} -> NOR: true if any of the recurCond are true</comment></p>
<p id=57 class="line"><span> 57</span><comment>* ```</comment></p>
<p id=58 class="line"><span> 58</span><comment>* </comment></p>
<p id=59 class="line"><span> 59</span><comment>* # Example</comment></p>
<p id=60 class="line"><span> 60</span><comment>* <example height=1000px libs={hsDatab:hsDatab}></comment></p>
<p id=61 class="line"><span> 61</span><comment>* <file name=<quote>"script.js"</quote>></comment></p>
<p id=62 class="line"><span> 62</span><comment>* const colNames = [<quote>'Name'</quote>, <quote>'Value'</quote>, <quote>'Start'</quote>, <quote>'End'</quote>];</comment></p>
<p id=63 class="line"><span> 63</span><comment>* const rows = [</comment></p>
<p id=64 class="line"><span> 64</span><comment>* [<quote>'Harry'</quote>, <quote>'100'</quote>, <quote>'3/1/14'</quote>, <quote>'11/20/14'</quote>], </comment></p>
<p id=65 class="line"><span> 65</span><comment>* [<quote>'Mary'</quote>, <quote>'1500'</quote>, <quote>'7/1/14'</quote>, <quote>'9/30/14'</quote>],</comment></p>
<p id=66 class="line"><span> 66</span><comment>* [<quote>'Peter'</quote>, <quote>'400'</quote>, <quote>'5/20/14'</quote>, <quote>'4/30/15'</quote>], </comment></p>
<p id=67 class="line"><span> 67</span><comment>* [<quote>'Jane'</quote>, <quote>'700'</quote>, <quote>'11/13/14'</quote>, <quote>'8/15/15'</quote>]</comment></p>
<p id=68 class="line"><span> 68</span><comment>* ]</comment></p>
<p id=69 class="line"><span> 69</span><comment>* const data = new hsDatab.Data({colNames:colNames, rows:rows});</comment></p>
<p id=70 class="line"><span> 70</span><comment>* </comment></p>
<p id=71 class="line"><span> 71</span><comment>* queries = [</comment></p>
<p id=72 class="line"><span> 72</span><comment>* [<quote>'0'</quote>, undefined, <quote>'undefined query => pass all'</quote>],</comment></p>
<p id=73 class="line"><span> 73</span><comment>* [<quote>'1'</quote>, [], <quote>'empty OR: [] => fail all'</quote>],</comment></p>
<p id=74 class="line"><span> 74</span><comment>* [<quote>'2'</quote>, {}, <quote>'empty AND: {} => pass all'</quote>],</comment></p>
<p id=75 class="line"><span> 75</span><comment>* [<quote>'3'</quote>, 1, <quote>'2nd row: pass row 1'</quote>],</comment></p>
<p id=76 class="line"><span> 76</span><comment>* [<quote>'4'</quote>, [1,3], <quote>'2nd+4th: pass rows: 1 and 3'</quote>],</comment></p>
<p id=77 class="line"><span> 77</span><comment>* [<quote>'5'</quote>, {Name:<quote>"Jane"</quote>}, <quote>'Name is Jane'</quote>],</comment></p>
<p id=78 class="line"><span> 78</span><comment>* [<quote>'6'</quote>, {1:1500}, <quote>'Column 2 is 1500'</quote>],</comment></p>
<p id=79 class="line"><span> 79</span><comment>* [<quote>'7'</quote>, {Name:[<quote>"Peter"</quote>, <quote>"Jane"</quote>]}, <quote>'Name is Peter or Jane'</quote>],</comment></p>
<p id=80 class="line"><span> 80</span><comment>* [<quote>'8'</quote>, [{Name:<quote>"Peter"</quote>}, {Value:1500}], <quote>'Name is Peter or Value is 1500'</quote>],</comment></p>
<p id=81 class="line"><span> 81</span><comment>* [<quote>'9'</quote>, {or:{Name:<quote>"Peter"</quote>, Value:1500}}, <quote>'OR: same as 8:'</quote>],</comment></p>
<p id=82 class="line"><span> 82</span><comment>* [<quote>'A'</quote>, {or:[{Name:<quote>"Peter"</quote>}, {Value:1500}]}, <quote>'OR: [{Name is Peter}, {Value is 1500}]'</quote>],</comment></p>
<p id=83 class="line"><span> 83</span><comment>* [<quote>'B'</quote>, {Name:<quote>"Peter"</quote>, Value:400}, <quote>'Name is Peter and Value is 400'</quote>],</comment></p>
<p id=84 class="line"><span> 84</span><comment>* [<quote>'C'</quote>, {and:{Name:<quote>"Peter"</quote>, Value:400}}, <quote>'AND: {Name is Peter, Value is 400}'</quote>],</comment></p>
<p id=85 class="line"><span> 85</span><comment>* [<quote>'D'</quote>, {and:{Name:<quote>"Peter"</quote>, Value:1500}}, <quote>'AND: {Name is Peter, Value is 1500}'</quote>],</comment></p>
<p id=86 class="line"><span> 86</span><comment>* [<quote>'E'</quote>, {and:[{Name:<quote>"Peter"</quote>}, {Value:400}]}, <quote>'AND:[{Name is Peter}, {Value is 400}]'</quote>],</comment></p>
<p id=87 class="line"><span> 87</span><comment>* [<quote>'F'</quote>, {and:[{Name:<quote>"Peter"</quote>}, {Value:1500}]},<quote>'AND:[{Name is Peter}, {Value is 1500}]'</quote>],</comment></p>
<p id=88 class="line"><span> 88</span><comment>* [<quote>'G'</quote>, {not:{Name:<quote>"Peter"</quote>, Value:400}}, <quote>'NAND: not {Name is Peter and Value is 400}'</quote>],</comment></p>
<p id=89 class="line"><span> 89</span><comment>* [<quote>'H'</quote>, {not:{Name:<quote>"Peter"</quote>, Value:1500}}, <quote>'NAND: not {Name is Peter and Value is 1500}'</quote>],</comment></p>
<p id=90 class="line"><span> 90</span><comment>* [<quote>'I'</quote>, {not:[{Name:<quote>"Peter"</quote>}, {Value:1500}]},<quote>'NOR: not [{Name is Peter} or {Value is 1500}]'</quote>],</comment></p>
<p id=91 class="line"><span> 91</span><comment>* [<quote>'J'</quote>, {Name:(v) => v.length===4}, <quote>'Name has 4 letters'</quote>]</comment></p>
<p id=92 class="line"><span> 92</span><comment>* ];</comment></p>
<p id=93 class="line"><span> 93</span><comment>*</comment></p>
<p id=94 class="line"><span> 94</span><comment>* m.mount(root, { </comment></p>
<p id=95 class="line"><span> 95</span><comment>* view:() => m(<quote>''</quote>, [</comment></p>
<p id=96 class="line"><span> 96</span><comment>* m(<quote>'h3'</quote>, <quote>'Given the data set:'</quote>),</comment></p>
<p id=97 class="line"><span> 97</span><comment>* m(<quote>'table#data'</quote>, [</comment></p>
<p id=98 class="line"><span> 98</span><comment>* m(<quote>'tr'</quote>, colNames.map(n => m(<quote>'th'</quote>, n))),</comment></p>
<p id=99 class="line"><span> 99</span><comment>* ...rows.map(row => m(<quote>'tr'</quote>, [m(<quote>'td'</quote>, row[0]),m(<quote>'td'</quote>, row[1]),m(<quote>'td'</quote>, row[2].toDateString()),m(<quote>'td'</quote>, row[3].toDateString())]))</comment></p>
<p id=100 class="line"><span> 100</span><comment>* ]),</comment></p>
<p id=101 class="line"><span> 101</span><comment>* m(<quote>'h3'</quote>, <quote>'The following queries yield:'</quote>),</comment></p>
<p id=102 class="line"><span> 102</span><comment>* m(<quote>'table'</quote>, [</comment></p>
<p id=103 class="line"><span> 103</span><comment>* m(<quote>'tr'</quote>, [m(<quote>'th'</quote>,<quote>'#'</quote>), m(<quote>'th'</quote>,<quote>'Query'</quote>), m(<quote>'th'</quote>,<quote>"Live Result, by <quote>'Name'</quote> field"</quote>)]),</comment></p>
<p id=104 class="line"><span> 104</span><comment>* ...queries.map(q => {</comment></p>
<p id=105 class="line"><span> 105</span><comment>* const result = data.filter(q[1]).getColumn(<quote>'Name'</quote>).join(<quote>', '</quote>);</comment></p>
<p id=106 class="line"><span> 106</span><comment>* return m(<quote>'tr'</quote>, [m(<quote>'td'</quote>,`${q[0]}:`), m(<quote>'td'</quote>,`${q[2]}`), m(<quote>'td'</quote>,`[ ${result} ]`)]);</comment></p>
<p id=107 class="line"><span> 107</span><comment>* })</comment></p>
<p id=108 class="line"><span> 108</span><comment>* ])</comment></p>
<p id=109 class="line"><span> 109</span><comment>* ])</comment></p>
<p id=110 class="line"><span> 110</span><comment>* });</comment></p>
<p id=111 class="line"><span> 111</span><comment>* </file></comment></p>
<p id=112 class="line"><span> 112</span><comment>* <file name=<quote>'style.css'</quote>></comment></p>
<p id=113 class="line"><span> 113</span><comment>* $exampleID { height: 600px; }</comment></p>
<p id=114 class="line"><span> 114</span><comment>* #data th { width:15%; }</comment></p>
<p id=115 class="line"><span> 115</span><comment>* table { </comment></p>
<p id=116 class="line"><span> 116</span><comment>* font-size: 10pt;</comment></p>
<p id=117 class="line"><span> 117</span><comment>* margin-left: 10px;</comment></p>
<p id=118 class="line"><span> 118</span><comment>* }</comment></p>
<p id=119 class="line"><span> 119</span><comment>* </file></comment></p>
<p id=120 class="line"><span> 120</span><comment>* </example> </comment></p>
<p id=121 class="line"><span> 121</span><comment>*/</comment></p>
<p id=122 class="line"><span> 122</span></p>
<p id=123 class="line"><span> 123</span><comment>/** */</comment></p>
<p id=124 class="line"><span> 124</span>import { Data, DataVal, DataRow } from <quote>'./Data'</quote>; </p>
<p id=125 class="line"><span> 125</span>import { Log} from <quote>'hsutil'</quote>; const log = new Log(<quote>'DataFilters'</quote>);</p>
<p id=126 class="line"><span> 126</span></p>
<p id=127 class="line"><span> 127</span></p>
<p id=128 class="line"><span> 128</span>export type Condition = IndexCondition | RecursiveCondition;</p>
<p id=129 class="line"><span> 129</span></p>
<p id=130 class="line"><span> 130</span><comment>/** true if row index matches the number(s) */</comment></p>
<p id=131 class="line"><span> 131</span>export type IndexCondition = number;</p>
<p id=132 class="line"><span> 132</span></p>
<p id=133 class="line"><span> 133</span>export type RecursiveCondition = AndCondition | OrCondition;</p>
<p id=134 class="line"><span> 134</span>export type OrCondition = AndCondition[] | IndexCondition[];</p>
<p id=135 class="line"><span> 135</span>export type AndCondition = SetAndCondition | TermAndCondition;</p>
<p id=136 class="line"><span> 136</span></p>
<p id=137 class="line"><span> 137</span>export interface SetAndCondition {</p>
<p id=138 class="line"><span> 138</span> or?: RecursiveCondition;</p>
<p id=139 class="line"><span> 139</span> and?:RecursiveCondition;</p>
<p id=140 class="line"><span> 140</span> not?:RecursiveCondition;</p>
<p id=141 class="line"><span> 141</span>}</p>
<p id=142 class="line"><span> 142</span></p>
<p id=143 class="line"><span> 143</span>export interface TermAndCondition { </p>
<p id=144 class="line"><span> 144</span> [colDesc:string]: </p>
<p id=145 class="line"><span> 145</span> DataVal </p>
<p id=146 class="line"><span> 146</span> | DataVal[]</p>
<p id=147 class="line"><span> 147</span> | TermConditionFunction</p>
<p id=148 class="line"><span> 148</span> ;</p>
<p id=149 class="line"><span> 149</span>}</p>
<p id=150 class="line"><span> 150</span></p>
<p id=151 class="line"><span> 151</span>export type TermConditionFunction = (value:DataVal, row:DataRow) => boolean;</p>
<p id=152 class="line"><span> 152</span></p>
<p id=153 class="line"><span> 153</span>function resolveTerminalCondition(name:string, val:any, row:DataRow, colNumber:(name:string)=>number):boolean { </p>
<p id=154 class="line"><span> 154</span> const col = colNumber(name);</p>
<p id=155 class="line"><span> 155</span> const valIsFunction = (typeof val === <quote>'function'</quote>);</p>
<p id=156 class="line"><span> 156</span> const valIsArray = ((typeof val === <quote>'object'</quote>) && (val.length!==undefined));</p>
<p id=157 class="line"><span> 157</span> if (isNaN(col)) { </p>
<p id=158 class="line"><span> 158</span> log.warn(`column name <quote>'${name}'</quote> cannot be resolved in terminal condition ${name}=${val}`);</p>
<p id=159 class="line"><span> 159</span> log.warn(row);</p>
<p id=160 class="line"><span> 160</span> return false; <comment>// -> this condition is not met;</comment></p>
<p id=161 class="line"><span> 161</span><comment></comment> } else if (valIsFunction) { </p>
<p id=162 class="line"><span> 162</span> <comment>// query true if function evaluates to true</comment></p>
<p id=163 class="line"><span> 163</span><comment></comment> return val(row[col], row);</p>
<p id=164 class="line"><span> 164</span> } else if (valIsArray) {</p>
<p id=165 class="line"><span> 165</span> <comment>// query true if empty array, or at least one c true</comment></p>
<p id=166 class="line"><span> 166</span><comment></comment> return (val.length === 0) || val.some((v:any) => row[col] === v); </p>
<p id=167 class="line"><span> 167</span> } else { <comment>// object: all conditions have to be met, unless specified as or</comment></p>
<p id=168 class="line"><span> 168</span><comment></comment> return (row[col] === val); </p>
<p id=169 class="line"><span> 169</span> }</p>
<p id=170 class="line"><span> 170</span>}</p>
<p id=171 class="line"><span> 171</span></p>
<p id=172 class="line"><span> 172</span><comment>/**</comment></p>
<p id=173 class="line"><span> 173</span><comment> * applies `condition` to a row of data and returns `true` if the row passes.</comment></p>
<p id=174 class="line"><span> 174</span><comment> * @param condition the complex condition to test against</comment></p>
<p id=175 class="line"><span> 175</span><comment> * @param r the row index in the data set</comment></p>
<p id=176 class="line"><span> 176</span><comment> * @param row the row values </comment></p>
<p id=177 class="line"><span> 177</span><comment> * @param and </comment></p>
<p id=178 class="line"><span> 178</span><comment> */</comment></p>
<p id=179 class="line"><span> 179</span>function resolveCondition(condition:Condition, row:DataRow, r:number, colNumber:(name:string)=>number, and?:boolean):boolean { </p>
<p id=180 class="line"><span> 180</span> let orResult = false;</p>
<p id=181 class="line"><span> 181</span> let andResult= true; </p>
<p id=182 class="line"><span> 182</span> <comment>// undefined condition is TRUE</comment></p>
<p id=183 class="line"><span> 183</span><comment></comment> if (condition===undefined) { return true; }</p>
<p id=184 class="line"><span> 184</span> </p>
<p id=185 class="line"><span> 185</span> <comment>// Simple Index Condition on row index:</comment></p>
<p id=186 class="line"><span> 186</span><comment></comment> else if (typeof condition === <quote>'number'</quote>) { return (condition === r); }</p>
<p id=187 class="line"><span> 187</span></p>
<p id=188 class="line"><span> 188</span> <comment>// Recursive Condition - OR: [...], AND {...}: </comment></p>
<p id=189 class="line"><span> 189</span><comment></comment> else if (typeof condition === <quote>'object'</quote>) {</p>
<p id=190 class="line"><span> 190</span> <comment>// array -> or condition on a list of row indices or compound conditions</comment></p>
<p id=191 class="line"><span> 191</span><comment></comment> const mc = <AndCondition[]>condition;</p>
<p id=192 class="line"><span> 192</span></p>
<p id=193 class="line"><span> 193</span> <comment>// OR condition: [...], or:[], not:[]</comment></p>
<p id=194 class="line"><span> 194</span><comment></comment> if (mc.length !== undefined) { </p>
<p id=195 class="line"><span> 195</span> if (and === undefined) { and = false; } </p>
<p id=196 class="line"><span> 196</span> if (mc.length === 0) { return false; } <comment>// empty OR is false: </comment></p>
<p id=197 class="line"><span> 197</span><comment></comment> <comment>// else: OR is true if any sub-condition is met </comment></p>
<p id=198 class="line"><span> 198</span><comment></comment> return and?</p>
<p id=199 class="line"><span> 199</span> mc.every((cd:AndCondition) => resolveCondition(cd, row, r, colNumber, and)) :</p>
<p id=200 class="line"><span> 200</span> mc.some((cd:AndCondition) => resolveCondition(cd, row, r, colNumber, and));</p>
<p id=201 class="line"><span> 201</span> } </p>
<p id=202 class="line"><span> 202</span> <comment>// AND condition: {...}, and:{}, not:{}</comment></p>
<p id=203 class="line"><span> 203</span><comment></comment> else { </p>
<p id=204 class="line"><span> 204</span> if (and === undefined) { and = true; } </p>
<p id=205 class="line"><span> 205</span> for (const name in condition) {</p>
<p id=206 class="line"><span> 206</span> let conditionMet = and; <comment>// initialize with false for OR, and true for AND conjunction</comment></p>
<p id=207 class="line"><span> 207</span><comment></comment> const setCond = <SetAndCondition>condition;</p>
<p id=208 class="line"><span> 208</span> </p>
<p id=209 class="line"><span> 209</span> <comment>// resolve SetConditions:</comment></p>
<p id=210 class="line"><span> 210</span><comment></comment> switch (name) {</p>
<p id=211 class="line"><span> 211</span> case <quote>'or'</quote>: conditionMet = resolveCondition(setCond.or, row, r, colNumber, false); break;</p>
<p id=212 class="line"><span> 212</span> case <quote>'and'</quote>: conditionMet = resolveCondition(setCond.and, row, r, colNumber, true); break;</p>
<p id=213 class="line"><span> 213</span> case <quote>'not'</quote>: conditionMet = !resolveCondition(setCond.not, row, r, colNumber); break;</p>
<p id=214 class="line"><span> 214</span> default: conditionMet = resolveTerminalCondition(name, condition[name], row, colNumber); </p>
<p id=215 class="line"><span> 215</span> }</p>
<p id=216 class="line"><span> 216</span> if (conditionMet) { orResult = true; if(!and) { break; }} <comment>// OR conjunction: exit for name loop if condition met</comment></p>
<p id=217 class="line"><span> 217</span><comment></comment> else { andResult = false; if(and) { break; }} <comment>// AND conjunction: exit for name loop if condition not met</comment></p>
<p id=218 class="line"><span> 218</span><comment></comment> }</p>
<p id=219 class="line"><span> 219</span> } </p>
<p id=220 class="line"><span> 220</span> } else {</p>
<p id=221 class="line"><span> 221</span> console.error(`unrecognized condition: ${JSON.stringify(condition)}`);</p>
<p id=222 class="line"><span> 222</span> return false;</p>
<p id=223 class="line"><span> 223</span> }</p>
<p id=224 class="line"><span> 224</span> return and? andResult : orResult;</p>
<p id=225 class="line"><span> 225</span>}</p>
<p id=226 class="line"><span> 226</span></p>
<p id=227 class="line"><span> 227</span><comment>/**</comment></p>
<p id=228 class="line"><span> 228</span><comment> * filters a `Data` object for the given `Condition`s and returns a new `Data` object with those rows for which</comment></p>
<p id=229 class="line"><span> 229</span><comment> * `cond` holds true.</comment></p>
<p id=230 class="line"><span> 230</span><comment> * @param data the `Data` object to filter</comment></p>
<p id=231 class="line"><span> 231</span><comment> * @param cond the complex condition to test against</comment></p>
<p id=232 class="line"><span> 232</span><comment> * @return a new `Data` object with the filtered rows </comment></p>
<p id=233 class="line"><span> 233</span><comment> */</comment></p>
<p id=234 class="line"><span> 234</span>export function filter(data:Data, cond:Condition):Data {</p>
<p id=235 class="line"><span> 235</span> const colNumber = (name:string):number => data.colNumber(name);</p>
<p id=236 class="line"><span> 236</span> try {</p>
<p id=237 class="line"><span> 237</span> return new Data({</p>
<p id=238 class="line"><span> 238</span> name: data.getName(),</p>
<p id=239 class="line"><span> 239</span> colNames: data.colNames(), </p>
<p id=240 class="line"><span> 240</span> rows:data.getData().filter((row:DataRow, i:number) => {</p>
<p id=241 class="line"><span> 241</span> const keep = resolveCondition(cond, row, i, colNumber);</p>
<p id=242 class="line"><span> 242</span> return keep;</p>
<p id=243 class="line"><span> 243</span> })</p>
<p id=244 class="line"><span> 244</span> });</p>
<p id=245 class="line"><span> 245</span> } catch(err) {</p>
<p id=246 class="line"><span> 246</span> log.warn(err);</p>
<p id=247 class="line"><span> 247</span> log.warn(err.stack);</p>
<p id=248 class="line"><span> 248</span> }</p>
<p id=249 class="line"><span> 249</span>}</p>
<p id=250 class="line"><span> 250</span></p></code></div>
</body>