mirror of
https://github.com/plausible/analytics.git
synced 2024-12-23 17:44:43 +03:00
Assert filters are tuples, simplify schema (#4541)
This commit is contained in:
parent
e8d544c841
commit
52b94842c0
@ -17,11 +17,11 @@ defmodule Plausible.Stats.JSONSchema do
|
|||||||
@internal_query_schema @raw_public_schema
|
@internal_query_schema @raw_public_schema
|
||||||
# Add overrides for things allowed in the internal API
|
# Add overrides for things allowed in the internal API
|
||||||
|> JSONPointer.add!(
|
|> JSONPointer.add!(
|
||||||
"#/definitions/filter_entry/oneOf/0/items/0/enum/0",
|
"#/definitions/filter_operation_without_goals/enum/0",
|
||||||
"matches_wildcard"
|
"matches_wildcard"
|
||||||
)
|
)
|
||||||
|> JSONPointer.add!(
|
|> JSONPointer.add!(
|
||||||
"#/definitions/filter_entry/oneOf/0/items/0/enum/0",
|
"#/definitions/filter_operation_without_goals/enum/0",
|
||||||
"matches_wildcard_not"
|
"matches_wildcard_not"
|
||||||
)
|
)
|
||||||
|> JSONPointer.add!("#/definitions/metric/oneOf/0", %{
|
|> JSONPointer.add!("#/definitions/metric/oneOf/0", %{
|
||||||
|
@ -29,9 +29,7 @@
|
|||||||
},
|
},
|
||||||
"filters": {
|
"filters": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": { "$ref": "#/definitions/filter_tree" },
|
||||||
"$ref": "#/definitions/filter_entry"
|
|
||||||
},
|
|
||||||
"description": "How to drill into your data"
|
"description": "How to drill into your data"
|
||||||
},
|
},
|
||||||
"order_by": {
|
"order_by": {
|
||||||
@ -54,11 +52,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": ["site_id", "metrics", "date_range"],
|
||||||
"site_id",
|
|
||||||
"metrics",
|
|
||||||
"date_range"
|
|
||||||
],
|
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"definitions": {
|
"definitions": {
|
||||||
"date_range": {
|
"date_range": {
|
||||||
@ -97,23 +91,21 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
"additionalItems": false,
|
||||||
|
"minItems": 2,
|
||||||
|
"maxItems": 2,
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^\\d{4}-\\d{2}-\\d{2}(?:T\\d{2}:\\d{2}:\\d{2}\\s[A-Za-z/_]+)?$"
|
"pattern": "^\\d{4}-\\d{2}-\\d{2}(?:T\\d{2}:\\d{2}:\\d{2}\\s[A-Za-z/_]+)?$"
|
||||||
},
|
},
|
||||||
"markdownDescription": "A list of two elements to determine the query date range. Both elements should have the same format - either `YYYY-MM-DD` or `YYYY-MM-DDThh:mm:ss <timezone>`",
|
"markdownDescription": "A list of two elements to determine the query date range. Both elements should have the same format - either `YYYY-MM-DD` or `YYYY-MM-DDThh:mm:ss <timezone>`",
|
||||||
"examples": [
|
"examples": [
|
||||||
[
|
["2024-01-01", "2024-01-31"],
|
||||||
"2024-01-01",
|
|
||||||
"2024-01-31"
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
"2024-01-01T00:00:00 Europe/Tallinn",
|
"2024-01-01T00:00:00 Europe/Tallinn",
|
||||||
"2024-01-01T12:00:00 Europe/Tallinn"
|
"2024-01-01T12:00:00 Europe/Tallinn"
|
||||||
]
|
]
|
||||||
],
|
]
|
||||||
"minItems": 2,
|
|
||||||
"maxItems": 2
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -196,10 +188,7 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^event:props:.+",
|
"pattern": "^event:props:.+",
|
||||||
"markdownDescription": "Custom property. See [documentation](https://plausible.io/docs/custom-props/introduction) for more information",
|
"markdownDescription": "Custom property. See [documentation](https://plausible.io/docs/custom-props/introduction) for more information",
|
||||||
"examples": [
|
"examples": ["event:props:url", "event:props:path"]
|
||||||
"event:props:url",
|
|
||||||
"event:props:path"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"goal_dimension": {
|
"goal_dimension": {
|
||||||
"const": "event:goal",
|
"const": "event:goal",
|
||||||
@ -207,28 +196,14 @@
|
|||||||
},
|
},
|
||||||
"time_dimensions": {
|
"time_dimensions": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": ["time", "time:month", "time:week", "time:day", "time:hour"]
|
||||||
"time",
|
|
||||||
"time:month",
|
|
||||||
"time:week",
|
|
||||||
"time:day",
|
|
||||||
"time:hour"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"dimensions": {
|
"dimensions": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{ "$ref": "#/definitions/simple_filter_dimensions" },
|
||||||
"$ref": "#/definitions/simple_filter_dimensions"
|
{ "$ref": "#/definitions/custom_property_filter_dimensions" },
|
||||||
},
|
{ "$ref": "#/definitions/goal_dimension" },
|
||||||
{
|
{ "$ref": "#/definitions/time_dimensions" }
|
||||||
"$ref": "#/definitions/custom_property_filter_dimensions"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/goal_dimension"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/time_dimensions"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"clauses": {
|
"clauses": {
|
||||||
@ -237,129 +212,108 @@
|
|||||||
"type": ["string", "integer"]
|
"type": ["string", "integer"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"filter_operation_without_goals": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["is_not", "contains_not", "matches", "matches_not"],
|
||||||
|
"description": "filter operation"
|
||||||
|
},
|
||||||
|
"filter_operation_with_goals": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["is", "contains"],
|
||||||
|
"description": "filter operation"
|
||||||
|
},
|
||||||
|
"filter_without_goals": {
|
||||||
|
"type": "array",
|
||||||
|
"additionalItems": false,
|
||||||
|
"minItems": 3,
|
||||||
|
"maxItems": 3,
|
||||||
|
"items": [
|
||||||
|
{ "$ref": "#/definitions/filter_operation_without_goals" },
|
||||||
|
{
|
||||||
|
"oneOf": [
|
||||||
|
{ "$ref": "#/definitions/simple_filter_dimensions" },
|
||||||
|
{ "$ref": "#/definitions/custom_property_filter_dimensions" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ "$ref": "#/definitions/clauses" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"filter_with_goals": {
|
||||||
|
"type": "array",
|
||||||
|
"additionalItems": false,
|
||||||
|
"minItems": 3,
|
||||||
|
"maxItems": 3,
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/filter_operation_with_goals"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"oneOf": [
|
||||||
|
{ "$ref": "#/definitions/goal_dimension" },
|
||||||
|
{ "$ref": "#/definitions/simple_filter_dimensions" },
|
||||||
|
{ "$ref": "#/definitions/custom_property_filter_dimensions" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/clauses"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"filter_entry": {
|
"filter_entry": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{ "$ref": "#/definitions/filter_without_goals" },
|
||||||
"type": "array",
|
{ "$ref": "#/definitions/filter_with_goals" }
|
||||||
"items": [
|
]
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"enum": [
|
|
||||||
"is_not",
|
|
||||||
"contains_not",
|
|
||||||
"matches",
|
|
||||||
"matches_not"
|
|
||||||
],
|
|
||||||
"description": "filter operation"
|
|
||||||
},
|
},
|
||||||
{
|
"filter_tree": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{ "$ref": "#/definitions/filter_entry" },
|
||||||
"$ref": "#/definitions/simple_filter_dimensions"
|
{ "$ref": "#/definitions/filter_and_or" },
|
||||||
},
|
{ "$ref": "#/definitions/filter_not" }
|
||||||
{
|
|
||||||
"$ref": "#/definitions/custom_property_filter_dimensions"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/clauses"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "array",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"enum": [
|
|
||||||
"is",
|
|
||||||
"contains"
|
|
||||||
],
|
|
||||||
"description": "filter operation"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"oneOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/goal_dimension"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/simple_filter_dimensions"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/custom_property_filter_dimensions"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/clauses"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/filter_and_or"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/filter_not"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"filter_not": {
|
"filter_not": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": [
|
"additionalItems": false,
|
||||||
{
|
"minItems": 2,
|
||||||
"const": "not"
|
"maxItems": 2,
|
||||||
},
|
"items": [{ "const": "not" }, { "$ref": "#/definitions/filter_tree" }]
|
||||||
{
|
|
||||||
"$ref": "#/definitions/filter_entry"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"filter_and_or": {
|
"filter_and_or": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
"additionalItems": false,
|
||||||
|
"minItems": 2,
|
||||||
|
"maxItems": 2,
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": ["and", "or"]
|
||||||
"and",
|
|
||||||
"or"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": { "$ref": "#/definitions/filter_tree" },
|
||||||
"$ref": "#/definitions/filter_entry"
|
|
||||||
},
|
|
||||||
"minItems": 1
|
"minItems": 1
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"order_by_entry": {
|
"order_by_entry": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
"additionalItems": false,
|
||||||
|
"minItems": 2,
|
||||||
|
"maxItems": 2,
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{ "$ref": "#/definitions/metric" },
|
||||||
"$ref": "#/definitions/metric"
|
{ "$ref": "#/definitions/simple_filter_dimensions" },
|
||||||
},
|
{ "$ref": "#/definitions/custom_property_filter_dimensions" },
|
||||||
{
|
{ "$ref": "#/definitions/time_dimensions" }
|
||||||
"$ref": "#/definitions/simple_filter_dimensions"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/custom_property_filter_dimensions"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/time_dimensions"
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
"markdownDescription": "Metric or dimension to order by. Must be listed under `metrics` or `dimensions`"
|
"markdownDescription": "Metric or dimension to order by. Must be listed under `metrics` or `dimensions`"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": ["asc", "desc"],
|
||||||
"asc",
|
|
||||||
"desc"
|
|
||||||
],
|
|
||||||
"description": "Sorting order"
|
"description": "Sorting order"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -238,6 +238,60 @@ defmodule Plausible.Stats.Filters.QueryParserTest do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
for too_short_filter <- [
|
||||||
|
[],
|
||||||
|
["and"],
|
||||||
|
["or"],
|
||||||
|
["and", []],
|
||||||
|
["or", []],
|
||||||
|
["not"],
|
||||||
|
["is_not"],
|
||||||
|
["is_not", "event:name"]
|
||||||
|
] do
|
||||||
|
test "errors on too short filter #{inspect(too_short_filter)}", %{
|
||||||
|
site: site
|
||||||
|
} do
|
||||||
|
%{
|
||||||
|
"site_id" => site.domain,
|
||||||
|
"metrics" => ["visitors"],
|
||||||
|
"date_range" => "all",
|
||||||
|
"filters" => [
|
||||||
|
unquote(too_short_filter)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|> check_error(
|
||||||
|
site,
|
||||||
|
~s(#/filters/0: Invalid filter #{inspect(unquote(too_short_filter))})
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
valid_filter = ["is", "event:props:foobar", ["value"]]
|
||||||
|
|
||||||
|
for too_long_filter <- [
|
||||||
|
["and", [valid_filter], "extra"],
|
||||||
|
["or", [valid_filter], []],
|
||||||
|
["not", valid_filter, 1],
|
||||||
|
Enum.concat(valid_filter, [true])
|
||||||
|
] do
|
||||||
|
test "errors on too long filter #{inspect(too_long_filter)}", %{
|
||||||
|
site: site
|
||||||
|
} do
|
||||||
|
%{
|
||||||
|
"site_id" => site.domain,
|
||||||
|
"metrics" => ["visitors"],
|
||||||
|
"date_range" => "all",
|
||||||
|
"filters" => [
|
||||||
|
unquote(too_long_filter)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|> check_error(
|
||||||
|
site,
|
||||||
|
~s(#/filters/0: Invalid filter #{inspect(unquote(too_long_filter))})
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
test "filtering by invalid operation", %{site: site} do
|
test "filtering by invalid operation", %{site: site} do
|
||||||
%{
|
%{
|
||||||
"site_id" => site.domain,
|
"site_id" => site.domain,
|
||||||
|
Loading…
Reference in New Issue
Block a user