Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d264710
Define schemas for simple filter interface
nickpeihl Oct 29, 2025
5989e98
Add descriptions to schemas
nickpeihl Oct 29, 2025
f900770
Remove id and rename indexPattern to dataViewId
nickpeihl Oct 30, 2025
5037bbe
Merge remote-tracking branch 'upstream/main' into simple-filters-schema
nickpeihl Oct 31, 2025
fb0f138
Changes from node scripts/lint_ts_projects --fix
kibanamachine Oct 31, 2025
b49449a
Fix filter value schema arrays to be homogeneous
nickpeihl Nov 5, 2025
ab20892
Fix casing inconsistency
nickpeihl Nov 5, 2025
48689fc
Naming consistency
nickpeihl Nov 5, 2025
f13c024
Stricter discriminated filter conditions
nickpeihl Nov 5, 2025
539a159
Document controlledBy field
nickpeihl Nov 5, 2025
565848a
Remove duplicate stored filter schema
nickpeihl Nov 5, 2025
7f85963
Changes from node scripts/lint_ts_projects --fix
kibanamachine Nov 5, 2025
51c30b1
Rename path
nickpeihl Nov 5, 2025
a2979a9
Merge remote-tracking branch 'refs/remotes/origin/simple-filters-sche…
nickpeihl Nov 5, 2025
883b3b6
Rename stored filter schema to "storedFilterSchema" and "simpleFilter…
nickpeihl Nov 6, 2025
3cbf28b
Add constants package to avoid circular references
nickpeihl Nov 7, 2025
00bd945
Add isMultiIindex, filterType, and BWC legacy properties
nickpeihl Nov 7, 2025
8aa68b4
Changes from node scripts/generate codeowners
kibanamachine Nov 7, 2025
e72bb46
Merge branch 'main' into simple-filters-schema
nickpeihl Nov 7, 2025
6b5e025
Rename AsCodeFilter types
nickpeihl Nov 7, 2025
f94f926
Merge remote-tracking branch 'origin/simple-filters-schema' into simp…
nickpeihl Nov 7, 2025
d1c1ea2
As "asCode" prefix to exported schemas
nickpeihl Nov 7, 2025
27870ca
Don't export StoredFilter types
nickpeihl Nov 7, 2025
36da619
Use schema extend instead of spread
nickpeihl Nov 7, 2025
7702432
Remove unnecessary nested query object from DSL schema
nickpeihl Nov 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,7 @@ src/platform/packages/shared/kbn-es @elastic/kibana-operations
src/platform/packages/shared/kbn-es-archiver @elastic/appex-qa
src/platform/packages/shared/kbn-es-errors @elastic/kibana-core
src/platform/packages/shared/kbn-es-query @elastic/kibana-data-discovery
src/platform/packages/shared/kbn-es-query-constants @elastic/kibana-data-discovery
src/platform/packages/shared/kbn-es-query-server @elastic/kibana-data-discovery
src/platform/packages/shared/kbn-es-types @elastic/kibana-core @elastic/obs-knowledge-team
src/platform/packages/shared/kbn-esql-ast @elastic/kibana-esql
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,7 @@
"@kbn/error-boundary-example-plugin": "link:examples/error_boundary",
"@kbn/es-errors": "link:src/platform/packages/shared/kbn-es-errors",
"@kbn/es-query": "link:src/platform/packages/shared/kbn-es-query",
"@kbn/es-query-constants": "link:src/platform/packages/shared/kbn-es-query-constants",
"@kbn/es-query-server": "link:src/platform/packages/shared/kbn-es-query-server",
"@kbn/es-types": "link:src/platform/packages/shared/kbn-es-types",
"@kbn/es-ui-shared-plugin": "link:src/platform/plugins/shared/es_ui_shared",
Expand Down
3 changes: 3 additions & 0 deletions src/platform/packages/shared/kbn-es-query-constants/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# @kbn/es-query-constants

Constants that can be used by both `@kbn/es-query` and `@kbn/es-query-server` packages to avoid circular references.
10 changes: 10 additions & 0 deletions src/platform/packages/shared/kbn-es-query-constants/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

export { FilterStateStore } from './src/constants';
14 changes: 14 additions & 0 deletions src/platform/packages/shared/kbn-es-query-constants/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

