diff --git a/schema/audience-definition-schema.json b/schema/audience-definition-schema.json index 26f0763..f53e15d 100644 --- a/schema/audience-definition-schema.json +++ b/schema/audience-definition-schema.json @@ -26,6 +26,23 @@ ], "type": "string" }, + "AliasPath": { + "additionalProperties": false, + "description": "References a specific field on a named alias (e.g., a step in an event sequence). Examples: 1. Reference event1's timestamp: { alias: \"event1\", path: \"timestamp\" }", + "properties": { + "alias": { + "type": "string" + }, + "path": { + "type": "string" + } + }, + "required": [ + "alias", + "path" + ], + "type": "object" + }, "ArithmeticOperator": { "description": "Represents mathematical operators for numeric calculations. Examples:\n- \"plus\": { value1: 5, value2: 3 } // result: 8\n- \"multiply\": { value1: 4, value2: 2 } // result: 8\n- \"mod\": { value1: 10, value2: 3 } // result: 1", "enum": [ @@ -309,6 +326,26 @@ ], "type": "object", "title": "LogicalExpression" + }, + { + "additionalProperties": false, + "properties": { + "operator": { + "$ref": "#/definitions/SequenceOperator" + }, + "sequence": { + "items": { + "$ref": "#/definitions/SequenceOperand" + }, + "type": "array" + } + }, + "required": [ + "operator", + "sequence" + ], + "type": "object", + "title": "SequenceExpression" } ], "description": "Represents a complex expression that can evaluate to true, false, or noop. Examples: 1. Join expression (combining expressions from different models): { \"model\": \"user\", \"expression\": { \"operator\": \"equals\", \"left\": { \"path\": \"age\" }, \"right\": 18 } }\n\n2. Logical expression (AND): { \"operator\": \"and\", \"expressions\": [ { \"operator\": \"equals\", \"left\": { \"path\": \"country\" }, \"right\": \"US\" }, { \"operator\": \"greater_than\", \"left\": { \"path\": \"age\" }, \"right\": 18 } ] }\n\n3. Location expression: { \"operator\": \"within\", \"left\": { \"location\": { \"latitude\": 37.7749, \"longitude\": -122.4194, \"distance\": { \"value\": 10, \"unit\": \"miles\" } } }, \"right\": { \"model\": \"user\", \"path\": \"location\" } }" @@ -562,7 +599,7 @@ }, "RelativeDate": { "additionalProperties": false, - "description": "Represents a date/time relative to the current time. Examples: 1. 7 days ago: { relative: { offset: -7, unit: \"day\" } }\n\n2. Start of current month: { relative: { offset: 0, unit: \"month\", boundary: \"start\" } }\n\n3. End of previous quarter: { relative: { offset: -1, unit: \"quarter\", boundary: \"end\" } }", + "description": "Represents a date/time relative to the current time, or optionally relative to a named alias field. Examples: 1. 7 days ago: { relative: { offset: -7, unit: \"day\" } }\n\n2. Start of current month: { relative: { offset: 0, unit: \"month\", boundary: \"start\" } }\n\n3. End of previous quarter: { relative: { offset: -1, unit: \"quarter\", boundary: \"end\" } }\n\n4. Within 7 days of event1's timestamp (for event sequencing): { relative: { offset: 7, unit: \"day\", relative_to: { alias: \"event1\", path: \"timestamp\" } } }", "properties": { "relative": { "additionalProperties": false, @@ -577,6 +614,9 @@ "offset": { "type": "number" }, + "relative_to": { + "$ref": "#/definitions/AliasPath" + }, "unit": { "$ref": "#/definitions/DateUnit" } @@ -593,6 +633,31 @@ ], "type": "object" }, + "SequenceOperand": { + "additionalProperties": false, + "description": "Represents a single step in an event sequence. The alias uniquely identifies this step so other parts of the definition (e.g., relative_to) can reference it. Examples: 1. Step A with a timestamp operand and event name filter: { \"alias\": \"event1\", \"operand\": { \"model\": \"events\", \"path\": \"timestamp\" }, \"condition\": { \"operator\": \"equal\", \"left\": { \"model\": \"events\", \"path\": \"name\" }, \"right\": \"purchase\" } }", + "properties": { + "alias": { + "type": "string" + }, + "condition": { + "$ref": "#/definitions/Expression" + }, + "operand": { + "$ref": "#/definitions/ModelPath" + } + }, + "required": [ + "alias", + "operand" + ], + "type": "object" + }, + "SequenceOperator": { + "const": "then", + "description": "Represents operators for expressing ordered event sequences. Examples:\n- \"then\": user performed Event A, then Event B { operator: \"then\", sequence: [{ alias: \"a\", operand: {...} }, { alias: \"b\", operand: {...} }] }", + "type": "string" + }, "UnaryOperator": { "description": "Represents unary operators that operate on a single value. Examples:\n- \"not\": Negates a boolean expression\n- \"exist\": Checks if a value exists", "enum": [ diff --git a/sdk/python/mp_audience_sdk/models/audience_models.py b/sdk/python/mp_audience_sdk/models/audience_models.py index 2984ee8..62022b6 100644 --- a/sdk/python/mp_audience_sdk/models/audience_models.py +++ b/sdk/python/mp_audience_sdk/models/audience_models.py @@ -1,11 +1,11 @@ # generated by datamodel-codegen: # filename: audience-definition-schema.json -# timestamp: 2026-01-26T22:57:53+00:00 +# timestamp: 2026-03-10T15:26:29+00:00 from __future__ import annotations from enum import Enum -from typing import Any, List, Optional, Union +from typing import Any, List, Literal, Optional, Union from pydantic import BaseModel, ConfigDict, Field, RootModel @@ -30,6 +30,14 @@ class AggregationOperator(Enum): count = "count" +class AliasPath(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + alias: str + path: str + + class ArithmeticOperator(Enum): plus = "plus" minus = "minus" @@ -164,6 +172,7 @@ class Relative(BaseModel): ) boundary: Optional[Boundary] = None offset: float + relative_to: Optional[AliasPath] = None unit: DateUnit @@ -174,6 +183,13 @@ class RelativeDate(BaseModel): relative: Relative +class SequenceOperator(RootModel[Literal["then"]]): + root: Literal["then"] = Field( + ..., + description='Represents operators for expressing ordered event sequences. Examples:\n- "then": user performed Event A, then Event B { operator: "then", sequence: [{ alias: "a", operand: {...} }, { alias: "b", operand: {...} }] }', + ) + + class UnaryOperator(Enum): null = "null" not_null = "not_null" @@ -299,10 +315,22 @@ class LogicalExpression(BaseModel): operator: LogicalOperator +class SequenceExpression(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + operator: SequenceOperator + sequence: List[SequenceOperand] + + class Expression( - RootModel[Union[UnaryExpression, BinaryExpression, LogicalExpression]] + RootModel[ + Union[UnaryExpression, BinaryExpression, LogicalExpression, SequenceExpression] + ] ): - root: Union[UnaryExpression, BinaryExpression, LogicalExpression] = Field( + root: Union[ + UnaryExpression, BinaryExpression, LogicalExpression, SequenceExpression + ] = Field( ..., description='Represents a complex expression that can evaluate to true, false, or noop. Examples: 1. Join expression (combining expressions from different models): { "model": "user", "expression": { "operator": "equals", "left": { "path": "age" }, "right": 18 } }\n\n2. Logical expression (AND): { "operator": "and", "expressions": [ { "operator": "equals", "left": { "path": "country" }, "right": "US" }, { "operator": "greater_than", "left": { "path": "age" }, "right": 18 } ] }\n\n3. Location expression: { "operator": "within", "left": { "location": { "latitude": 37.7749, "longitude": -122.4194, "distance": { "value": 10, "unit": "miles" } } }, "right": { "model": "user", "path": "location" } }', ) @@ -389,6 +417,15 @@ class PathExpression( ) +class SequenceOperand(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + alias: str + condition: Optional[Expression] = None + operand: ModelPath + + AudienceDefinition.model_rebuild() CountExpression1.model_rebuild() CountExpression2.model_rebuild() @@ -396,6 +433,7 @@ class PathExpression( UnaryExpression.model_rebuild() BinaryExpression.model_rebuild() LogicalExpression.model_rebuild() +SequenceExpression.model_rebuild() LocationExpression2.model_rebuild() ModelAggregationOperand.model_rebuild() UnaryPathExpression.model_rebuild() diff --git a/sdk/python/pyproject.toml b/sdk/python/pyproject.toml index c6e2087..7d60f0b 100644 --- a/sdk/python/pyproject.toml +++ b/sdk/python/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "mp_audience_sdk" -version = "0.2.8" +version = "0.2.9" description = "mParticle Audience SDK" readme = "README.md" requires-python = ">=3.11" diff --git a/sdk/typescript-schema/common/operator.ts b/sdk/typescript-schema/common/operator.ts index df624d9..f5d8ac8 100644 --- a/sdk/typescript-schema/common/operator.ts +++ b/sdk/typescript-schema/common/operator.ts @@ -113,3 +113,11 @@ export type LocationOperator = export type LogicalOperator = "and" | "or" + +/** + * Represents operators for expressing ordered event sequences. + * Examples: + * - "then": user performed Event A, then Event B + * { operator: "then", sequence: [{ alias: "a", operand: {...} }, { alias: "b", operand: {...} }] } + */ +export type SequenceOperator = "then" diff --git a/sdk/typescript-schema/expression/expression.ts b/sdk/typescript-schema/expression/expression.ts index 5752742..daf9890 100644 --- a/sdk/typescript-schema/expression/expression.ts +++ b/sdk/typescript-schema/expression/expression.ts @@ -1,5 +1,6 @@ import { Operand } from "../operand/operand"; -import { BinaryOperator, LogicalOperator, UnaryOperator } from "../common/operator"; +import { BinaryOperator, LogicalOperator, SequenceOperator, UnaryOperator } from "../common/operator"; +import { SequenceOperand } from "../operand/sequence-operand"; /** * Represents a complex expression that can evaluate to true, false, or noop. @@ -37,3 +38,5 @@ export type Expression = { operator: BinaryOperator, left: Operand, right: Operand } | // logical expression group { operator: LogicalOperator, expressions: Expression[] } + | // sequence expression (A THEN B) + { operator: SequenceOperator, sequence: SequenceOperand[] } diff --git a/sdk/typescript-schema/index.ts b/sdk/typescript-schema/index.ts index dd6e5d2..498d738 100644 --- a/sdk/typescript-schema/index.ts +++ b/sdk/typescript-schema/index.ts @@ -15,9 +15,11 @@ export * from './expression/path-expression'; export * from './operand/operand'; export * from './operand/location-operand'; export * from './operand/date-operand'; +export * from './operand/sequence-operand'; // Export common types export * from './common/location'; +export * from './common/model-path'; export * from './common/operator'; export * from './common/version'; diff --git a/sdk/typescript-schema/operand/date-operand.ts b/sdk/typescript-schema/operand/date-operand.ts index f07f27f..27bf03c 100644 --- a/sdk/typescript-schema/operand/date-operand.ts +++ b/sdk/typescript-schema/operand/date-operand.ts @@ -38,7 +38,18 @@ export type AbsoluteDate = }; /** - * Represents a date/time relative to the current time. + * References a specific field on a named alias (e.g., a step in an event sequence). + * Examples: + * 1. Reference event1's timestamp: + * { alias: "event1", path: "timestamp" } + */ +export type AliasPath = { + alias: string, + path: string +}; + +/** + * Represents a date/time relative to the current time, or optionally relative to a named alias field. * Examples: * 1. 7 days ago: * { relative: { offset: -7, unit: "day" } } @@ -48,13 +59,17 @@ export type AbsoluteDate = * * 3. End of previous quarter: * { relative: { offset: -1, unit: "quarter", boundary: "end" } } + * + * 4. Within 7 days of event1's timestamp (for event sequencing): + * { relative: { offset: 7, unit: "day", relative_to: { alias: "event1", path: "timestamp" } } } */ export type RelativeDate = { "relative": { offset: number, unit: DateUnit, - boundary?: "start" | "end" + boundary?: "start" | "end", + relative_to?: AliasPath } }; diff --git a/sdk/typescript-schema/operand/sequence-operand.ts b/sdk/typescript-schema/operand/sequence-operand.ts new file mode 100644 index 0000000..89a6a26 --- /dev/null +++ b/sdk/typescript-schema/operand/sequence-operand.ts @@ -0,0 +1,20 @@ +import { ModelPath } from "../common/model-path"; +import { Expression } from "../expression/expression"; + +/** + * Represents a single step in an event sequence. + * The alias uniquely identifies this step so other parts of the definition (e.g., relative_to) + * can reference it. + * Examples: + * 1. Step A with a timestamp operand and event name filter: + * { + * "alias": "event1", + * "operand": { "model": "events", "path": "timestamp" }, + * "condition": { "operator": "equal", "left": { "model": "events", "path": "name" }, "right": "purchase" } + * } + */ +export type SequenceOperand = { + alias: string, + operand: ModelPath, + condition?: Expression +}; diff --git a/sdk/typescript-schema/schema/audience-schema.json b/sdk/typescript-schema/schema/audience-schema.json index 26f0763..f53e15d 100644 --- a/sdk/typescript-schema/schema/audience-schema.json +++ b/sdk/typescript-schema/schema/audience-schema.json @@ -26,6 +26,23 @@ ], "type": "string" }, + "AliasPath": { + "additionalProperties": false, + "description": "References a specific field on a named alias (e.g., a step in an event sequence). Examples: 1. Reference event1's timestamp: { alias: \"event1\", path: \"timestamp\" }", + "properties": { + "alias": { + "type": "string" + }, + "path": { + "type": "string" + } + }, + "required": [ + "alias", + "path" + ], + "type": "object" + }, "ArithmeticOperator": { "description": "Represents mathematical operators for numeric calculations. Examples:\n- \"plus\": { value1: 5, value2: 3 } // result: 8\n- \"multiply\": { value1: 4, value2: 2 } // result: 8\n- \"mod\": { value1: 10, value2: 3 } // result: 1", "enum": [ @@ -309,6 +326,26 @@ ], "type": "object", "title": "LogicalExpression" + }, + { + "additionalProperties": false, + "properties": { + "operator": { + "$ref": "#/definitions/SequenceOperator" + }, + "sequence": { + "items": { + "$ref": "#/definitions/SequenceOperand" + }, + "type": "array" + } + }, + "required": [ + "operator", + "sequence" + ], + "type": "object", + "title": "SequenceExpression" } ], "description": "Represents a complex expression that can evaluate to true, false, or noop. Examples: 1. Join expression (combining expressions from different models): { \"model\": \"user\", \"expression\": { \"operator\": \"equals\", \"left\": { \"path\": \"age\" }, \"right\": 18 } }\n\n2. Logical expression (AND): { \"operator\": \"and\", \"expressions\": [ { \"operator\": \"equals\", \"left\": { \"path\": \"country\" }, \"right\": \"US\" }, { \"operator\": \"greater_than\", \"left\": { \"path\": \"age\" }, \"right\": 18 } ] }\n\n3. Location expression: { \"operator\": \"within\", \"left\": { \"location\": { \"latitude\": 37.7749, \"longitude\": -122.4194, \"distance\": { \"value\": 10, \"unit\": \"miles\" } } }, \"right\": { \"model\": \"user\", \"path\": \"location\" } }" @@ -562,7 +599,7 @@ }, "RelativeDate": { "additionalProperties": false, - "description": "Represents a date/time relative to the current time. Examples: 1. 7 days ago: { relative: { offset: -7, unit: \"day\" } }\n\n2. Start of current month: { relative: { offset: 0, unit: \"month\", boundary: \"start\" } }\n\n3. End of previous quarter: { relative: { offset: -1, unit: \"quarter\", boundary: \"end\" } }", + "description": "Represents a date/time relative to the current time, or optionally relative to a named alias field. Examples: 1. 7 days ago: { relative: { offset: -7, unit: \"day\" } }\n\n2. Start of current month: { relative: { offset: 0, unit: \"month\", boundary: \"start\" } }\n\n3. End of previous quarter: { relative: { offset: -1, unit: \"quarter\", boundary: \"end\" } }\n\n4. Within 7 days of event1's timestamp (for event sequencing): { relative: { offset: 7, unit: \"day\", relative_to: { alias: \"event1\", path: \"timestamp\" } } }", "properties": { "relative": { "additionalProperties": false, @@ -577,6 +614,9 @@ "offset": { "type": "number" }, + "relative_to": { + "$ref": "#/definitions/AliasPath" + }, "unit": { "$ref": "#/definitions/DateUnit" } @@ -593,6 +633,31 @@ ], "type": "object" }, + "SequenceOperand": { + "additionalProperties": false, + "description": "Represents a single step in an event sequence. The alias uniquely identifies this step so other parts of the definition (e.g., relative_to) can reference it. Examples: 1. Step A with a timestamp operand and event name filter: { \"alias\": \"event1\", \"operand\": { \"model\": \"events\", \"path\": \"timestamp\" }, \"condition\": { \"operator\": \"equal\", \"left\": { \"model\": \"events\", \"path\": \"name\" }, \"right\": \"purchase\" } }", + "properties": { + "alias": { + "type": "string" + }, + "condition": { + "$ref": "#/definitions/Expression" + }, + "operand": { + "$ref": "#/definitions/ModelPath" + } + }, + "required": [ + "alias", + "operand" + ], + "type": "object" + }, + "SequenceOperator": { + "const": "then", + "description": "Represents operators for expressing ordered event sequences. Examples:\n- \"then\": user performed Event A, then Event B { operator: \"then\", sequence: [{ alias: \"a\", operand: {...} }, { alias: \"b\", operand: {...} }] }", + "type": "string" + }, "UnaryOperator": { "description": "Represents unary operators that operate on a single value. Examples:\n- \"not\": Negates a boolean expression\n- \"exist\": Checks if a value exists", "enum": [ diff --git a/sdk/typescript-schema/scripts/add_titles_to_schema.sh b/sdk/typescript-schema/scripts/add_titles_to_schema.sh index 563cfea..9d0f3b5 100755 --- a/sdk/typescript-schema/scripts/add_titles_to_schema.sh +++ b/sdk/typescript-schema/scripts/add_titles_to_schema.sh @@ -22,6 +22,7 @@ $.definitions.DateOperand.anyOf[1]|RelativeDateOperand $.definitions.Expression.anyOf[0]|UnaryExpression $.definitions.Expression.anyOf[1]|BinaryExpression $.definitions.Expression.anyOf[2]|LogicalExpression +$.definitions.Expression.anyOf[3]|SequenceExpression $.definitions.PathExpression.anyOf[0]|BooleanPathExpression $.definitions.PathExpression.anyOf[1]|NumberPathExpression $.definitions.PathExpression.anyOf[2]|StringPathExpression diff --git a/sdk/typescript-schema/tsconfig.json b/sdk/typescript-schema/tsconfig.json index 65dc70b..152cdbc 100644 --- a/sdk/typescript-schema/tsconfig.json +++ b/sdk/typescript-schema/tsconfig.json @@ -22,7 +22,8 @@ "outDir": "dist", "declaration": true, "declarationDir": "dist", - "declarationMap": false + "declarationMap": false, + "emitDeclarationOnly": true }, "include": [ "./**/*"