(
store: StoreQueries<R>,
typeName: TypeName,
query: QueryExpression<Extract<R, { typeName: TypeName }>>
)
| 137 | * @public |
| 138 | */ |
| 139 | export function executeQuery<R extends UnknownRecord, TypeName extends R['typeName']>( |
| 140 | store: StoreQueries<R>, |
| 141 | typeName: TypeName, |
| 142 | query: QueryExpression<Extract<R, { typeName: TypeName }>> |
| 143 | ): Set<IdOf<Extract<R, { typeName: TypeName }>>> { |
| 144 | type S = Extract<R, { typeName: TypeName }> |
| 145 | |
| 146 | // Extract all paths with matchers (flattens nested queries) |
| 147 | const matcherPaths = extractMatcherPaths(query) |
| 148 | |
| 149 | // Build a set of matching IDs for each path |
| 150 | const matchIds = Object.fromEntries(matcherPaths.map(({ path }) => [path, new Set<IdOf<S>>()])) |
| 151 | |
| 152 | // For each path, use the index to find matching IDs |
| 153 | for (const { path, matcher } of matcherPaths) { |
| 154 | const index = store.index(typeName, path as any) |
| 155 | |
| 156 | if ('eq' in matcher) { |
| 157 | const ids = index.get().get(matcher.eq) |
| 158 | if (ids) { |
| 159 | for (const id of ids) { |
| 160 | matchIds[path].add(id) |
| 161 | } |
| 162 | } |
| 163 | } else if ('neq' in matcher) { |
| 164 | for (const [value, ids] of index.get()) { |
| 165 | if (value !== matcher.neq) { |
| 166 | for (const id of ids) { |
| 167 | matchIds[path].add(id) |
| 168 | } |
| 169 | } |
| 170 | } |
| 171 | } else if ('gt' in matcher) { |
| 172 | for (const [value, ids] of index.get()) { |
| 173 | if (typeof value === 'number' && value > matcher.gt) { |
| 174 | for (const id of ids) { |
| 175 | matchIds[path].add(id) |
| 176 | } |
| 177 | } |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | // Short-circuit if this set is empty - intersection will be empty |
| 182 | if (matchIds[path].size === 0) { |
| 183 | return new Set() |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | // Intersect all the match sets |
| 188 | return intersectSets(Object.values(matchIds)) as Set<IdOf<S>> |
| 189 | } |
searching dependent graphs…