/ test / evaluation.spec.js
evaluation.spec.js
  1  import { Memory, Task, Link, $, Analyzer } from './lib.js'
  2  import * as Match from '../src/match.js'
  3  
  4  /**
  5   * @type {import('entail').Suite}
  6   */
  7  export const testEvaluation = {
  8    'plans negation last': async (assert) => {
  9      const db = Memory.create({ alice })
 10  
 11      const plan = Analyzer.rule({
 12        match: {
 13          manager: $.manager,
 14          employee: $.employee,
 15          managerName: $.managerName,
 16          employeeName: $.employeeName,
 17        },
 18        when: {
 19          where: [
 20            {
 21              match: {
 22                name: $.managerName,
 23                supervisor: $.manager,
 24                report: $.employee,
 25              },
 26              rule: {
 27                match: {
 28                  name: $.name,
 29                  supervisor: $.supervisor,
 30                  report: $.report,
 31                },
 32                when: {
 33                  where: [
 34                    {
 35                      match: {
 36                        the: 'person/name',
 37                        of: $.supervisor,
 38                        is: $.name,
 39                      },
 40                    },
 41                    {
 42                      match: {
 43                        the: 'work/report',
 44                        of: $.supervisor,
 45                        is: $.report,
 46                      },
 47                    },
 48                  ],
 49                },
 50              },
 51            },
 52            {
 53              match: {
 54                person: $.employee,
 55                name: $.employeeName,
 56              },
 57              rule: {
 58                match: {
 59                  name: $.name,
 60                  person: $.person,
 61                },
 62                when: {
 63                  where: [
 64                    {
 65                      match: {
 66                        the: 'person/name',
 67                        of: $.person,
 68                        is: $.name,
 69                      },
 70                    },
 71                  ],
 72                },
 73              },
 74            },
 75          ],
 76        },
 77      })
 78        .apply({
 79          manager: $.$manager,
 80          employee: $.$employee,
 81          managerName: $.$managerName,
 82          employeeName: $.$employeeName,
 83        })
 84        .prepare()
 85  
 86      const result = await Task.perform(plan.query({ from: db }))
 87  
 88      assert.deepEqual(
 89        [...result],
 90        [
 91          Match.from([
 92            [$.$manager, Link.of(alice)],
 93            [$.$employee, Link.of(bob)],
 94            [$.$managerName, 'Alice'],
 95            [$.$employeeName, 'Bob'],
 96          ]),
 97          Match.from([
 98            [$.$manager, Link.of(bob)],
 99            [$.$employee, Link.of(mallory)],
100            [$.$managerName, 'Bob'],
101            [$.$employeeName, 'Mallory'],
102          ]),
103        ]
104      )
105    },
106  
107    'same variable as different binding': async (assert) => {
108      const db = Memory.create({ alice })
109  
110      const rule = Analyzer.rule({
111        match: {
112          a: $.a,
113          actual: $.aa,
114          b: $.b,
115          expect: $.bb,
116        },
117        when: {
118          where: [
119            {
120              match: {
121                the: 'person/name',
122                of: $.a,
123                is: $.aa,
124              },
125            },
126            {
127              match: {
128                the: 'person/name',
129                of: $.b,
130                is: $.bb,
131              },
132            },
133          ],
134        },
135      })
136  
137      const plan = rule
138        .apply({
139          a: $.subject,
140          actual: $.actual,
141          b: $.subject,
142          expect: $.expect,
143        })
144        .prepare()
145  
146      const result = await Task.perform(plan.query({ from: db }))
147  
148      assert.deepEqual(
149        [...result],
150        [
151          Match.from([
152            [$.subject, Link.of(alice)],
153            [$.actual, 'Alice'],
154            [$.expect, 'Alice'],
155          ]),
156          Match.from([
157            [$.subject, Link.of(bob)],
158            [$.actual, 'Bob'],
159            [$.expect, 'Bob'],
160          ]),
161          Match.from([
162            [$.subject, Link.of(mallory)],
163            [$.actual, 'Mallory'],
164            [$.expect, 'Mallory'],
165          ]),
166          // {
167          //   a: Link.of(alice),
168          //   actual: 'Alice',
169          //   b: Link.of(alice),
170          //   expect: 'Alice',
171          // },
172          // {
173          //   a: Link.of(bob),
174          //   actual: 'Bob',
175          //   b: Link.of(bob),
176          //   expect: 'Bob',
177          // },
178          // {
179          //   a: Link.of(mallory),
180          //   actual: 'Mallory',
181          //   b: Link.of(mallory),
182          //   expect: 'Mallory',
183          // },
184        ]
185      )
186    },
187  
188    'test generate query': async (assert) => {
189      const mallory = { 'Person/name': 'Mallory' }
190      const bob = {
191        'Person/name': 'Bob',
192        'Manages/employee': mallory,
193      }
194      const alice = {
195        'Person/name': 'Alice',
196        'Manages/employee': bob,
197      }
198      const db = Memory.create({ alice })
199  
200      const rule = Analyzer.rule({
201        match: {
202          this: $.this,
203          'name.the': $['name.the'],
204          'name.is': $['name.is'],
205          'name.of': $.this,
206          'manages.the': $['manages.the'],
207          'manages.is.name.the': $['manages.is.name.the'],
208          'manages.is.name.is': $['manages.is.name.is'],
209          'manages.of': $.this,
210        },
211        when: {
212          where: [
213            {
214              match: { the: $['name.the'], is: $['name.is'], of: $.this },
215              rule: {
216                match: { the: $.the, is: $.is, of: $.of },
217                when: {
218                  where: [
219                    { match: { of: 'Person/name', is: $.the }, operator: '==' },
220                    { match: { the: $.the, of: $.of, is: $.is } },
221                    { match: { of: $.is, is: 'string' }, operator: 'data/type' },
222                  ],
223                },
224              },
225            },
226            {
227              match: {
228                the: $['manages.the'],
229                'is.this': $['manages.is.this'],
230                'is.name.the': $['manages.is.name.the'],
231                'is.name.is': $['manages.is.name.is'],
232                of: $.this,
233              },
234              rule: {
235                match: {
236                  the: $.the,
237                  'is.this': $['is.this'],
238                  'is.name.the': $['is.name.the'],
239                  'is.name.is': $['is.name.is'],
240                  of: $.of,
241                },
242                when: {
243                  where: [
244                    {
245                      match: { of: 'Manages/employee', is: $.the },
246                      operator: '==',
247                    },
248                    { match: { the: $.the, of: $.of, is: $['is.this'] } },
249                    {
250                      match: {
251                        this: $['is.this'],
252                        'name.the': $['is.name.the'],
253                        'name.is': $['is.name.is'],
254                        'name.of': $['is.this'],
255                      },
256                      rule: {
257                        match: {
258                          this: $.this,
259                          'name.the': $['name.the'],
260                          'name.is': $['name.is'],
261                          'name.of': $.this,
262                        },
263                        when: {
264                          where: [
265                            {
266                              match: {
267                                the: $['name.the'],
268                                is: $['name.is'],
269                                of: $.this,
270                              },
271                              rule: {
272                                match: { the: $.the, is: $.is, of: $.of },
273                                when: {
274                                  where: [
275                                    {
276                                      match: { of: 'Person/name', is: $.the },
277                                      operator: '==',
278                                    },
279                                    { match: { the: $.the, of: $.of, is: $.is } },
280                                    {
281                                      match: { of: $.is, is: 'string' },
282                                      operator: 'data/type',
283                                    },
284                                  ],
285                                },
286                              },
287                            },
288                          ],
289                        },
290                      },
291                    },
292                  ],
293                },
294              },
295            },
296          ],
297        },
298      })
299  
300      const result = await Task.perform(rule.apply().query({ from: db }))
301  
302      assert.deepEqual(
303        [...result],
304        [
305          Match.from([
306            [$.this, Link.of(alice)],
307            [$['name.the'], 'Person/name'],
308            [$['name.is'], 'Alice'],
309            [$['manages.the'], 'Manages/employee'],
310            [$['manages.is.name.the'], 'Person/name'],
311            [$['manages.is.name.is'], 'Bob'],
312          ]),
313          Match.from([
314            [$.this, Link.of(bob)],
315            [$['name.the'], 'Person/name'],
316            [$['name.is'], 'Bob'],
317            [$['manages.the'], 'Manages/employee'],
318            [$['manages.is.name.the'], 'Person/name'],
319            [$['manages.is.name.is'], 'Mallory'],
320          ]),
321        ]
322      )
323    },
324  }
325  
326  const mallory = {
327    'person/name': 'Mallory',
328  }
329  
330  const bob = {
331    'person/name': 'Bob',
332    'work/report': mallory,
333  }
334  
335  const alice = {
336    'person/name': 'Alice',
337    'work/report': bob,
338  }