clintropolis commented on code in PR #18126:
URL: https://github.com/apache/druid/pull/18126#discussion_r2153912017


##########
web-console/src/views/load-data-view/ingestion-spec-completions.ts:
##########
@@ -0,0 +1,831 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import type { JsonCompletionRule } from '../../utils';
+
+/**
+ * Determines if a type is a supervisor type based on the documentation:
+ * "The supervisor type. For streaming ingestion, this can be either kafka, 
kinesis, or rabbit.
+ * For automatic compaction, set the type to autocompact."
+ */
+function isSupervisorType(type: string): boolean {
+  return type === 'kafka' || type === 'kinesis' || type === 'rabbit' || type 
=== 'autocompact';
+}
+
+export const INGESTION_SPEC_COMPLETIONS: JsonCompletionRule[] = [
+  // Root level properties (task and supervisor specs)
+  {
+    path: '$',
+    isObject: true,
+    completions: [
+      { value: 'type', documentation: 'Type of ingestion task or supervisor' },
+      { value: 'spec', documentation: 'Specification for the ingestion task or 
supervisor' },
+    ],
+  },
+  // Supervisor-only root level properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => isSupervisorType(obj.type),
+    completions: [
+      {
+        value: 'suspended',
+        documentation: 'Whether the supervisor is suspended (supervisor only)',
+      },
+    ],
+  },
+  // Type values for tasks
+  {
+    path: '$.type',
+    completions: [
+      { value: 'index_parallel', documentation: 'Native batch ingestion 
(parallel)' },
+      { value: 'index', documentation: 'Native batch ingestion (single task)' 
},
+      { value: 'index_hadoop', documentation: 'Hadoop-based batch ingestion' },
+      { value: 'kafka', documentation: 'Kafka supervisor for streaming 
ingestion' },
+      { value: 'kinesis', documentation: 'Kinesis supervisor for streaming 
ingestion' },
+      { value: 'rabbit', documentation: 'RabbitMQ supervisor for streaming 
ingestion' },
+      { value: 'autocompact', documentation: 'Auto-compaction supervisor' },
+    ],
+  },
+  // suspended values (supervisor only)
+  {
+    path: '$.suspended',
+    completions: [
+      { value: 'false', documentation: 'Supervisor is running (default)' },
+      { value: 'true', documentation: 'Supervisor is suspended' },
+    ],
+  },
+  // spec object properties
+  {
+    path: '$.spec',
+    isObject: true,
+    completions: [
+      { value: 'dataSchema', documentation: 'Schema configuration for 
ingestion' },
+      { value: 'ioConfig', documentation: 'Input/output configuration' },
+      { value: 'tuningConfig', documentation: 'Performance and tuning 
configuration' },
+    ],
+  },
+  // dataSchema object properties
+  {
+    path: '$.spec.dataSchema',
+    isObject: true,
+    completions: [
+      { value: 'dataSource', documentation: 'Name of the datasource to ingest 
into' },
+      { value: 'timestampSpec', documentation: 'Primary timestamp 
configuration' },
+      { value: 'dimensionsSpec', documentation: 'Dimensions configuration' },
+      { value: 'metricsSpec', documentation: 'Metrics and aggregators 
configuration' },
+      { value: 'granularitySpec', documentation: 'Granularity and rollup 
configuration' },
+      { value: 'transformSpec', documentation: 'Transform and filter 
configuration' },
+    ],
+  },
+  // timestampSpec object properties
+  {
+    path: '$.spec.dataSchema.timestampSpec',
+    isObject: true,
+    completions: [
+      { value: 'column', documentation: 'Input column containing the 
timestamp' },
+      { value: 'format', documentation: 'Format of the timestamp' },
+      { value: 'missingValue', documentation: 'Default timestamp for missing 
values' },
+    ],
+  },
+  // timestampSpec.format values
+  {
+    path: '$.spec.dataSchema.timestampSpec.format',
+    completions: [
+      { value: 'auto', documentation: 'Automatically detect ISO or millis 
format (default)' },
+      { value: 'iso', documentation: 'ISO8601 format with T separator' },
+      { value: 'posix', documentation: 'Seconds since epoch' },
+      { value: 'millis', documentation: 'Milliseconds since epoch' },
+      { value: 'micro', documentation: 'Microseconds since epoch' },
+      { value: 'nano', documentation: 'Nanoseconds since epoch' },
+      { value: 'yyyy-MM-dd HH:mm:ss', documentation: 'Custom Joda format' },
+      { value: 'yyyy-MM-dd', documentation: 'Date only format' },
+    ],
+  },
+  // timestampSpec.column common values
+  {
+    path: '$.spec.dataSchema.timestampSpec.column',
+    completions: [
+      { value: 'timestamp', documentation: 'Default timestamp column name' },
+      { value: '__time', documentation: 'Druid internal timestamp column' },
+      { value: 'time', documentation: 'Common timestamp column name' },
+      { value: 'event_time', documentation: 'Common event time column name' },
+      { value: 'created_at', documentation: 'Common creation time column name' 
},
+    ],
+  },
+  // dimensionsSpec object properties
+  {
+    path: '$.spec.dataSchema.dimensionsSpec',
+    isObject: true,
+    completions: [
+      { value: 'dimensions', documentation: 'List of dimension specifications' 
},
+      { value: 'dimensionExclusions', documentation: 'Dimensions to exclude 
from ingestion' },
+      { value: 'spatialDimensions', documentation: 'Spatial dimension 
specifications' },
+      { value: 'includeAllDimensions', documentation: 'Include all discovered 
dimensions' },
+      { value: 'useSchemaDiscovery', documentation: 'Enable automatic schema 
discovery' },
+      {
+        value: 'forceSegmentSortByTime',
+        documentation: 'Force segments to be sorted by time first',
+      },
+    ],
+  },
+  // useSchemaDiscovery values
+  {
+    path: '$.spec.dataSchema.dimensionsSpec.useSchemaDiscovery',
+    completions: [
+      { value: 'true', documentation: 'Enable automatic type detection and 
schema discovery' },
+      { value: 'false', documentation: 'Use manual dimension specification 
(default)' },
+    ],
+  },
+  // includeAllDimensions values
+  {
+    path: '$.spec.dataSchema.dimensionsSpec.includeAllDimensions',
+    completions: [
+      { value: 'true', documentation: 'Include both explicit and discovered 
dimensions' },
+      { value: 'false', documentation: 'Include only explicit dimensions 
(default)' },
+    ],
+  },
+  // forceSegmentSortByTime values
+  {
+    path: '$.spec.dataSchema.dimensionsSpec.forceSegmentSortByTime',
+    completions: [
+      { value: 'true', documentation: 'Sort by __time first, then dimensions 
(default)' },
+      { value: 'false', documentation: 'Sort by dimensions only 
(experimental)' },
+    ],
+  },
+  // dimension object properties
+  {
+    path: '$.spec.dataSchema.dimensionsSpec.dimensions.[]',
+    isObject: true,
+    completions: [
+      { value: 'type', documentation: 'Type of the dimension' },
+      { value: 'name', documentation: 'Name of the dimension' },
+      { value: 'createBitmapIndex', documentation: 'Whether to create bitmap 
index (string only)' },
+      {
+        value: 'multiValueHandling',
+        documentation: 'How to handle multi-value fields (string only)',
+      },
+    ],
+  },
+  // dimension type values
+  {
+    path: '$.spec.dataSchema.dimensionsSpec.dimensions.[].type',
+    completions: [
+      { value: 'auto', documentation: 'Automatically detect type (schema 
discovery)' },
+      { value: 'string', documentation: 'String dimension (default)' },
+      { value: 'long', documentation: 'Long integer dimension' },
+      { value: 'float', documentation: 'Float dimension' },
+      { value: 'double', documentation: 'Double precision dimension' },
+      { value: 'json', documentation: 'JSON/nested data dimension' },
+    ],
+  },
+  // createBitmapIndex values
+  {
+    path: '$.spec.dataSchema.dimensionsSpec.dimensions.[].createBitmapIndex',
+    completions: [
+      { value: 'true', documentation: 'Create bitmap index (default, faster 
filtering)' },
+      { value: 'false', documentation: 'No bitmap index (saves storage)' },
+    ],
+  },
+  // multiValueHandling values
+  {
+    path: '$.spec.dataSchema.dimensionsSpec.dimensions.[].multiValueHandling',
+    completions: [
+      { value: 'sorted_array', documentation: 'Sort multi-values (default)' },
+      { value: 'sorted_set', documentation: 'Sort and deduplicate 
multi-values' },
+      { value: 'array', documentation: 'Keep multi-values as-is' },
+    ],
+  },
+  // metricsSpec array properties
+  {
+    path: '$.spec.dataSchema.metricsSpec.[]',
+    isObject: true,
+    completions: [
+      { value: 'type', documentation: 'Type of aggregator' },
+      { value: 'name', documentation: 'Name of the metric' },
+      { value: 'fieldName', documentation: 'Input field to aggregate' },
+    ],
+  },
+  // metric aggregator types
+  {
+    path: '$.spec.dataSchema.metricsSpec.[].type',
+    completions: [
+      { value: 'count', documentation: 'Count of rows' },
+      { value: 'longSum', documentation: 'Sum of long values' },
+      { value: 'doubleSum', documentation: 'Sum of double values' },
+      { value: 'longMin', documentation: 'Minimum of long values' },
+      { value: 'longMax', documentation: 'Maximum of long values' },
+      { value: 'doubleMin', documentation: 'Minimum of double values' },
+      { value: 'doubleMax', documentation: 'Maximum of double values' },
+      { value: 'longFirst', documentation: 'First long value seen' },
+      { value: 'longLast', documentation: 'Last long value seen' },
+      { value: 'doubleFirst', documentation: 'First double value seen' },
+      { value: 'doubleLast', documentation: 'Last double value seen' },
+      { value: 'thetaSketch', documentation: 'Theta sketch for approximate 
counting' },
+      { value: 'HLLSketchBuild', documentation: 'HyperLogLog sketch for 
cardinality' },
+      { value: 'quantilesDoublesSketch', documentation: 'Quantiles sketch for 
percentiles' },
+    ],
+  },
+  // granularitySpec object properties
+  {
+    path: '$.spec.dataSchema.granularitySpec',
+    isObject: true,
+    completions: [
+      { value: 'type', documentation: 'Type of granularity specification' },
+      { value: 'segmentGranularity', documentation: 'Granularity for segment 
partitioning' },
+      { value: 'queryGranularity', documentation: 'Granularity for timestamp 
truncation' },
+      { value: 'rollup', documentation: 'Whether to enable rollup 
(aggregation)' },
+      { value: 'intervals', documentation: 'Time intervals to process (batch 
only)' },
+    ],
+  },
+  // granularitySpec.type values
+  {
+    path: '$.spec.dataSchema.granularitySpec.type',
+    completions: [
+      { value: 'uniform', documentation: 'Uniform granularity (default)' },
+      { value: 'arbitrary', documentation: 'Arbitrary granularity (advanced)' 
},
+    ],
+  },
+  // segmentGranularity values
+  {
+    path: '$.spec.dataSchema.granularitySpec.segmentGranularity',
+    completions: [
+      { value: 'SECOND', documentation: 'Second-level segments' },
+      { value: 'MINUTE', documentation: 'Minute-level segments' },
+      { value: 'HOUR', documentation: 'Hourly segments' },
+      { value: 'DAY', documentation: 'Daily segments (common choice)' },
+      { value: 'WEEK', documentation: 'Weekly segments (not recommended)' },
+      { value: 'MONTH', documentation: 'Monthly segments' },
+      { value: 'QUARTER', documentation: 'Quarterly segments' },
+      { value: 'YEAR', documentation: 'Yearly segments' },
+      { value: 'ALL', documentation: 'Single segment for all data' },
+    ],
+  },
+  // queryGranularity values
+  {
+    path: '$.spec.dataSchema.granularitySpec.queryGranularity',
+    completions: [
+      { value: 'NONE', documentation: 'No truncation (millisecond precision)' 
},
+      { value: 'SECOND', documentation: 'Second-level truncation' },
+      { value: 'MINUTE', documentation: 'Minute-level truncation' },
+      { value: 'HOUR', documentation: 'Hour-level truncation' },
+      { value: 'DAY', documentation: 'Day-level truncation' },
+      { value: 'WEEK', documentation: 'Week-level truncation' },
+      { value: 'MONTH', documentation: 'Month-level truncation' },
+      { value: 'QUARTER', documentation: 'Quarter-level truncation' },
+      { value: 'YEAR', documentation: 'Year-level truncation' },
+    ],
+  },
+  // rollup values
+  {
+    path: '$.spec.dataSchema.granularitySpec.rollup',
+    completions: [
+      { value: 'true', documentation: 'Enable rollup (aggregate identical 
rows)' },
+      { value: 'false', documentation: 'Disable rollup (store raw data)' },
+    ],
+  },
+  // transformSpec object properties
+  {
+    path: '$.spec.dataSchema.transformSpec',
+    isObject: true,
+    completions: [
+      { value: 'transforms', documentation: 'List of transform expressions' },
+      { value: 'filter', documentation: 'Filter to apply during ingestion' },
+    ],
+  },
+  // transform object properties
+  {
+    path: '$.spec.dataSchema.transformSpec.transforms.[]',
+    isObject: true,
+    completions: [
+      { value: 'type', documentation: 'Type of transform' },
+      { value: 'name', documentation: 'Name of the output field' },
+      { value: 'expression', documentation: 'Transform expression' },
+    ],
+  },
+  // transform type values
+  {
+    path: '$.spec.dataSchema.transformSpec.transforms.[].type',
+    completions: [{ value: 'expression', documentation: 'Expression-based 
transform' }],
+  },
+  // filter object properties
+  {
+    path: '$.spec.dataSchema.transformSpec.filter',
+    isObject: true,
+    completions: [
+      { value: 'type', documentation: 'Type of filter' },
+      { value: 'dimension', documentation: 'Dimension to filter on' },
+      { value: 'value', documentation: 'Value to filter for' },
+      { value: 'values', documentation: 'List of values to filter for' },
+      { value: 'fields', documentation: 'List of sub-filters (logical 
filters)' },
+    ],
+  },
+  // filter type values
+  {
+    path: '$.spec.dataSchema.transformSpec.filter.type',
+    completions: [
+      { value: 'selector', documentation: 'Exact match filter' },
+      { value: 'in', documentation: 'Match any of multiple values' },
+      { value: 'like', documentation: 'Pattern matching filter' },
+      { value: 'regex', documentation: 'Regular expression filter' },
+      { value: 'range', documentation: 'Numeric range filter' },
+      { value: 'and', documentation: 'Logical AND filter' },
+      { value: 'or', documentation: 'Logical OR filter' },
+      { value: 'not', documentation: 'Logical NOT filter' },
+    ],
+  },
+  // ioConfig object properties (general)
+  {
+    path: '$.spec.ioConfig',
+    isObject: true,
+    completions: [
+      { value: 'type', documentation: 'Type of I/O configuration' },
+      { value: 'inputSource', documentation: 'Data input source configuration' 
},
+      { value: 'inputFormat', documentation: 'Input data format configuration' 
},
+    ],
+  },
+  // ioConfig type values
+  {
+    path: '$.spec.ioConfig.type',
+    completions: [
+      { value: 'index_parallel', documentation: 'Parallel batch ingestion' },
+      { value: 'index', documentation: 'Single task batch ingestion' },
+      { value: 'hadoop', documentation: 'Hadoop-based ingestion' },
+      { value: 'kafka', documentation: 'Kafka streaming ingestion' },
+      { value: 'kinesis', documentation: 'Kinesis streaming ingestion' },
+      { value: 'rabbit', documentation: 'RabbitMQ streaming ingestion' },
+    ],
+  },
+  // Batch ioConfig properties
+  {
+    path: '$.spec.ioConfig',
+    isObject: true,
+    condition: obj => obj.type === 'index_parallel' || obj.type === 'index',
+    completions: [
+      { value: 'firehose', documentation: 'Legacy data input (deprecated)' },

Review Comment:
   this is gone, not just deprecated



##########
web-console/src/views/load-data-view/ingestion-spec-completions.ts:
##########
@@ -0,0 +1,831 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import type { JsonCompletionRule } from '../../utils';
+
+/**
+ * Determines if a type is a supervisor type based on the documentation:
+ * "The supervisor type. For streaming ingestion, this can be either kafka, 
kinesis, or rabbit.
+ * For automatic compaction, set the type to autocompact."
+ */
+function isSupervisorType(type: string): boolean {
+  return type === 'kafka' || type === 'kinesis' || type === 'rabbit' || type 
=== 'autocompact';
+}
+
+export const INGESTION_SPEC_COMPLETIONS: JsonCompletionRule[] = [
+  // Root level properties (task and supervisor specs)
+  {
+    path: '$',
+    isObject: true,
+    completions: [
+      { value: 'type', documentation: 'Type of ingestion task or supervisor' },
+      { value: 'spec', documentation: 'Specification for the ingestion task or 
supervisor' },
+    ],
+  },
+  // Supervisor-only root level properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => isSupervisorType(obj.type),
+    completions: [
+      {
+        value: 'suspended',
+        documentation: 'Whether the supervisor is suspended (supervisor only)',
+      },
+    ],
+  },
+  // Type values for tasks
+  {
+    path: '$.type',
+    completions: [
+      { value: 'index_parallel', documentation: 'Native batch ingestion 
(parallel)' },
+      { value: 'index', documentation: 'Native batch ingestion (single task)' 
},
+      { value: 'index_hadoop', documentation: 'Hadoop-based batch ingestion' },
+      { value: 'kafka', documentation: 'Kafka supervisor for streaming 
ingestion' },
+      { value: 'kinesis', documentation: 'Kinesis supervisor for streaming 
ingestion' },
+      { value: 'rabbit', documentation: 'RabbitMQ supervisor for streaming 
ingestion' },
+      { value: 'autocompact', documentation: 'Auto-compaction supervisor' },
+    ],
+  },
+  // suspended values (supervisor only)
+  {
+    path: '$.suspended',
+    completions: [
+      { value: 'false', documentation: 'Supervisor is running (default)' },
+      { value: 'true', documentation: 'Supervisor is suspended' },
+    ],
+  },
+  // spec object properties
+  {
+    path: '$.spec',
+    isObject: true,
+    completions: [
+      { value: 'dataSchema', documentation: 'Schema configuration for 
ingestion' },
+      { value: 'ioConfig', documentation: 'Input/output configuration' },
+      { value: 'tuningConfig', documentation: 'Performance and tuning 
configuration' },
+    ],
+  },
+  // dataSchema object properties
+  {
+    path: '$.spec.dataSchema',
+    isObject: true,
+    completions: [
+      { value: 'dataSource', documentation: 'Name of the datasource to ingest 
into' },
+      { value: 'timestampSpec', documentation: 'Primary timestamp 
configuration' },
+      { value: 'dimensionsSpec', documentation: 'Dimensions configuration' },
+      { value: 'metricsSpec', documentation: 'Metrics and aggregators 
configuration' },
+      { value: 'granularitySpec', documentation: 'Granularity and rollup 
configuration' },
+      { value: 'transformSpec', documentation: 'Transform and filter 
configuration' },
+    ],
+  },
+  // timestampSpec object properties
+  {
+    path: '$.spec.dataSchema.timestampSpec',
+    isObject: true,
+    completions: [
+      { value: 'column', documentation: 'Input column containing the 
timestamp' },
+      { value: 'format', documentation: 'Format of the timestamp' },
+      { value: 'missingValue', documentation: 'Default timestamp for missing 
values' },
+    ],
+  },
+  // timestampSpec.format values
+  {
+    path: '$.spec.dataSchema.timestampSpec.format',
+    completions: [
+      { value: 'auto', documentation: 'Automatically detect ISO or millis 
format (default)' },
+      { value: 'iso', documentation: 'ISO8601 format with T separator' },
+      { value: 'posix', documentation: 'Seconds since epoch' },
+      { value: 'millis', documentation: 'Milliseconds since epoch' },
+      { value: 'micro', documentation: 'Microseconds since epoch' },
+      { value: 'nano', documentation: 'Nanoseconds since epoch' },
+      { value: 'yyyy-MM-dd HH:mm:ss', documentation: 'Custom Joda format' },
+      { value: 'yyyy-MM-dd', documentation: 'Date only format' },
+    ],
+  },
+  // timestampSpec.column common values
+  {
+    path: '$.spec.dataSchema.timestampSpec.column',
+    completions: [
+      { value: 'timestamp', documentation: 'Default timestamp column name' },
+      { value: '__time', documentation: 'Druid internal timestamp column' },
+      { value: 'time', documentation: 'Common timestamp column name' },
+      { value: 'event_time', documentation: 'Common event time column name' },
+      { value: 'created_at', documentation: 'Common creation time column name' 
},
+    ],
+  },
+  // dimensionsSpec object properties
+  {
+    path: '$.spec.dataSchema.dimensionsSpec',
+    isObject: true,
+    completions: [
+      { value: 'dimensions', documentation: 'List of dimension specifications' 
},
+      { value: 'dimensionExclusions', documentation: 'Dimensions to exclude 
from ingestion' },
+      { value: 'spatialDimensions', documentation: 'Spatial dimension 
specifications' },
+      { value: 'includeAllDimensions', documentation: 'Include all discovered 
dimensions' },
+      { value: 'useSchemaDiscovery', documentation: 'Enable automatic schema 
discovery' },
+      {
+        value: 'forceSegmentSortByTime',
+        documentation: 'Force segments to be sorted by time first',
+      },
+    ],
+  },
+  // useSchemaDiscovery values
+  {
+    path: '$.spec.dataSchema.dimensionsSpec.useSchemaDiscovery',
+    completions: [
+      { value: 'true', documentation: 'Enable automatic type detection and 
schema discovery' },
+      { value: 'false', documentation: 'Use manual dimension specification 
(default)' },
+    ],
+  },
+  // includeAllDimensions values
+  {
+    path: '$.spec.dataSchema.dimensionsSpec.includeAllDimensions',
+    completions: [
+      { value: 'true', documentation: 'Include both explicit and discovered 
dimensions' },
+      { value: 'false', documentation: 'Include only explicit dimensions 
(default)' },
+    ],
+  },
+  // forceSegmentSortByTime values
+  {
+    path: '$.spec.dataSchema.dimensionsSpec.forceSegmentSortByTime',
+    completions: [
+      { value: 'true', documentation: 'Sort by __time first, then dimensions 
(default)' },
+      { value: 'false', documentation: 'Sort by dimensions only 
(experimental)' },
+    ],
+  },
+  // dimension object properties
+  {
+    path: '$.spec.dataSchema.dimensionsSpec.dimensions.[]',
+    isObject: true,
+    completions: [
+      { value: 'type', documentation: 'Type of the dimension' },
+      { value: 'name', documentation: 'Name of the dimension' },
+      { value: 'createBitmapIndex', documentation: 'Whether to create bitmap 
index (string only)' },
+      {
+        value: 'multiValueHandling',
+        documentation: 'How to handle multi-value fields (string only)',
+      },
+    ],
+  },
+  // dimension type values
+  {
+    path: '$.spec.dataSchema.dimensionsSpec.dimensions.[].type',
+    completions: [
+      { value: 'auto', documentation: 'Automatically detect type (schema 
discovery)' },
+      { value: 'string', documentation: 'String dimension (default)' },
+      { value: 'long', documentation: 'Long integer dimension' },
+      { value: 'float', documentation: 'Float dimension' },
+      { value: 'double', documentation: 'Double precision dimension' },
+      { value: 'json', documentation: 'JSON/nested data dimension' },
+    ],
+  },
+  // createBitmapIndex values
+  {
+    path: '$.spec.dataSchema.dimensionsSpec.dimensions.[].createBitmapIndex',
+    completions: [
+      { value: 'true', documentation: 'Create bitmap index (default, faster 
filtering)' },
+      { value: 'false', documentation: 'No bitmap index (saves storage)' },
+    ],
+  },
+  // multiValueHandling values
+  {
+    path: '$.spec.dataSchema.dimensionsSpec.dimensions.[].multiValueHandling',
+    completions: [
+      { value: 'sorted_array', documentation: 'Sort multi-values (default)' },
+      { value: 'sorted_set', documentation: 'Sort and deduplicate 
multi-values' },
+      { value: 'array', documentation: 'Keep multi-values as-is' },
+    ],
+  },
+  // metricsSpec array properties
+  {
+    path: '$.spec.dataSchema.metricsSpec.[]',
+    isObject: true,
+    completions: [
+      { value: 'type', documentation: 'Type of aggregator' },
+      { value: 'name', documentation: 'Name of the metric' },
+      { value: 'fieldName', documentation: 'Input field to aggregate' },
+    ],
+  },
+  // metric aggregator types
+  {
+    path: '$.spec.dataSchema.metricsSpec.[].type',
+    completions: [
+      { value: 'count', documentation: 'Count of rows' },
+      { value: 'longSum', documentation: 'Sum of long values' },
+      { value: 'doubleSum', documentation: 'Sum of double values' },
+      { value: 'longMin', documentation: 'Minimum of long values' },
+      { value: 'longMax', documentation: 'Maximum of long values' },
+      { value: 'doubleMin', documentation: 'Minimum of double values' },
+      { value: 'doubleMax', documentation: 'Maximum of double values' },
+      { value: 'longFirst', documentation: 'First long value seen' },
+      { value: 'longLast', documentation: 'Last long value seen' },
+      { value: 'doubleFirst', documentation: 'First double value seen' },
+      { value: 'doubleLast', documentation: 'Last double value seen' },
+      { value: 'thetaSketch', documentation: 'Theta sketch for approximate 
counting' },
+      { value: 'HLLSketchBuild', documentation: 'HyperLogLog sketch for 
cardinality' },
+      { value: 'quantilesDoublesSketch', documentation: 'Quantiles sketch for 
percentiles' },
+    ],
+  },
+  // granularitySpec object properties
+  {
+    path: '$.spec.dataSchema.granularitySpec',
+    isObject: true,
+    completions: [
+      { value: 'type', documentation: 'Type of granularity specification' },
+      { value: 'segmentGranularity', documentation: 'Granularity for segment 
partitioning' },
+      { value: 'queryGranularity', documentation: 'Granularity for timestamp 
truncation' },
+      { value: 'rollup', documentation: 'Whether to enable rollup 
(aggregation)' },
+      { value: 'intervals', documentation: 'Time intervals to process (batch 
only)' },
+    ],
+  },
+  // granularitySpec.type values
+  {
+    path: '$.spec.dataSchema.granularitySpec.type',
+    completions: [
+      { value: 'uniform', documentation: 'Uniform granularity (default)' },
+      { value: 'arbitrary', documentation: 'Arbitrary granularity (advanced)' 
},
+    ],
+  },
+  // segmentGranularity values
+  {
+    path: '$.spec.dataSchema.granularitySpec.segmentGranularity',
+    completions: [
+      { value: 'SECOND', documentation: 'Second-level segments' },
+      { value: 'MINUTE', documentation: 'Minute-level segments' },
+      { value: 'HOUR', documentation: 'Hourly segments' },
+      { value: 'DAY', documentation: 'Daily segments (common choice)' },
+      { value: 'WEEK', documentation: 'Weekly segments (not recommended)' },
+      { value: 'MONTH', documentation: 'Monthly segments' },
+      { value: 'QUARTER', documentation: 'Quarterly segments' },
+      { value: 'YEAR', documentation: 'Yearly segments' },
+      { value: 'ALL', documentation: 'Single segment for all data' },
+    ],
+  },
+  // queryGranularity values
+  {
+    path: '$.spec.dataSchema.granularitySpec.queryGranularity',
+    completions: [
+      { value: 'NONE', documentation: 'No truncation (millisecond precision)' 
},
+      { value: 'SECOND', documentation: 'Second-level truncation' },
+      { value: 'MINUTE', documentation: 'Minute-level truncation' },
+      { value: 'HOUR', documentation: 'Hour-level truncation' },
+      { value: 'DAY', documentation: 'Day-level truncation' },
+      { value: 'WEEK', documentation: 'Week-level truncation' },
+      { value: 'MONTH', documentation: 'Month-level truncation' },
+      { value: 'QUARTER', documentation: 'Quarter-level truncation' },
+      { value: 'YEAR', documentation: 'Year-level truncation' },
+    ],
+  },
+  // rollup values
+  {
+    path: '$.spec.dataSchema.granularitySpec.rollup',
+    completions: [
+      { value: 'true', documentation: 'Enable rollup (aggregate identical 
rows)' },
+      { value: 'false', documentation: 'Disable rollup (store raw data)' },
+    ],
+  },
+  // transformSpec object properties
+  {
+    path: '$.spec.dataSchema.transformSpec',
+    isObject: true,
+    completions: [
+      { value: 'transforms', documentation: 'List of transform expressions' },
+      { value: 'filter', documentation: 'Filter to apply during ingestion' },
+    ],
+  },
+  // transform object properties
+  {
+    path: '$.spec.dataSchema.transformSpec.transforms.[]',
+    isObject: true,
+    completions: [
+      { value: 'type', documentation: 'Type of transform' },
+      { value: 'name', documentation: 'Name of the output field' },
+      { value: 'expression', documentation: 'Transform expression' },
+    ],
+  },
+  // transform type values
+  {
+    path: '$.spec.dataSchema.transformSpec.transforms.[].type',
+    completions: [{ value: 'expression', documentation: 'Expression-based 
transform' }],
+  },
+  // filter object properties
+  {
+    path: '$.spec.dataSchema.transformSpec.filter',
+    isObject: true,
+    completions: [
+      { value: 'type', documentation: 'Type of filter' },
+      { value: 'dimension', documentation: 'Dimension to filter on' },
+      { value: 'value', documentation: 'Value to filter for' },
+      { value: 'values', documentation: 'List of values to filter for' },
+      { value: 'fields', documentation: 'List of sub-filters (logical 
filters)' },
+    ],
+  },
+  // filter type values
+  {
+    path: '$.spec.dataSchema.transformSpec.filter.type',
+    completions: [
+      { value: 'selector', documentation: 'Exact match filter' },
+      { value: 'in', documentation: 'Match any of multiple values' },
+      { value: 'like', documentation: 'Pattern matching filter' },
+      { value: 'regex', documentation: 'Regular expression filter' },
+      { value: 'range', documentation: 'Numeric range filter' },
+      { value: 'and', documentation: 'Logical AND filter' },
+      { value: 'or', documentation: 'Logical OR filter' },
+      { value: 'not', documentation: 'Logical NOT filter' },
+    ],
+  },
+  // ioConfig object properties (general)
+  {
+    path: '$.spec.ioConfig',
+    isObject: true,
+    completions: [
+      { value: 'type', documentation: 'Type of I/O configuration' },
+      { value: 'inputSource', documentation: 'Data input source configuration' 
},
+      { value: 'inputFormat', documentation: 'Input data format configuration' 
},
+    ],
+  },
+  // ioConfig type values
+  {
+    path: '$.spec.ioConfig.type',
+    completions: [
+      { value: 'index_parallel', documentation: 'Parallel batch ingestion' },
+      { value: 'index', documentation: 'Single task batch ingestion' },
+      { value: 'hadoop', documentation: 'Hadoop-based ingestion' },
+      { value: 'kafka', documentation: 'Kafka streaming ingestion' },
+      { value: 'kinesis', documentation: 'Kinesis streaming ingestion' },
+      { value: 'rabbit', documentation: 'RabbitMQ streaming ingestion' },
+    ],
+  },
+  // Batch ioConfig properties
+  {
+    path: '$.spec.ioConfig',
+    isObject: true,
+    condition: obj => obj.type === 'index_parallel' || obj.type === 'index',
+    completions: [
+      { value: 'firehose', documentation: 'Legacy data input (deprecated)' },
+      { value: 'appendToExisting', documentation: 'Whether to append to 
existing segments' },
+      { value: 'dropExisting', documentation: 'Whether to drop existing 
segments' },
+    ],
+  },
+  // Streaming ioConfig properties (Kafka/Kinesis/Rabbit)
+  {
+    path: '$.spec.ioConfig',
+    isObject: true,
+    condition: obj => isSupervisorType(obj.type) && obj.type !== 'autocompact',
+    completions: [
+      { value: 'taskCount', documentation: 'Number of reading tasks per 
replica' },
+      { value: 'replicas', documentation: 'Number of replica task sets' },
+      { value: 'taskDuration', documentation: 'Duration before tasks stop 
reading' },
+      { value: 'startDelay', documentation: 'Delay before supervisor starts 
managing tasks' },
+      { value: 'period', documentation: 'How often supervisor executes 
management logic' },
+      { value: 'completionTimeout', documentation: 'Timeout for task 
completion' },
+      { value: 'autoScalerConfig', documentation: 'Auto-scaling configuration' 
},
+    ],
+  },
+  // Kafka-specific ioConfig properties
+  {
+    path: '$.spec.ioConfig',
+    isObject: true,
+    condition: obj => obj.type === 'kafka',
+    completions: [
+      { value: 'topic', documentation: 'Kafka topic to consume from' },
+      { value: 'consumerProperties', documentation: 'Kafka consumer 
properties' },
+      {
+        value: 'useEarliestOffset',
+        documentation: 'Start from earliest offset when no stored offset',
+      },
+    ],
+  },
+  // Kinesis-specific ioConfig properties
+  {
+    path: '$.spec.ioConfig',
+    isObject: true,
+    condition: obj => obj.type === 'kinesis',
+    completions: [
+      { value: 'stream', documentation: 'Kinesis stream to consume from' },
+      { value: 'endpoint', documentation: 'Kinesis endpoint URL' },
+      {
+        value: 'useEarliestSequenceNumber',
+        documentation: 'Start from earliest when no stored sequence number',
+      },
+    ],
+  },
+  // appendToExisting values
+  {
+    path: '$.spec.ioConfig.appendToExisting',
+    completions: [
+      { value: 'false', documentation: 'Overwrite existing data (default)' },
+      { value: 'true', documentation: 'Append to existing data' },
+    ],
+  },
+  // dropExisting values
+  {
+    path: '$.spec.ioConfig.dropExisting',
+    completions: [
+      { value: 'false', documentation: 'Keep existing segments (default)' },
+      { value: 'true', documentation: 'Drop existing segments in intervals' },
+    ],
+  },
+  // useEarliestOffset values
+  {
+    path: '$.spec.ioConfig.useEarliestOffset',
+    completions: [
+      { value: 'false', documentation: 'Use latest offset when no stored 
offset (default)' },
+      { value: 'true', documentation: 'Use earliest offset when no stored 
offset' },
+    ],
+  },
+  // useEarliestSequenceNumber values
+  {
+    path: '$.spec.ioConfig.useEarliestSequenceNumber',
+    completions: [
+      { value: 'false', documentation: 'Use latest sequence number (default)' 
},
+      { value: 'true', documentation: 'Use earliest sequence number' },
+    ],
+  },
+  // inputSource object properties
+  {
+    path: '$.spec.ioConfig.inputSource',
+    isObject: true,
+    completions: [{ value: 'type', documentation: 'Type of input source' }],
+  },
+  // inputSource type values
+  {
+    path: '$.spec.ioConfig.inputSource.type',
+    completions: [
+      { value: 'local', documentation: 'Local file system' },
+      { value: 'http', documentation: 'HTTP/HTTPS URLs' },
+      { value: 's3', documentation: 'Amazon S3' },
+      { value: 'gs', documentation: 'Google Cloud Storage' },
+      { value: 'azure', documentation: 'Azure Blob Storage' },
+      { value: 'hdfs', documentation: 'Hadoop Distributed File System' },
+      { value: 'druid', documentation: 'Re-index from existing Druid 
datasource' },
+      { value: 'inline', documentation: 'Inline data in the spec' },
+      { value: 'combining', documentation: 'Combine multiple input sources' },
+    ],
+  },
+  // Local input source properties
+  {
+    path: '$.spec.ioConfig.inputSource',
+    isObject: true,
+    condition: obj => obj.type === 'local',
+    completions: [
+      { value: 'baseDir', documentation: 'Base directory path' },
+      { value: 'filter', documentation: 'File filter pattern' },
+      { value: 'files', documentation: 'List of specific file paths' },
+    ],
+  },
+  // HTTP input source properties
+  {
+    path: '$.spec.ioConfig.inputSource',
+    isObject: true,
+    condition: obj => obj.type === 'http',
+    completions: [
+      { value: 'uris', documentation: 'List of HTTP/HTTPS URIs' },
+      { value: 'httpAuthenticationUsername', documentation: 'HTTP 
authentication username' },
+      { value: 'httpAuthenticationPassword', documentation: 'HTTP 
authentication password' },

Review Comment:
   there are a couple missing ones here, `systemFields` and `requestHeaders` 
though the latter isn't documented either



##########
web-console/src/views/load-data-view/ingestion-spec-completions.ts:
##########
@@ -0,0 +1,831 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import type { JsonCompletionRule } from '../../utils';
+
+/**
+ * Determines if a type is a supervisor type based on the documentation:
+ * "The supervisor type. For streaming ingestion, this can be either kafka, 
kinesis, or rabbit.
+ * For automatic compaction, set the type to autocompact."
+ */
+function isSupervisorType(type: string): boolean {
+  return type === 'kafka' || type === 'kinesis' || type === 'rabbit' || type 
=== 'autocompact';

Review Comment:
   missing the scheduled batch supervisor, #17353



##########
web-console/src/druid-models/native-json-query/native-json-query-completions.ts:
##########
@@ -0,0 +1,1098 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import type { JsonCompletionRule } from '../../utils';
+
+export const NATIVE_JSON_QUERY_COMPLETIONS: JsonCompletionRule[] = [
+  // Root level - when starting a new query
+  {
+    path: '$',
+    isObject: true,
+    completions: [
+      { value: 'queryType', documentation: 'The type of query to execute' },
+      { value: 'dataSource', documentation: 'The data source to query' },
+    ],
+  },
+
+  // Query type values
+  {
+    path: '$.queryType',
+    completions: [
+      {
+        value: 'timeseries',
+        documentation: 'Timeseries query for time-based aggregations',
+      },
+      {
+        value: 'topN',
+        documentation: 'TopN query to get the top N dimension values',
+      },
+      { value: 'groupBy', documentation: 'GroupBy query for grouped 
aggregations' },
+      { value: 'scan', documentation: 'Scan query to return raw Druid rows' },
+      { value: 'search', documentation: 'Search query to find dimension 
values' },
+      {
+        value: 'timeBoundary',
+        documentation: 'Time boundary query to find data time range',
+      },
+      { value: 'segmentMetadata', documentation: 'Segment metadata query' },
+      { value: 'dataSourceMetadata', documentation: 'Data source metadata 
query' },
+    ],
+  },
+
+  // Common properties for most query types
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType !== 'dataSourceMetadata',
+    completions: [
+      { value: 'intervals', documentation: 'Time intervals to query' },
+      { value: 'filter', documentation: 'Filter to apply to the query' },
+      { value: 'context', documentation: 'Query context parameters' },
+      { value: 'virtualColumns', documentation: 'Virtual columns for computed 
values' },
+    ],
+  },
+
+  // Timeseries query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'timeseries',
+    completions: [
+      { value: 'granularity', documentation: 'Time granularity for bucketing' 
},
+      { value: 'aggregations', documentation: 'Aggregations to compute' },
+      {
+        value: 'postAggregations',
+        documentation: 'Post-aggregations to compute',
+      },
+      {
+        value: 'descending',
+        documentation: 'Whether to sort results in descending order',
+      },
+      { value: 'limit', documentation: 'Maximum number of results to return' },
+    ],
+  },
+
+  // TopN query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'topN',
+    completions: [
+      {
+        value: 'dimension',
+        documentation: 'The dimension to get top values for',
+      },
+      { value: 'threshold', documentation: 'The number of top values to 
return' },
+      { value: 'metric', documentation: 'The metric to sort by' },
+      { value: 'granularity', documentation: 'Time granularity for bucketing' 
},
+      { value: 'aggregations', documentation: 'Aggregations to compute' },
+      {
+        value: 'postAggregations',
+        documentation: 'Post-aggregations to compute',
+      },
+    ],
+  },
+
+  // GroupBy query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'groupBy',
+    completions: [
+      { value: 'dimensions', documentation: 'Dimensions to group by' },
+      { value: 'granularity', documentation: 'Time granularity for bucketing' 
},
+      { value: 'aggregations', documentation: 'Aggregations to compute' },
+      {
+        value: 'postAggregations',
+        documentation: 'Post-aggregations to compute',
+      },
+      { value: 'having', documentation: 'Having clause to filter groups' },
+      { value: 'limitSpec', documentation: 'Limit and ordering specification' 
},
+    ],
+  },
+
+  // Scan query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'scan',
+    completions: [
+      { value: 'columns', documentation: 'Columns to return' },
+      { value: 'limit', documentation: 'Maximum number of rows to return' },
+      { value: 'offset', documentation: 'Number of rows to skip' },
+      { value: 'resultFormat', documentation: 'Format of the result' },
+      { value: 'batchSize', documentation: 'Batch size for streaming' },
+      { value: 'legacy', documentation: 'Use legacy scan query mode' },
+      { value: 'order', documentation: 'Result ordering (none, ascending, 
descending)' },
+    ],
+  },
+
+  // Search query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'search',
+    completions: [
+      { value: 'granularity', documentation: 'Time granularity for bucketing' 
},
+      { value: 'searchDimensions', documentation: 'Dimensions to search' },
+      { value: 'query', documentation: 'Search query specification' },
+      { value: 'sort', documentation: 'Sort specification for results' },
+      { value: 'limit', documentation: 'Maximum number of results to return' },
+    ],
+  },
+
+  // TimeBoundary query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'timeBoundary',
+    completions: [
+      {
+        value: 'bound',
+        documentation: 'Which boundary to return (minTime, maxTime, or null 
for both)',
+      },
+    ],
+  },
+
+  // SegmentMetadata query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'segmentMetadata',
+    completions: [
+      { value: 'toInclude', documentation: 'Columns to include in the result 
(defaults to "all")' },
+      {
+        value: 'merge',
+        documentation: 'Merge all individual segment metadata results into a 
single result',
+      },
+      {
+        value: 'analysisTypes',
+        documentation: 'Column properties to calculate and return (e.g. 
cardinality, size)',
+      },
+      {
+        value: 'aggregatorMergeStrategy',
+        documentation: 'Strategy for merging aggregators: strict, lenient, 
earliest, or latest',
+      },
+      {
+        value: 'lenientAggregatorMerge',
+        documentation: 'Deprecated. Use aggregatorMergeStrategy instead',
+      },
+    ],
+  },
+
+  // SegmentMetadata toInclude properties
+  {
+    path: '$.toInclude',
+    isObject: true,
+    condition: obj => obj.queryType === 'segmentMetadata',
+    completions: [
+      { value: 'type', documentation: 'Type of columns to include: all, none, 
or list' },
+    ],
+  },
+
+  // SegmentMetadata toInclude types
+  {
+    path: '$.toInclude.type',
+    condition: obj => obj.queryType === 'segmentMetadata',
+    completions: [
+      { value: 'all', documentation: 'Include all columns in the result' },
+      { value: 'none', documentation: 'Include no columns in the result' },
+      { value: 'list', documentation: 'Include specific columns listed in the 
columns array' },
+    ],
+  },
+
+  // SegmentMetadata toInclude list properties
+  {
+    path: '$.toInclude',
+    isObject: true,
+    condition: obj => obj.queryType === 'segmentMetadata' && 
obj.toInclude?.type === 'list',
+    completions: [{ value: 'columns', documentation: 'Array of column names to 
include' }],
+  },
+
+  // SegmentMetadata analysisTypes values
+  {
+    path: '$.analysisTypes.[]',
+    condition: obj => obj.queryType === 'segmentMetadata',
+    completions: [
+      { value: 'cardinality', documentation: 'Number of unique values in 
string columns' },
+      { value: 'interval', documentation: 'Time intervals associated with 
queried segments' },
+      { value: 'minmax', documentation: 'Estimated min/max values for string 
columns' },
+      { value: 'size', documentation: 'Estimated byte size as if stored in 
text format' },
+      { value: 'timestampSpec', documentation: 'Timestamp specification of 
data in segments' },
+      { value: 'queryGranularity', documentation: 'Query granularity of data 
in segments' },
+      { value: 'aggregators', documentation: 'List of aggregators usable for 
metric columns' },
+      { value: 'rollup', documentation: 'Whether the segments are rolled up' },
+    ],
+  },
+
+  // SegmentMetadata aggregatorMergeStrategy values
+  {
+    path: '$.aggregatorMergeStrategy',
+    condition: obj => obj.queryType === 'segmentMetadata',
+    completions: [
+      { value: 'strict', documentation: 'Fail if any conflicts or unknown 
aggregators exist' },
+      { value: 'lenient', documentation: 'Ignore unknown aggregators, set 
conflicts to null' },
+      { value: 'earliest', documentation: 'Use aggregator from earliest 
segment in conflicts' },
+      { value: 'latest', documentation: 'Use aggregator from most recent 
segment in conflicts' },
+    ],
+  },
+
+  // DataSourceMetadata query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'dataSourceMetadata',
+    completions: [
+      { value: 'dataSource', documentation: 'The data source to get metadata 
for' },
+      { value: 'context', documentation: 'Query context parameters' },
+    ],
+  },
+
+  // Granularity simple values
+  {
+    path: '$.granularity',
+    completions: [
+      { value: 'all', documentation: 'All data in a single bucket' },
+      { value: 'none', documentation: 'No time bucketing' },
+      { value: 'second', documentation: 'Bucket by second' },
+      { value: 'minute', documentation: 'Bucket by minute' },
+      { value: 'fifteen_minute', documentation: 'Bucket by 15 minutes' },
+      { value: 'thirty_minute', documentation: 'Bucket by 30 minutes' },
+      { value: 'hour', documentation: 'Bucket by hour' },
+      { value: 'day', documentation: 'Bucket by day' },
+      { value: 'week', documentation: 'Bucket by week' },
+      { value: 'month', documentation: 'Bucket by month' },
+      { value: 'quarter', documentation: 'Bucket by quarter' },
+      { value: 'year', documentation: 'Bucket by year' },
+    ],
+  },
+
+  // Granularity object properties (when granularity is an object)
+  {
+    path: '$.granularity',
+    isObject: true,
+    condition: obj => typeof obj === 'object' && obj !== null,
+    completions: [
+      { value: 'type', documentation: 'Type of granularity' },
+      { value: 'period', documentation: 'ISO 8601 period' },
+      { value: 'timeZone', documentation: 'Timezone for bucketing' },
+      { value: 'origin', documentation: 'Origin timestamp' },
+    ],
+  },
+
+  // Granularity types
+  {
+    path: '$.granularity.type',
+    completions: [
+      { value: 'duration', documentation: 'Duration-based granularity' },
+      { value: 'period', documentation: 'Period-based granularity' },
+      { value: 'uniform', documentation: 'Uniform granularity' },
+    ],
+  },
+
+  // Duration granularity properties
+  {
+    path: '$.granularity',
+    isObject: true,
+    condition: obj => obj.type === 'duration',
+    completions: [
+      { value: 'duration', documentation: 'Duration in milliseconds' },
+      { value: 'origin', documentation: 'Origin timestamp' },
+    ],
+  },
+
+  // Period granularity properties
+  {
+    path: '$.granularity',
+    isObject: true,
+    condition: obj => obj.type === 'period',
+    completions: [
+      { value: 'period', documentation: 'ISO 8601 period string' },
+      { value: 'timeZone', documentation: 'Timezone for bucketing' },
+      { value: 'origin', documentation: 'Origin timestamp' },
+    ],
+  },
+
+  // Aggregation properties
+  {
+    path: '$.aggregations.[]',
+    isObject: true,
+    completions: [
+      { value: 'type', documentation: 'Type of aggregation' },
+      { value: 'name', documentation: 'Output name for this aggregation' },
+    ],
+  },
+
+  // Aggregation types
+  {
+    path: '$.aggregations.[].type',
+    completions: [
+      { value: 'count', documentation: 'Count aggregator' },
+      { value: 'longSum', documentation: 'Sum aggregator for long values' },
+      { value: 'doubleSum', documentation: 'Sum aggregator for double values' 
},
+      { value: 'floatSum', documentation: 'Sum aggregator for float values' },
+      { value: 'longMin', documentation: 'Min aggregator for long values' },
+      { value: 'doubleMin', documentation: 'Min aggregator for double values' 
},
+      { value: 'floatMin', documentation: 'Min aggregator for float values' },
+      { value: 'longMax', documentation: 'Max aggregator for long values' },
+      { value: 'doubleMax', documentation: 'Max aggregator for double values' 
},
+      { value: 'floatMax', documentation: 'Max aggregator for float values' },
+      { value: 'doubleMean', documentation: 'Mean aggregator for double values 
(query time only)' },
+      { value: 'doubleFirst', documentation: 'First value aggregator for 
doubles' },
+      { value: 'doubleLast', documentation: 'Last value aggregator for 
doubles' },
+      { value: 'floatFirst', documentation: 'First value aggregator for 
floats' },
+      { value: 'floatLast', documentation: 'Last value aggregator for floats' 
},
+      { value: 'longFirst', documentation: 'First value aggregator for longs' 
},
+      { value: 'longLast', documentation: 'Last value aggregator for longs' },
+      { value: 'stringFirst', documentation: 'First value aggregator for 
strings' },
+      { value: 'stringLast', documentation: 'Last value aggregator for 
strings' },
+      { value: 'doubleAny', documentation: 'Any value aggregator for doubles' 
},
+      { value: 'floatAny', documentation: 'Any value aggregator for floats' },
+      { value: 'longAny', documentation: 'Any value aggregator for longs' },
+      { value: 'stringAny', documentation: 'Any value aggregator for strings' 
},
+      {
+        value: 'thetaSketch',
+        documentation: 'Theta sketch for approximate distinct count',
+      },
+      {
+        value: 'HLLSketchBuild',
+        documentation: 'HLL sketch for approximate distinct count',
+      },
+      {
+        value: 'quantilesDoublesSketch',
+        documentation: 'Quantiles sketch for doubles',
+      },
+      {
+        value: 'hyperUnique',
+        documentation: 'HyperLogLog for approximate distinct count',
+      },
+      { value: 'cardinality', documentation: 'Cardinality aggregator' },
+      { value: 'histogram', documentation: 'Approximate histogram aggregator' 
},
+      {
+        value: 'fixedBucketsHistogram',
+        documentation: 'Fixed buckets histogram aggregator',
+      },
+      { value: 'filtered', documentation: 'Filtered aggregator' },
+      { value: 'grouping', documentation: 'Grouping aggregator for subtotals' 
},
+    ],
+  },
+
+  // Aggregation properties for field-based aggregators
+  {
+    path: '$.aggregations.[]',
+    isObject: true,
+    condition: obj =>
+      obj.type &&
+      [
+        'longSum',
+        'doubleSum',
+        'floatSum',
+        'longMin',
+        'doubleMin',
+        'floatMin',
+        'longMax',
+        'doubleMax',
+        'floatMax',
+        'doubleMean',
+      ].includes(obj.type),
+    completions: [
+      { value: 'fieldName', documentation: 'The field to aggregate' },
+      { value: 'expression', documentation: 'Expression to evaluate instead of 
fieldName' },
+    ],
+  },
+
+  // Aggregation properties for first/last aggregators
+  {
+    path: '$.aggregations.[]',
+    isObject: true,
+    condition: obj =>
+      obj.type &&
+      [
+        'doubleFirst',
+        'doubleLast',
+        'floatFirst',
+        'floatLast',
+        'longFirst',
+        'longLast',
+        'stringFirst',
+        'stringLast',
+        'doubleAny',
+        'floatAny',
+        'longAny',
+        'stringAny',
+      ].includes(obj.type),
+    completions: [
+      { value: 'fieldName', documentation: 'The field to aggregate' },
+      {
+        value: 'timeColumn',
+        documentation: 'Time column to use for ordering (defaults to __time)',
+      },
+    ],
+  },
+
+  // Filtered aggregator properties
+  {
+    path: '$.aggregations.[]',
+    isObject: true,
+    condition: obj => obj.type === 'filtered',
+    completions: [
+      { value: 'filter', documentation: 'Filter to apply before aggregation' },
+      { value: 'aggregator', documentation: 'The aggregator to apply to 
filtered data' },
+    ],
+  },
+
+  // Filter types
+  {
+    path: '$.filter',
+    isObject: true,
+    completions: [{ value: 'type', documentation: 'Type of filter' }],
+  },
+
+  {
+    path: '$.filter.type',
+    completions: [
+      { value: 'selector', documentation: 'Matches a specific dimension value' 
},

Review Comment:
   this is missing the [range 
filter](https://druid.apache.org/docs/latest/querying/filters/#range-filter) 
and typed in filter (which i just realized isn't documented yet, from #16039)



##########
web-console/src/druid-models/native-json-query/native-json-query-completions.ts:
##########
@@ -0,0 +1,1098 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import type { JsonCompletionRule } from '../../utils';
+
+export const NATIVE_JSON_QUERY_COMPLETIONS: JsonCompletionRule[] = [
+  // Root level - when starting a new query
+  {
+    path: '$',
+    isObject: true,
+    completions: [
+      { value: 'queryType', documentation: 'The type of query to execute' },
+      { value: 'dataSource', documentation: 'The data source to query' },
+    ],
+  },
+
+  // Query type values
+  {
+    path: '$.queryType',
+    completions: [
+      {
+        value: 'timeseries',
+        documentation: 'Timeseries query for time-based aggregations',
+      },
+      {
+        value: 'topN',
+        documentation: 'TopN query to get the top N dimension values',
+      },
+      { value: 'groupBy', documentation: 'GroupBy query for grouped 
aggregations' },
+      { value: 'scan', documentation: 'Scan query to return raw Druid rows' },
+      { value: 'search', documentation: 'Search query to find dimension 
values' },
+      {
+        value: 'timeBoundary',
+        documentation: 'Time boundary query to find data time range',
+      },
+      { value: 'segmentMetadata', documentation: 'Segment metadata query' },
+      { value: 'dataSourceMetadata', documentation: 'Data source metadata 
query' },
+    ],
+  },
+
+  // Common properties for most query types
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType !== 'dataSourceMetadata',

Review Comment:
   afaik, everything has a context and intervals, even `dataSourceMetadata`



##########
web-console/src/druid-models/native-json-query/native-json-query-completions.ts:
##########
@@ -0,0 +1,1098 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import type { JsonCompletionRule } from '../../utils';
+
+export const NATIVE_JSON_QUERY_COMPLETIONS: JsonCompletionRule[] = [
+  // Root level - when starting a new query
+  {
+    path: '$',
+    isObject: true,
+    completions: [
+      { value: 'queryType', documentation: 'The type of query to execute' },
+      { value: 'dataSource', documentation: 'The data source to query' },
+    ],
+  },
+
+  // Query type values
+  {
+    path: '$.queryType',
+    completions: [
+      {
+        value: 'timeseries',
+        documentation: 'Timeseries query for time-based aggregations',
+      },
+      {
+        value: 'topN',
+        documentation: 'TopN query to get the top N dimension values',
+      },
+      { value: 'groupBy', documentation: 'GroupBy query for grouped 
aggregations' },
+      { value: 'scan', documentation: 'Scan query to return raw Druid rows' },
+      { value: 'search', documentation: 'Search query to find dimension 
values' },
+      {
+        value: 'timeBoundary',
+        documentation: 'Time boundary query to find data time range',
+      },
+      { value: 'segmentMetadata', documentation: 'Segment metadata query' },
+      { value: 'dataSourceMetadata', documentation: 'Data source metadata 
query' },
+    ],
+  },
+
+  // Common properties for most query types
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType !== 'dataSourceMetadata',
+    completions: [
+      { value: 'intervals', documentation: 'Time intervals to query' },
+      { value: 'filter', documentation: 'Filter to apply to the query' },
+      { value: 'context', documentation: 'Query context parameters' },
+      { value: 'virtualColumns', documentation: 'Virtual columns for computed 
values' },
+    ],
+  },
+
+  // Timeseries query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'timeseries',
+    completions: [
+      { value: 'granularity', documentation: 'Time granularity for bucketing' 
},
+      { value: 'aggregations', documentation: 'Aggregations to compute' },
+      {
+        value: 'postAggregations',
+        documentation: 'Post-aggregations to compute',
+      },
+      {
+        value: 'descending',
+        documentation: 'Whether to sort results in descending order',
+      },
+      { value: 'limit', documentation: 'Maximum number of results to return' },
+    ],
+  },
+
+  // TopN query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'topN',
+    completions: [
+      {
+        value: 'dimension',
+        documentation: 'The dimension to get top values for',
+      },
+      { value: 'threshold', documentation: 'The number of top values to 
return' },
+      { value: 'metric', documentation: 'The metric to sort by' },
+      { value: 'granularity', documentation: 'Time granularity for bucketing' 
},
+      { value: 'aggregations', documentation: 'Aggregations to compute' },
+      {
+        value: 'postAggregations',
+        documentation: 'Post-aggregations to compute',
+      },
+    ],
+  },
+
+  // GroupBy query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'groupBy',
+    completions: [
+      { value: 'dimensions', documentation: 'Dimensions to group by' },
+      { value: 'granularity', documentation: 'Time granularity for bucketing' 
},
+      { value: 'aggregations', documentation: 'Aggregations to compute' },
+      {
+        value: 'postAggregations',
+        documentation: 'Post-aggregations to compute',
+      },
+      { value: 'having', documentation: 'Having clause to filter groups' },
+      { value: 'limitSpec', documentation: 'Limit and ordering specification' 
},
+    ],
+  },
+
+  // Scan query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'scan',
+    completions: [
+      { value: 'columns', documentation: 'Columns to return' },
+      { value: 'limit', documentation: 'Maximum number of rows to return' },
+      { value: 'offset', documentation: 'Number of rows to skip' },
+      { value: 'resultFormat', documentation: 'Format of the result' },
+      { value: 'batchSize', documentation: 'Batch size for streaming' },
+      { value: 'legacy', documentation: 'Use legacy scan query mode' },
+      { value: 'order', documentation: 'Result ordering (none, ascending, 
descending)' },
+    ],
+  },
+
+  // Search query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'search',
+    completions: [
+      { value: 'granularity', documentation: 'Time granularity for bucketing' 
},
+      { value: 'searchDimensions', documentation: 'Dimensions to search' },
+      { value: 'query', documentation: 'Search query specification' },
+      { value: 'sort', documentation: 'Sort specification for results' },
+      { value: 'limit', documentation: 'Maximum number of results to return' },
+    ],
+  },
+
+  // TimeBoundary query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'timeBoundary',
+    completions: [
+      {
+        value: 'bound',
+        documentation: 'Which boundary to return (minTime, maxTime, or null 
for both)',
+      },
+    ],
+  },
+
+  // SegmentMetadata query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'segmentMetadata',
+    completions: [
+      { value: 'toInclude', documentation: 'Columns to include in the result 
(defaults to "all")' },
+      {
+        value: 'merge',
+        documentation: 'Merge all individual segment metadata results into a 
single result',
+      },
+      {
+        value: 'analysisTypes',
+        documentation: 'Column properties to calculate and return (e.g. 
cardinality, size)',
+      },
+      {
+        value: 'aggregatorMergeStrategy',
+        documentation: 'Strategy for merging aggregators: strict, lenient, 
earliest, or latest',
+      },
+      {
+        value: 'lenientAggregatorMerge',
+        documentation: 'Deprecated. Use aggregatorMergeStrategy instead',
+      },
+    ],
+  },
+
+  // SegmentMetadata toInclude properties
+  {
+    path: '$.toInclude',
+    isObject: true,
+    condition: obj => obj.queryType === 'segmentMetadata',
+    completions: [
+      { value: 'type', documentation: 'Type of columns to include: all, none, 
or list' },
+    ],
+  },
+
+  // SegmentMetadata toInclude types
+  {
+    path: '$.toInclude.type',
+    condition: obj => obj.queryType === 'segmentMetadata',
+    completions: [
+      { value: 'all', documentation: 'Include all columns in the result' },
+      { value: 'none', documentation: 'Include no columns in the result' },
+      { value: 'list', documentation: 'Include specific columns listed in the 
columns array' },
+    ],
+  },
+
+  // SegmentMetadata toInclude list properties
+  {
+    path: '$.toInclude',
+    isObject: true,
+    condition: obj => obj.queryType === 'segmentMetadata' && 
obj.toInclude?.type === 'list',
+    completions: [{ value: 'columns', documentation: 'Array of column names to 
include' }],
+  },
+
+  // SegmentMetadata analysisTypes values
+  {
+    path: '$.analysisTypes.[]',
+    condition: obj => obj.queryType === 'segmentMetadata',
+    completions: [
+      { value: 'cardinality', documentation: 'Number of unique values in 
string columns' },
+      { value: 'interval', documentation: 'Time intervals associated with 
queried segments' },
+      { value: 'minmax', documentation: 'Estimated min/max values for string 
columns' },
+      { value: 'size', documentation: 'Estimated byte size as if stored in 
text format' },
+      { value: 'timestampSpec', documentation: 'Timestamp specification of 
data in segments' },
+      { value: 'queryGranularity', documentation: 'Query granularity of data 
in segments' },
+      { value: 'aggregators', documentation: 'List of aggregators usable for 
metric columns' },
+      { value: 'rollup', documentation: 'Whether the segments are rolled up' },
+    ],
+  },
+
+  // SegmentMetadata aggregatorMergeStrategy values
+  {
+    path: '$.aggregatorMergeStrategy',
+    condition: obj => obj.queryType === 'segmentMetadata',
+    completions: [
+      { value: 'strict', documentation: 'Fail if any conflicts or unknown 
aggregators exist' },
+      { value: 'lenient', documentation: 'Ignore unknown aggregators, set 
conflicts to null' },
+      { value: 'earliest', documentation: 'Use aggregator from earliest 
segment in conflicts' },
+      { value: 'latest', documentation: 'Use aggregator from most recent 
segment in conflicts' },
+    ],
+  },
+
+  // DataSourceMetadata query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'dataSourceMetadata',
+    completions: [
+      { value: 'dataSource', documentation: 'The data source to get metadata 
for' },
+      { value: 'context', documentation: 'Query context parameters' },
+    ],
+  },
+
+  // Granularity simple values
+  {
+    path: '$.granularity',
+    completions: [
+      { value: 'all', documentation: 'All data in a single bucket' },
+      { value: 'none', documentation: 'No time bucketing' },
+      { value: 'second', documentation: 'Bucket by second' },
+      { value: 'minute', documentation: 'Bucket by minute' },
+      { value: 'fifteen_minute', documentation: 'Bucket by 15 minutes' },
+      { value: 'thirty_minute', documentation: 'Bucket by 30 minutes' },
+      { value: 'hour', documentation: 'Bucket by hour' },
+      { value: 'day', documentation: 'Bucket by day' },
+      { value: 'week', documentation: 'Bucket by week' },
+      { value: 'month', documentation: 'Bucket by month' },
+      { value: 'quarter', documentation: 'Bucket by quarter' },
+      { value: 'year', documentation: 'Bucket by year' },
+    ],
+  },
+
+  // Granularity object properties (when granularity is an object)
+  {
+    path: '$.granularity',
+    isObject: true,
+    condition: obj => typeof obj === 'object' && obj !== null,
+    completions: [
+      { value: 'type', documentation: 'Type of granularity' },
+      { value: 'period', documentation: 'ISO 8601 period' },
+      { value: 'timeZone', documentation: 'Timezone for bucketing' },
+      { value: 'origin', documentation: 'Origin timestamp' },
+    ],
+  },
+
+  // Granularity types
+  {
+    path: '$.granularity.type',
+    completions: [
+      { value: 'duration', documentation: 'Duration-based granularity' },
+      { value: 'period', documentation: 'Period-based granularity' },
+      { value: 'uniform', documentation: 'Uniform granularity' },
+    ],
+  },
+
+  // Duration granularity properties
+  {
+    path: '$.granularity',
+    isObject: true,
+    condition: obj => obj.type === 'duration',
+    completions: [
+      { value: 'duration', documentation: 'Duration in milliseconds' },
+      { value: 'origin', documentation: 'Origin timestamp' },
+    ],
+  },
+
+  // Period granularity properties
+  {
+    path: '$.granularity',
+    isObject: true,
+    condition: obj => obj.type === 'period',
+    completions: [
+      { value: 'period', documentation: 'ISO 8601 period string' },
+      { value: 'timeZone', documentation: 'Timezone for bucketing' },
+      { value: 'origin', documentation: 'Origin timestamp' },
+    ],
+  },
+
+  // Aggregation properties
+  {
+    path: '$.aggregations.[]',
+    isObject: true,
+    completions: [
+      { value: 'type', documentation: 'Type of aggregation' },
+      { value: 'name', documentation: 'Output name for this aggregation' },
+    ],
+  },
+
+  // Aggregation types
+  {
+    path: '$.aggregations.[].type',
+    completions: [
+      { value: 'count', documentation: 'Count aggregator' },
+      { value: 'longSum', documentation: 'Sum aggregator for long values' },
+      { value: 'doubleSum', documentation: 'Sum aggregator for double values' 
},
+      { value: 'floatSum', documentation: 'Sum aggregator for float values' },
+      { value: 'longMin', documentation: 'Min aggregator for long values' },
+      { value: 'doubleMin', documentation: 'Min aggregator for double values' 
},
+      { value: 'floatMin', documentation: 'Min aggregator for float values' },
+      { value: 'longMax', documentation: 'Max aggregator for long values' },
+      { value: 'doubleMax', documentation: 'Max aggregator for double values' 
},
+      { value: 'floatMax', documentation: 'Max aggregator for float values' },
+      { value: 'doubleMean', documentation: 'Mean aggregator for double values 
(query time only)' },
+      { value: 'doubleFirst', documentation: 'First value aggregator for 
doubles' },
+      { value: 'doubleLast', documentation: 'Last value aggregator for 
doubles' },
+      { value: 'floatFirst', documentation: 'First value aggregator for 
floats' },
+      { value: 'floatLast', documentation: 'Last value aggregator for floats' 
},
+      { value: 'longFirst', documentation: 'First value aggregator for longs' 
},
+      { value: 'longLast', documentation: 'Last value aggregator for longs' },
+      { value: 'stringFirst', documentation: 'First value aggregator for 
strings' },
+      { value: 'stringLast', documentation: 'Last value aggregator for 
strings' },
+      { value: 'doubleAny', documentation: 'Any value aggregator for doubles' 
},
+      { value: 'floatAny', documentation: 'Any value aggregator for floats' },
+      { value: 'longAny', documentation: 'Any value aggregator for longs' },
+      { value: 'stringAny', documentation: 'Any value aggregator for strings' 
},
+      {
+        value: 'thetaSketch',
+        documentation: 'Theta sketch for approximate distinct count',
+      },
+      {
+        value: 'HLLSketchBuild',
+        documentation: 'HLL sketch for approximate distinct count',
+      },
+      {
+        value: 'quantilesDoublesSketch',
+        documentation: 'Quantiles sketch for doubles',
+      },
+      {
+        value: 'hyperUnique',
+        documentation: 'HyperLogLog for approximate distinct count',
+      },
+      { value: 'cardinality', documentation: 'Cardinality aggregator' },
+      { value: 'histogram', documentation: 'Approximate histogram aggregator' 
},
+      {
+        value: 'fixedBucketsHistogram',
+        documentation: 'Fixed buckets histogram aggregator',
+      },
+      { value: 'filtered', documentation: 'Filtered aggregator' },
+      { value: 'grouping', documentation: 'Grouping aggregator for subtotals' 
},
+    ],
+  },
+
+  // Aggregation properties for field-based aggregators
+  {
+    path: '$.aggregations.[]',
+    isObject: true,
+    condition: obj =>
+      obj.type &&
+      [
+        'longSum',
+        'doubleSum',
+        'floatSum',
+        'longMin',
+        'doubleMin',
+        'floatMin',
+        'longMax',
+        'doubleMax',
+        'floatMax',
+        'doubleMean',
+      ].includes(obj.type),
+    completions: [
+      { value: 'fieldName', documentation: 'The field to aggregate' },
+      { value: 'expression', documentation: 'Expression to evaluate instead of 
fieldName' },
+    ],
+  },
+
+  // Aggregation properties for first/last aggregators
+  {
+    path: '$.aggregations.[]',
+    isObject: true,
+    condition: obj =>
+      obj.type &&
+      [
+        'doubleFirst',
+        'doubleLast',
+        'floatFirst',
+        'floatLast',
+        'longFirst',
+        'longLast',
+        'stringFirst',
+        'stringLast',
+        'doubleAny',
+        'floatAny',
+        'longAny',
+        'stringAny',
+      ].includes(obj.type),
+    completions: [
+      { value: 'fieldName', documentation: 'The field to aggregate' },
+      {
+        value: 'timeColumn',
+        documentation: 'Time column to use for ordering (defaults to __time)',
+      },
+    ],
+  },
+
+  // Filtered aggregator properties
+  {
+    path: '$.aggregations.[]',
+    isObject: true,
+    condition: obj => obj.type === 'filtered',
+    completions: [
+      { value: 'filter', documentation: 'Filter to apply before aggregation' },
+      { value: 'aggregator', documentation: 'The aggregator to apply to 
filtered data' },
+    ],
+  },
+
+  // Filter types
+  {
+    path: '$.filter',
+    isObject: true,
+    completions: [{ value: 'type', documentation: 'Type of filter' }],
+  },
+
+  {
+    path: '$.filter.type',
+    completions: [
+      { value: 'selector', documentation: 'Matches a specific dimension value' 
},
+      { value: 'equals', documentation: 'Equality filter with type checking' },
+      { value: 'null', documentation: 'Matches null or missing values' },
+      { value: 'in', documentation: 'Matches any of the given dimension 
values' },
+      { value: 'bound', documentation: 'Matches dimension values within 
bounds' },
+      { value: 'interval', documentation: 'Matches time intervals' },
+      {
+        value: 'like',
+        documentation: 'Matches dimension values using LIKE pattern',
+      },
+      { value: 'regex', documentation: 'Matches dimension values using regex' 
},
+      { value: 'search', documentation: 'Matches dimension values using 
search' },
+      { value: 'columnComparison', documentation: 'Compares two columns' },
+      { value: 'expression', documentation: 'Expression-based filter' },
+      { value: 'javascript', documentation: 'JavaScript function filter' },
+      { value: 'spatial', documentation: 'Spatial rectangle filter' },
+      { value: 'and', documentation: 'AND filter combinator' },
+      { value: 'or', documentation: 'OR filter combinator' },
+      { value: 'not', documentation: 'NOT filter combinator' },
+      { value: 'true', documentation: 'Always matches' },
+      { value: 'false', documentation: 'Never matches' },
+    ],
+  },
+
+  // Selector filter properties
+  {
+    path: '$.filter',
+    isObject: true,
+    condition: obj => obj.type === 'selector',
+    completions: [
+      { value: 'dimension', documentation: 'The dimension to filter on' },
+      { value: 'value', documentation: 'The value to match' },
+      { value: 'extractionFn', documentation: 'Extraction function to apply' },
+    ],
+  },
+
+  // Equals filter properties
+  {
+    path: '$.filter',
+    isObject: true,
+    condition: obj => obj.type === 'equals',
+    completions: [
+      { value: 'column', documentation: 'The column to filter on' },
+      { value: 'matchValue', documentation: 'The value to match' },
+      { value: 'matchValueType', documentation: 'Type of the match value' },
+    ],
+  },
+
+  // Null filter properties
+  {
+    path: '$.filter',
+    isObject: true,
+    condition: obj => obj.type === 'null',
+    completions: [{ value: 'column', documentation: 'The column to check for 
null values' }],
+  },
+
+  // In filter properties
+  {
+    path: '$.filter',
+    isObject: true,
+    condition: obj => obj.type === 'in',
+    completions: [
+      { value: 'dimension', documentation: 'The dimension to filter on' },
+      { value: 'values', documentation: 'The values to match' },
+      { value: 'extractionFn', documentation: 'Extraction function to apply' },
+    ],
+  },
+
+  // Bound filter properties
+  {
+    path: '$.filter',
+    isObject: true,
+    condition: obj => obj.type === 'bound',
+    completions: [
+      { value: 'dimension', documentation: 'The dimension to filter on' },
+      { value: 'lower', documentation: 'Lower bound value' },
+      { value: 'upper', documentation: 'Upper bound value' },
+      { value: 'lowerStrict', documentation: 'Whether lower bound is strict' },
+      { value: 'upperStrict', documentation: 'Whether upper bound is strict' },
+      { value: 'ordering', documentation: 'Ordering to use for comparison' },
+      { value: 'extractionFn', documentation: 'Extraction function to apply' },
+    ],
+  },
+
+  // Like filter properties
+  {
+    path: '$.filter',
+    isObject: true,
+    condition: obj => obj.type === 'like',
+    completions: [
+      { value: 'dimension', documentation: 'The dimension to filter on' },
+      { value: 'pattern', documentation: 'LIKE pattern to match' },
+      { value: 'escape', documentation: 'Escape character for pattern' },
+      { value: 'extractionFn', documentation: 'Extraction function to apply' },
+    ],
+  },
+
+  // Regex filter properties
+  {
+    path: '$.filter',
+    isObject: true,
+    condition: obj => obj.type === 'regex',
+    completions: [
+      { value: 'dimension', documentation: 'The dimension to filter on' },
+      { value: 'pattern', documentation: 'Regular expression pattern' },
+      { value: 'extractionFn', documentation: 'Extraction function to apply' },
+    ],
+  },
+
+  // Search filter properties
+  {
+    path: '$.filter',
+    isObject: true,
+    condition: obj => obj.type === 'search',
+    completions: [
+      { value: 'dimension', documentation: 'The dimension to filter on' },
+      { value: 'query', documentation: 'Search query specification' },
+      { value: 'extractionFn', documentation: 'Extraction function to apply' },
+    ],
+  },
+
+  // Column comparison filter properties
+  {
+    path: '$.filter',
+    isObject: true,
+    condition: obj => obj.type === 'columnComparison',
+    completions: [{ value: 'dimensions', documentation: 'Array of dimension 
specs to compare' }],
+  },
+
+  // Expression filter properties
+  {
+    path: '$.filter',
+    isObject: true,
+    condition: obj => obj.type === 'expression',
+    completions: [{ value: 'expression', documentation: 'Druid expression that 
returns boolean' }],
+  },
+
+  // JavaScript filter properties
+  {
+    path: '$.filter',
+    isObject: true,
+    condition: obj => obj.type === 'javascript',
+    completions: [
+      { value: 'dimension', documentation: 'The dimension to filter on' },
+      { value: 'function', documentation: 'JavaScript function for filtering' 
},
+      { value: 'extractionFn', documentation: 'Extraction function to apply' },
+    ],
+  },
+
+  // Interval filter properties
+  {
+    path: '$.filter',
+    isObject: true,
+    condition: obj => obj.type === 'interval',
+    completions: [
+      { value: 'dimension', documentation: 'The dimension to filter on 
(usually __time)' },
+      { value: 'intervals', documentation: 'Array of ISO-8601 intervals' },
+      { value: 'extractionFn', documentation: 'Extraction function to apply' },
+    ],
+  },
+
+  // AND/OR filter properties
+  {
+    path: '$.filter',
+    isObject: true,
+    condition: obj => obj.type === 'and' || obj.type === 'or',
+    completions: [{ value: 'fields', documentation: 'Array of filters to 
combine' }],
+  },
+
+  // NOT filter properties
+  {
+    path: '$.filter',
+    isObject: true,
+    condition: obj => obj.type === 'not',
+    completions: [{ value: 'field', documentation: 'Filter to negate' }],
+  },
+
+  // Nested filter fields for logical operators (AND/OR)
+  {
+    path: '$.filter.fields.[]',
+    isObject: true,
+    completions: [{ value: 'type', documentation: 'Type of this filter' }],
+  },
+
+  // Nested filter field for NOT operator
+  {
+    path: '$.filter.field',
+    isObject: true,
+    completions: [{ value: 'type', documentation: 'Type of this filter' }],
+  },
+
+  // Dimension spec properties (when dimension is an object)
+  {
+    path: '$.dimensions.[]',
+    isObject: true,
+    condition: obj => typeof obj === 'object' && obj !== null,
+    completions: [
+      { value: 'type', documentation: 'Type of dimension spec' },
+      { value: 'dimension', documentation: 'The dimension field' },
+      { value: 'outputName', documentation: 'Output name for this dimension' },
+    ],
+  },
+
+  // Dimension spec types
+  {
+    path: '$.dimensions.[].type',
+    completions: [
+      { value: 'default', documentation: 'Default dimension spec' },
+      {
+        value: 'extraction',
+        documentation: 'Dimension spec with extraction function',
+      },
+      {
+        value: 'listFiltered',
+        documentation: 'Dimension spec with value filtering',
+      },
+      { value: 'lookup', documentation: 'Dimension spec with lookup' },
+      {
+        value: 'prefixFiltered',
+        documentation: 'Dimension spec with prefix filtering',
+      },
+      {
+        value: 'regexFiltered',
+        documentation: 'Dimension spec with regex filtering',
+      },
+    ],
+  },
+
+  // Query context properties
+  {
+    path: '$.context',
+    isObject: true,
+    completions: [
+      { value: 'timeout', documentation: 'Query timeout in milliseconds' },
+      {
+        value: 'priority',
+        documentation: 'Query priority (higher = more important)',
+      },
+      { value: 'queryId', documentation: 'Unique identifier for this query' },
+      { value: 'useCache', documentation: 'Whether to use cached results' },
+      { value: 'populateCache', documentation: 'Whether to populate the cache' 
},
+      {
+        value: 'useResultLevelCache',
+        documentation: 'Whether to use result level cache',
+      },
+      {
+        value: 'populateResultLevelCache',
+        documentation: 'Whether to populate result level cache',
+      },
+      { value: 'bySegment', documentation: 'Return results by segment' },

Review Comment:
   does this still break the results if you actually set it?



##########
web-console/src/druid-models/native-json-query/native-json-query-completions.ts:
##########
@@ -0,0 +1,1098 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import type { JsonCompletionRule } from '../../utils';
+
+export const NATIVE_JSON_QUERY_COMPLETIONS: JsonCompletionRule[] = [
+  // Root level - when starting a new query
+  {
+    path: '$',
+    isObject: true,
+    completions: [
+      { value: 'queryType', documentation: 'The type of query to execute' },
+      { value: 'dataSource', documentation: 'The data source to query' },
+    ],
+  },
+
+  // Query type values
+  {
+    path: '$.queryType',
+    completions: [
+      {
+        value: 'timeseries',
+        documentation: 'Timeseries query for time-based aggregations',
+      },
+      {
+        value: 'topN',
+        documentation: 'TopN query to get the top N dimension values',
+      },
+      { value: 'groupBy', documentation: 'GroupBy query for grouped 
aggregations' },
+      { value: 'scan', documentation: 'Scan query to return raw Druid rows' },
+      { value: 'search', documentation: 'Search query to find dimension 
values' },
+      {
+        value: 'timeBoundary',
+        documentation: 'Time boundary query to find data time range',
+      },
+      { value: 'segmentMetadata', documentation: 'Segment metadata query' },
+      { value: 'dataSourceMetadata', documentation: 'Data source metadata 
query' },
+    ],
+  },
+
+  // Common properties for most query types
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType !== 'dataSourceMetadata',
+    completions: [
+      { value: 'intervals', documentation: 'Time intervals to query' },
+      { value: 'filter', documentation: 'Filter to apply to the query' },
+      { value: 'context', documentation: 'Query context parameters' },
+      { value: 'virtualColumns', documentation: 'Virtual columns for computed 
values' },
+    ],
+  },
+
+  // Timeseries query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'timeseries',
+    completions: [
+      { value: 'granularity', documentation: 'Time granularity for bucketing' 
},
+      { value: 'aggregations', documentation: 'Aggregations to compute' },
+      {
+        value: 'postAggregations',
+        documentation: 'Post-aggregations to compute',
+      },
+      {
+        value: 'descending',
+        documentation: 'Whether to sort results in descending order',
+      },
+      { value: 'limit', documentation: 'Maximum number of results to return' },
+    ],
+  },
+
+  // TopN query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'topN',
+    completions: [
+      {
+        value: 'dimension',
+        documentation: 'The dimension to get top values for',
+      },
+      { value: 'threshold', documentation: 'The number of top values to 
return' },
+      { value: 'metric', documentation: 'The metric to sort by' },
+      { value: 'granularity', documentation: 'Time granularity for bucketing' 
},
+      { value: 'aggregations', documentation: 'Aggregations to compute' },
+      {
+        value: 'postAggregations',
+        documentation: 'Post-aggregations to compute',
+      },
+    ],
+  },
+
+  // GroupBy query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'groupBy',
+    completions: [
+      { value: 'dimensions', documentation: 'Dimensions to group by' },
+      { value: 'granularity', documentation: 'Time granularity for bucketing' 
},
+      { value: 'aggregations', documentation: 'Aggregations to compute' },
+      {
+        value: 'postAggregations',
+        documentation: 'Post-aggregations to compute',
+      },
+      { value: 'having', documentation: 'Having clause to filter groups' },
+      { value: 'limitSpec', documentation: 'Limit and ordering specification' 
},
+    ],
+  },
+
+  // Scan query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'scan',
+    completions: [
+      { value: 'columns', documentation: 'Columns to return' },
+      { value: 'limit', documentation: 'Maximum number of rows to return' },
+      { value: 'offset', documentation: 'Number of rows to skip' },
+      { value: 'resultFormat', documentation: 'Format of the result' },
+      { value: 'batchSize', documentation: 'Batch size for streaming' },
+      { value: 'legacy', documentation: 'Use legacy scan query mode' },
+      { value: 'order', documentation: 'Result ordering (none, ascending, 
descending)' },
+    ],
+  },
+
+  // Search query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'search',
+    completions: [
+      { value: 'granularity', documentation: 'Time granularity for bucketing' 
},
+      { value: 'searchDimensions', documentation: 'Dimensions to search' },
+      { value: 'query', documentation: 'Search query specification' },
+      { value: 'sort', documentation: 'Sort specification for results' },
+      { value: 'limit', documentation: 'Maximum number of results to return' },
+    ],
+  },
+
+  // TimeBoundary query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'timeBoundary',
+    completions: [
+      {
+        value: 'bound',
+        documentation: 'Which boundary to return (minTime, maxTime, or null 
for both)',
+      },
+    ],
+  },
+
+  // SegmentMetadata query specific properties
+  {
+    path: '$',
+    isObject: true,
+    condition: obj => obj.queryType === 'segmentMetadata',
+    completions: [
+      { value: 'toInclude', documentation: 'Columns to include in the result 
(defaults to "all")' },
+      {
+        value: 'merge',
+        documentation: 'Merge all individual segment metadata results into a 
single result',
+      },
+      {
+        value: 'analysisTypes',
+        documentation: 'Column properties to calculate and return (e.g. 
cardinality, size)',
+      },
+      {
+        value: 'aggregatorMergeStrategy',
+        documentation: 'Strategy for merging aggregators: strict, lenient, 
earliest, or latest',
+      },
+      {
+        value: 'lenientAggregatorMerge',
+        documentation: 'Deprecated. Use aggregatorMergeStrategy instead',
+      },
+    ],
+  },
+
+  // SegmentMetadata toInclude properties
+  {
+    path: '$.toInclude',
+    isObject: true,
+    condition: obj => obj.queryType === 'segmentMetadata',
+    completions: [
+      { value: 'type', documentation: 'Type of columns to include: all, none, 
or list' },
+    ],
+  },
+
+  // SegmentMetadata toInclude types
+  {
+    path: '$.toInclude.type',
+    condition: obj => obj.queryType === 'segmentMetadata',
+    completions: [
+      { value: 'all', documentation: 'Include all columns in the result' },
+      { value: 'none', documentation: 'Include no columns in the result' },
+      { value: 'list', documentation: 'Include specific columns listed in the 
columns array' },
+    ],
+  },
+
+  // SegmentMetadata toInclude list properties
+  {
+    path: '$.toInclude',
+    isObject: true,
+    condition: obj => obj.queryType === 'segmentMetadata' && 
obj.toInclude?.type === 'list',
+    completions: [{ value: 'columns', documentation: 'Array of column names to 
include' }],
+  },
+
+  // SegmentMetadata analysisTypes values
+  {
+    path: '$.analysisTypes.[]',
+    condition: obj => obj.queryType === 'segmentMetadata',
+    completions: [
+      { value: 'cardinality', documentation: 'Number of unique values in 
string columns' },
+      { value: 'interval', documentation: 'Time intervals associated with 
queried segments' },
+      { value: 'minmax', documentation: 'Estimated min/max values for string 
columns' },
+      { value: 'size', documentation: 'Estimated byte size as if stored in 
text format' },
+      { value: 'timestampSpec', documentation: 'Timestamp specification of 
data in segments' },
+      { value: 'queryGranularity', documentation: 'Query granularity of data 
in segments' },
+      { value: 'aggregators', documentation: 'List of aggregators usable for 
metric columns' },
+      { value: 'rollup', documentation: 'Whether the segments are rolled up' },

Review Comment:
   #18119 recently added a `projection` analysis type



##########
web-console/src/dialogs/compaction-config-dialog/compaction-config-completions.ts:
##########
@@ -0,0 +1,401 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import type { JsonCompletionRule } from '../../utils';
+
+export const COMPACTION_CONFIG_COMPLETIONS: JsonCompletionRule[] = [
+  // Root level properties
+  {
+    path: '$',

Review Comment:
   this isn't really correct, after #17803 there is a "type" for a datasource 
compaction config, with the old spec type being "inline" and the one added in 
that PR is "catalog"



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to