module.exports = {
preset: '@kbn/test/jest_node',
rootDir: '../../../../..',
roots: ['<rootDir>/src/platform/packages/shared/kbn-es-query-constants'],
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "shared-common",
"id": "@kbn/es-query-constants",
"owner": "@elastic/kibana-data-discovery",
"group": "platform",
"visibility": "shared"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "@kbn/es-query-constants",
"private": true,
"version": "1.0.0",
"license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0"
"license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0",
"sideEffects": false

Probably worth disabling side effects for this package even if it's tiny atm.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

/**
Filter,
* An enum to denote whether a filter is specific to an application's context or whether it should be applied globally.
* @public
*/
export enum FilterStateStore {
APP_STATE = 'appState',
GLOBAL_STATE = 'globalState',
}
17 changes: 17 additions & 0 deletions src/platform/packages/shared/kbn-es-query-constants/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"extends": "../../../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types",
"types": [
"jest",
"node"
]
},
"include": [
"**/*.ts",
],
"exclude": [
"target/**/*"
],
"kbn_references": []
}
14 changes: 3 additions & 11 deletions src/platform/packages/shared/kbn-es-query-server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,14 @@

export { timeRangeSchema } from './src/time_range';
export { querySchema } from './src/query';
export { appStateSchema, globalStateSchema, filterSchema } from './src/filter/stored_filter';
export { simpleFilterSchema } from './src/filter/simple_filter';
export { asCodeFilterSchema } from './src/filter';
export { storedFilterSchema } from './src/stored_filter';

