fix(mongodb): offer query operators by filter position
This commit is contained in:
1 parent
14aeb93081
commit
608633edff
3 files changed
+77
-16
No files matched your search
@@ -4,10 +4,11 @@ import {
|
||||
COMMON_OPERATORS,
|
||||
EXPRESSION_OPERATORS,
|
||||
EXTENDED_JSON_VALUES,
|
||||
FIELD_QUERY_OPERATORS,
|
||||
PIPELINE_STAGES,
|
||||
PUSH_MODIFIERS,
|
||||
QUERY_OPERATORS,
|
||||
STAGE_OPTION_KEYS,
|
||||
TOP_LEVEL_QUERY_OPERATORS,
|
||||
UPDATE_OPERATORS,
|
||||
UPDATE_OPERATOR_LABELS,
|
||||
VALUE_SNIPPETS,
|
||||
@@ -34,6 +35,7 @@ export type MongoCompletionMode =
|
||||
| "method"
|
||||
| "cursorMethod"
|
||||
| "field"
|
||||
| "filterField"
|
||||
| "fieldPath"
|
||||
| "fieldRef"
|
||||
| "value"
|
||||
@@ -310,6 +312,10 @@ export function buildMongoCompletionItemsFromContext(context: MongoCompletionCon
|
||||
case "field":
|
||||
items = fieldItems(prefix, fields);
|
||||
break;
|
||||
case "filterField":
|
||||
// Fields lead; `$and` / `$or` and the other whole-filter operators follow once `$` is typed.
|
||||
items = [...fieldItems(prefix, fields), ...specItems(TOP_LEVEL_QUERY_OPERATORS, prefix, "query operator", 80)];
|
||||
break;
|
||||
case "fieldPath":
|
||||
items = fieldPathItems(prefix, fields);
|
||||
break;
|
||||
@@ -325,7 +331,7 @@ export function buildMongoCompletionItemsFromContext(context: MongoCompletionCon
|
||||
break;
|
||||
case "queryOperator":
|
||||
// `{ _id: { $oid: ... } }` is as valid here as `{ _id: { $gt: ... } }`.
|
||||
items = [...specItems(QUERY_OPERATORS, prefix, "query operator", 100), ...specItems(EXTENDED_JSON_VALUES, prefix, "extended JSON value", 90)];
|
||||
items = [...specItems(FIELD_QUERY_OPERATORS, prefix, "query operator", 100), ...specItems(EXTENDED_JSON_VALUES, prefix, "extended JSON value", 90)];
|
||||
break;
|
||||
case "updateOperator":
|
||||
items = specItems(UPDATE_OPERATORS, prefix, "update operator", 100);
|
||||
@@ -353,7 +359,7 @@ export function buildMongoCompletionItemsFromContext(context: MongoCompletionCon
|
||||
|
||||
/** Modes whose items are built from the target collection's sampled fields. */
|
||||
export function mongoCompletionNeedsFields(mode: MongoCompletionMode): boolean {
|
||||
return mode === "field" || mode === "fieldPath" || mode === "fieldRef" || mode === "expression";
|
||||
return mode === "field" || mode === "filterField" || mode === "fieldPath" || mode === "fieldRef" || mode === "expression";
|
||||
}
|
||||
|
||||
/** Modes whose items are built from the database's collection names. */
|
||||
@@ -544,7 +550,7 @@ function classifyFilter(scan: MongoCallScan, rootIndex: number): MongoCompletion
|
||||
if (inner.kind === "array") return VALUE_ARRAY_OPERATORS.has(inner.key ?? "") && !scan.inString ? "value" : "none";
|
||||
if (inner.kind !== "object") return "none";
|
||||
if (scan.inValue) return scan.inString ? "none" : "value";
|
||||
if (innerDepth(scan, rootIndex) === 0) return "field";
|
||||
if (innerDepth(scan, rootIndex) === 0) return "filterField";
|
||||
|
||||
// Inside a nested object: whose value is it?
|
||||
switch (inner.key) {
|
||||
@@ -552,10 +558,10 @@ function classifyFilter(scan: MongoCallScan, rootIndex: number): MongoCompletion
|
||||
// An object inside an array: a sub-filter under `$and` / `$or` / `$nor`,
|
||||
// or an extended JSON wrapper such as `{ $oid: ... }` under `$in`.
|
||||
const parent = scan.stack[scan.stack.length - 2];
|
||||
return parent?.kind === "array" && VALUE_ARRAY_OPERATORS.has(parent.key ?? "") ? "valueWrapper" : "field";
|
||||
return parent?.kind === "array" && VALUE_ARRAY_OPERATORS.has(parent.key ?? "") ? "valueWrapper" : "filterField";
|
||||
}
|
||||
case "$elemMatch":
|
||||
return "field";
|
||||
return "filterField";
|
||||
case "$expr":
|
||||
return "expression";
|
||||
case "$jsonSchema":
|
||||
|
||||
@@ -38,7 +38,11 @@ export function mongoOperatorItemType(apply: string): "snippet" | "keyword" {
|
||||
return apply.includes("${") ? "snippet" : "keyword";
|
||||
}
|
||||
|
||||
export const QUERY_OPERATORS: MongoOperatorSpec[] = specs([
|
||||
/**
|
||||
* Operators that constrain one field, valid inside `{ field: { ... } }`.
|
||||
* `$and` / `$or` and friends are not: those go at the top level of a filter.
|
||||
*/
|
||||
export const FIELD_QUERY_OPERATORS: MongoOperatorSpec[] = specs([
|
||||
["$eq", "Matches values equal to a value", "$eq: ${}"],
|
||||
["$ne", "Matches values not equal to a value", "$ne: ${}"],
|
||||
["$gt", "Matches values greater than a value", "$gt: ${}"],
|
||||
@@ -47,18 +51,11 @@ export const QUERY_OPERATORS: MongoOperatorSpec[] = specs([
|
||||
["$lte", "Matches values less than or equal to a value", "$lte: ${}"],
|
||||
["$in", "Matches any value in an array", "$in: [${}]"],
|
||||
["$nin", "Matches no value in an array", "$nin: [${}]"],
|
||||
["$and", "Joins clauses with a logical AND", "$and: [${}]"],
|
||||
["$or", "Joins clauses with a logical OR", "$or: [${}]"],
|
||||
["$nor", "Joins clauses with a logical NOR", "$nor: [${}]"],
|
||||
["$not", "Inverts the effect of a query expression", "$not: { ${} }"],
|
||||
["$exists", "Matches documents that have the field", "$exists: true"],
|
||||
["$type", "Matches documents by BSON type", '$type: "${string}"'],
|
||||
["$regex", "Matches a regular expression", '$regex: "${pattern}"'],
|
||||
["$text", "Performs a text search", '$text: { $search: "${text}" }'],
|
||||
["$expr", "Uses aggregation expressions in a query", "$expr: { ${} }"],
|
||||
["$jsonSchema", "Matches documents against a JSON schema", "$jsonSchema: { ${} }"],
|
||||
["$mod", "Matches values by modulo division", "$mod: [${divisor}, ${remainder}]"],
|
||||
["$where", "Matches with a JavaScript predicate", '$where: "${expression}"'],
|
||||
["$all", "Matches arrays containing all the values", "$all: [${}]"],
|
||||
["$elemMatch", "Matches arrays with an element matching all criteria", "$elemMatch: { ${} }"],
|
||||
["$size", "Matches arrays of a given length", "$size: ${}"],
|
||||
@@ -72,6 +69,23 @@ export const QUERY_OPERATORS: MongoOperatorSpec[] = specs([
|
||||
["$nearSphere", "Matches points near a point on a sphere", "$nearSphere: { ${} }"],
|
||||
]);
|
||||
|
||||
/**
|
||||
* Operators that apply to the whole filter, valid at its top level and inside
|
||||
* the sub-filters of `$and` / `$or` / `$nor` — never under a field.
|
||||
*/
|
||||
export const TOP_LEVEL_QUERY_OPERATORS: MongoOperatorSpec[] = specs([
|
||||
["$and", "Joins clauses with a logical AND", "$and: [${}]"],
|
||||
["$or", "Joins clauses with a logical OR", "$or: [${}]"],
|
||||
["$nor", "Joins clauses with a logical NOR", "$nor: [${}]"],
|
||||
["$expr", "Uses aggregation expressions in a query", "$expr: { ${} }"],
|
||||
["$text", "Performs a text search", '$text: { $search: "${text}" }'],
|
||||
["$where", "Matches with a JavaScript predicate", '$where: "${expression}"'],
|
||||
["$jsonSchema", "Matches documents against a JSON schema", "$jsonSchema: { ${} }"],
|
||||
]);
|
||||
|
||||
/** Every query operator, for callers that do not care about position. */
|
||||
export const QUERY_OPERATORS: MongoOperatorSpec[] = [...FIELD_QUERY_OPERATORS, ...TOP_LEVEL_QUERY_OPERATORS];
|
||||
|
||||
export const UPDATE_OPERATORS: MongoOperatorSpec[] = specs([
|
||||
["$set", "Sets field values", "$set: { ${} }"],
|
||||
["$unset", "Removes fields", '$unset: { ${field}: "" }'],
|
||||
|
||||
Reference in new issue
Block a user