from marshmallow import Schema, ValidationError, fields, validate, validates_schema from playlist.connectors.snowflake import SnowflakeQuery from playlist.queries.constants import ( PLACEMENT_POSITION_EVENTS_TABLE, PUBLIC_PLACEMENT_TABLE, ) from playlist.queries.schema import ISRC class PlacementTimeSeriesQuerySchema(Schema): isrc = ISRC() isrcs = fields.List(ISRC(), validate=validate.Length(min=1, max=1000)) store_id = fields.Str(required=True) store_playlist_id = fields.Str(required=True) storefront = fields.Str() start_date = fields.Date() end_date = fields.Date() @validates_schema def validate_isrc_or_isrcs(self, data, **kwargs): """Ensure exactly one of 'isrc' or 'isrcs' is provided""" has_isrc = "isrc" in data and data["isrc"] is not None has_isrcs = "isrcs" in data and data["isrcs"] if not has_isrc and not has_isrcs: raise ValidationError("Either 'isrc' or 'isrcs' is required") if has_isrc and has_isrcs: raise ValidationError( "Provide either 'isrc' (single) or 'isrcs' (list), not both" ) class PlacementPositionTimeSeriesQuery(SnowflakeQuery): """/playlist//placement//positions endpoint Supports both single ISRC and batch queries: - Single: {"isrc": "QZK6M1903348", ...} - Batch: {"isrcs": ["QZK6M1903348", "USHR12108509"], ...} """ query_schema = PlacementTimeSeriesQuerySchema filename = "placement_position_time_series.sql" table_params = { "placement_position_events_table_name": PLACEMENT_POSITION_EVENTS_TABLE, "public_placement_table": PUBLIC_PLACEMENT_TABLE, }