export type {
TimeRange,
AbsoluteTimeRange,
RelativeTimeRange,
Filter,
FilterMeta,
AggregateQuery,
Query,
SimpleFilter,
SimpleFilterCondition,
SimpleFilterGroup,
SimpleDSLFilter,
SimpleFilterValue,
SimpleRangeValue,
StoredFilterState,
AsCodeFilter,
} from './src/types';
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { schema } from '@kbn/config-schema';
/**
* Schema for range values used in numeric and date filters
*/
export const rangeValueSchema = schema.object({
const rangeSchema = schema.object({
gte: schema.maybe(
schema.oneOf([schema.number(), schema.string()], {
meta: { description: 'Greater than or equal to' },
Expand All @@ -46,30 +46,14 @@ export const rangeValueSchema = schema.object({
),
});

/**
* Schema for all possible filter values
*/
export const filterValueSchema = schema.oneOf(
[
schema.string(),
schema.number(),
schema.boolean(),
schema.arrayOf(schema.string()),
schema.arrayOf(schema.number()),
schema.arrayOf(schema.boolean()),
rangeValueSchema,
],
{ meta: { description: 'Filter value - single value, array of homogeneous values, or range' } }
);

// ====================================================================
// BASE FILTER PROPERTIES (SHARED BY ALL SIMPLIFIED FILTERS)
// BASE PROPERTIES (SHARED BY ALL FILTERS)
// ====================================================================

/**
* Base properties shared by all simplified filters
*/
const baseFilterPropertiesSchema = {
const basePropertiesSchema = schema.object({
pinned: schema.maybe(
schema.boolean({
meta: { description: 'Whether the filter is pinned' },
Expand Down Expand Up @@ -102,24 +86,50 @@ const baseFilterPropertiesSchema = {
meta: { description: 'Human-readable label for the filter' },
})
),
};
isMultiIndex: schema.maybe(
schema.boolean({
meta: { description: 'Whether this filter can be applied to multiple indices' },
})
),
filterType: schema.maybe(
schema.string({
meta: {
description:
'Filter type from legacy filters (e.g., "spatial_filter", "query_string") for backwards compatibility',
},
})
),
key: schema.maybe(
schema.string({
meta: {
description: 'Field name metadata from legacy filters for backwards compatibility',
},
})
),
value: schema.maybe(
schema.string({
meta: {
description: 'Value metadata from legacy filters for backwards compatibility',
},
})
),
Comment on lines +94 to +115
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these all related to the spatial filter?

});

// ====================================================================
// SIMPLE FILTER CONDITION SCHEMAS
// FILTER CONDITION SCHEMAS
// ====================================================================

/**
* Common field property for all filter conditions
*/
const filterConditionFieldSchema = {
const conditionFieldSchema = schema.object({
field: schema.string({ meta: { description: 'Field the filter applies to' } }),
};
});

/**
* Schema for 'is' and 'is_not' operators with single value
*/
const filterConditionIsSingleSchema = schema.object({
...filterConditionFieldSchema,
const singleConditionSchema = conditionFieldSchema.extends({
operator: schema.oneOf([schema.literal('is'), schema.literal('is_not')], {
meta: { description: 'Single value comparison operators' },
}),
Expand All @@ -131,8 +141,7 @@ const filterConditionIsSingleSchema = schema.object({
/**
* Schema for 'is_one_of' and 'is_not_one_of' operators with array values
*/
const filterConditionIsOneOfSchema = schema.object({
...filterConditionFieldSchema,
const oneOfConditionSchema = conditionFieldSchema.extends({
operator: schema.oneOf([schema.literal('is_one_of'), schema.literal('is_not_one_of')], {
meta: { description: 'Array value comparison operators' },
}),
Expand All @@ -149,17 +158,15 @@ const filterConditionIsOneOfSchema = schema.object({
/**
* Schema for 'range' operator with range value
*/
const filterConditionRangeSchema = schema.object({
...filterConditionFieldSchema,
const rangeConditionSchema = conditionFieldSchema.extends({
operator: schema.literal('range'),
value: rangeValueSchema,
value: rangeSchema,
});

/**
* Schema for 'exists' and 'not_exists' operators without value
*/
const filterConditionExistsSchema = schema.object({
...filterConditionFieldSchema,
const existsConditionSchema = conditionFieldSchema.extends({
operator: schema.oneOf([schema.literal('exists'), schema.literal('not_exists')], {
meta: { description: 'Field existence check operators' },
}),
Expand All @@ -169,93 +176,62 @@ const filterConditionExistsSchema = schema.object({
/**
* Discriminated union schema for simple filter conditions with proper operator/value type combinations
*/
export const simpleFilterConditionSchema = schema.oneOf(
[
filterConditionIsSingleSchema,
filterConditionIsOneOfSchema,
filterConditionRangeSchema,
filterConditionExistsSchema,
],
const conditionSchema = schema.oneOf(
[singleConditionSchema, oneOfConditionSchema, rangeConditionSchema, existsConditionSchema],
{ meta: { description: 'A filter condition with strict operator/value type matching' } }
);

// ====================================================================
// FILTER GROUP SCHEMA (RECURSIVE)
// FILTER DISCRIMINATED UNION SCHEMA
// ====================================================================

/**
* Schema for logical filter groups with recursive structure
* Uses lazy schema to handle recursive references
* Note: Groups only contain logical structure (type, conditions) - no metadata properties
* Schema for condition filters
*/
export const filterGroupSchema = schema.object(
export const asCodeConditionFilterSchema = basePropertiesSchema.extends(
{
type: schema.oneOf([schema.literal('and'), schema.literal('or')]),
conditions: schema.arrayOf(
schema.oneOf([
simpleFilterConditionSchema,
schema.lazy('filterGroup'), // Recursive reference
])
),
condition: conditionSchema,
},
{ meta: { description: 'Grouped filters', id: 'filterGroup' } }
{ meta: { description: 'Condition filter' } }
);

// ====================================================================
// RAW DSL FILTER SCHEMA
// ====================================================================

/**
* Schema for raw Elasticsearch Query DSL filters
*/
export const rawDSLFilterSchema = schema.object({
query: schema.recordOf(schema.string(), schema.any(), {
meta: { description: 'Elasticsearch Query DSL object' },
}),
});

// ====================================================================
// SIMPLE FILTER DISCRIMINATED UNION SCHEMA
// ====================================================================

/**
* Schema for simple condition filters (Tier 1)
*/
export const simpleConditionFilterSchema = schema.object(
{
...baseFilterPropertiesSchema,
condition: simpleFilterConditionSchema,
},
{ meta: { description: 'Simple condition filter' } }
);

/**
* Schema for grouped condition filters (Tier 2-3)
* Schema for logical filter groups with recursive structure
* Uses lazy schema to handle recursive references
*/
export const simpleGroupFilterSchema = schema.object(
const GROUP_FILTER_ID = '@kbn/es-query-server_groupFilter'; // package prefix for global uniqueness in OAS specs
export const asCodeGroupFilterSchema = basePropertiesSchema.extends(
{
...baseFilterPropertiesSchema,
group: filterGroupSchema,
group: schema.object(
{
type: schema.oneOf([schema.literal('and'), schema.literal('or')]),
conditions: schema.arrayOf(
schema.oneOf([
conditionSchema,
schema.lazy(GROUP_FILTER_ID), // Recursive reference for nested groups
])
),
},
{ meta: { description: 'Condition or nested group filter', id: GROUP_FILTER_ID } }
),
},
{ meta: { description: 'Grouped condition filter' } }
);

/**
* Schema for raw DSL filters (Tier 4)
* Schema for DSL filters
*/
export const simpleDSLFilterSchema = schema.object(
{
...baseFilterPropertiesSchema,
dsl: rawDSLFilterSchema,
},
{ meta: { description: 'Raw DSL filter' } }
);
export const asCodeDSLFilterSchema = basePropertiesSchema.extends({
dsl: schema.recordOf(schema.string(), schema.any(), {
meta: { description: 'Elasticsearch Query DSL object' },
}),
});

/**
* Main discriminated union schema for SimpleFilter
* Main discriminated union schema for Filter
* Ensures exactly one of: condition, group, or dsl is present
*/
export const simpleFilterSchema = schema.oneOf(
[simpleConditionFilterSchema, simpleGroupFilterSchema, simpleDSLFilterSchema],
export const asCodeFilterSchema = schema.oneOf(
[asCodeConditionFilterSchema, asCodeGroupFilterSchema, asCodeDSLFilterSchema],
{ meta: { description: 'A filter which can be a condition, group, or raw DSL' } }
);
Loading