EvalExternalQuery evaluates an external query. See ExternalPredicateCallback for more details.
(query ast.Atom, mode []ast.ArgMode, ext ExternalPredicateCallback, pushdown []ast.Term, cb func(fact ast.Atom) error)
| 80 | // EvalExternalQuery evaluates an external query. |
| 81 | // See ExternalPredicateCallback for more details. |
| 82 | func (q QueryContext) EvalExternalQuery(query ast.Atom, mode []ast.ArgMode, |
| 83 | ext ExternalPredicateCallback, pushdown []ast.Term, cb func(fact ast.Atom) error) error { |
| 84 | // Step 1. Check if we already have the facts. |
| 85 | err := q.Store.GetFacts(query, func(fact ast.Atom) error { |
| 86 | return errFound |
| 87 | }) |
| 88 | if err != nil { |
| 89 | if errors.Is(err, errFound) { |
| 90 | return nil |
| 91 | } |
| 92 | return err |
| 93 | } |
| 94 | // Step 2. Check if we need to query. |
| 95 | var inputs []ast.Constant |
| 96 | var filters []ast.BaseTerm |
| 97 | for i, arg := range query.Args { |
| 98 | if mode[i] == ast.ArgModeInput { |
| 99 | inputs = append(inputs, arg.(ast.Constant)) |
| 100 | } else { |
| 101 | filters = append(filters, arg) |
| 102 | } |
| 103 | } |
| 104 | if !ext.ShouldQuery(inputs, filters, pushdown) { |
| 105 | return nil |
| 106 | } |
| 107 | // Step 3. Query and add facts. |
| 108 | var hasFilters bool |
| 109 | for _, filter := range filters { |
| 110 | if _, ok := filter.(ast.Variable); !ok { |
| 111 | hasFilters = true |
| 112 | break |
| 113 | } |
| 114 | } |
| 115 | return ext.ExecuteQuery(inputs, filters, pushdown, func(output []ast.BaseTerm) { |
| 116 | j := 0 |
| 117 | args := make([]ast.BaseTerm, query.Predicate.Arity) |
| 118 | for i, arg := range query.Args { |
| 119 | if mode[i] == ast.ArgModeInput { |
| 120 | args[i] = arg |
| 121 | } else if !hasFilters { |
| 122 | args[i] = output[j] |
| 123 | j++ |
| 124 | } else { // check if filters match |
| 125 | res := output[j] |
| 126 | c, ok := arg.(ast.Constant) |
| 127 | if !ok || c.Equals(res) { |
| 128 | args[i] = res |
| 129 | j++ |
| 130 | } else { |
| 131 | return // skip this output |
| 132 | } |
| 133 | } |
| 134 | } |
| 135 | cb(ast.Atom{query.Predicate, args}) |
| 136 | }) |
| 137 | } |
| 138 | |
| 139 | // EvalPremise evaluates a single premise top-down. |
no test coverage detected