import { type Maybe, type TimezoneString } from '@dereekb/util'; import { type DateDayTimezoneHintFilter, type DateItemOccuringFilter, type DateItemQueryStartsEndsFilter, type DateItemRangeFilter } from './query.filter'; /** * Paired time and day filters produced by a {@link DaysAndTimeFiltersFunction}. * * Separates the UTC-based time filter from the timezone-adjusted day filter so * that consumers can apply each independently or together. */ export interface DaysAndTimeFilter { /** * The time filter is the primary filter. */ timeFilter: F; /** * The days filter is calculated when a timezone is provided, and filters on the days that match the range. */ daysFilter: Maybe; } /** * Intermediate representation of a date query before it is compiled into * database-specific filters via a {@link DateQueryBuilder}. * * Captures upper/lower bounds for both the starts-at and ends-at fields, * plus the implied recurrence range used internally for range-based filtering. */ export interface RawDateQuery extends DateDayTimezoneHintFilter { timezone?: Maybe; startsLte?: Maybe; startsGte?: Maybe; endsLte?: Maybe; endsGte?: Maybe; /** * Implied Range to filter on. * * We want to include all recurring items that start before the end, AND end after the start. * * rStart or rEnd may not be defined if no start or end are defined. */ rStart?: Maybe; rEnd?: Maybe; } /** * Strategy interface that converts {@link RawDateQuery} bounds into * database-specific range objects (`R`) and field filter objects (`F`). * * Implementations are provided for different query backends (e.g. MongoDB-like). */ export interface DateQueryBuilder { /** * Makes the "range" filter, which denotes the range to filter on. It is only used for building the "field" filter later. */ makeRangeFilter: MakeRangeFilterFunction; /** * Actual filter used to return values. */ makeFieldFilter: MakeFieldFilterFunction; } export type MakeRangeFilterFunction = (gte: Maybe, lte: Maybe) => Maybe; /** * A single field that manages start/end will start and end at the same instant (end = start), so we merge the gte/lte values. * * The "start" should be the startsAt start range first, and then the endsAt start range if provided. * The "ends" should be equal to the endsAt end range first, and then the startsAt end range if provided. */ export type MergeStartsAtEndsAtFilterFunction = (startsAt: Maybe, endsAt: Maybe) => R; /** * Input to {@link MakeFieldFilterFunction} containing the optional range * objects for starts-at and ends-at fields. */ export interface MakeFieldFilterInput { startsAt?: Maybe; endsAt?: Maybe; } export type MakeFieldFilterFunction = (input: MakeFieldFilterInput) => F; /** * Builds a {@link RawDateQuery} that matches items occurring at a single point in time. * * Sets `startsLte` and `endsGte` to the same instant so only items whose * active window contains the target date are included. * * @param find - Filter specifying the target date and optional timezone hint. * @returns A raw date query representing the "occurring at" constraint. * * @example * ```ts * const query = makeDateQueryForOccuringFilter({ * occuringAt: new Date('2026-06-15T12:00:00Z'), * timezone: 'America/Chicago' * }); * ``` * * @__NO_SIDE_EFFECTS__ */ export declare function makeDateQueryForOccuringFilter(find: DateItemOccuringFilter & DateDayTimezoneHintFilter): RawDateQuery; /** * Builds a {@link RawDateQuery} from a {@link DateItemRangeFilter}, deriving * the concrete start/end dates from the provided {@link DateRangeParams}. * * When `rangeContained` is true, only items fully enclosed within the range * are matched. Otherwise items merely overlapping the range are included. * * @param find - Range filter with optional timezone and containment flag. * @returns A raw date query bounded by the resolved range. * * @example * ```ts * const query = makeDateQueryForDateItemRangeFilter({ * range: { type: DateRangeType.WEEK, date: new Date() }, * timezone: 'America/New_York', * rangeContained: false * }); * ``` * * @__NO_SIDE_EFFECTS__ */ export declare function makeDateQueryForDateItemRangeFilter(find: DateItemRangeFilter): RawDateQuery; /** * Builds a {@link RawDateQuery} from explicit starts/ends boundary constraints. * * Allows callers to independently control the before/after bounds for both * the start and end fields of date items. * * @param find - Filter with optional starts/ends boundaries and timezone hint. * @returns A raw date query with the corresponding GTE/LTE bounds populated. * * @example * ```ts * const query = makeDateQueryForDateStartsEndsFilter({ * starts: { after: new Date('2026-01-01'), before: new Date('2026-12-31') }, * ends: { after: new Date('2026-06-01') }, * timezone: 'UTC' * }); * ``` * * @__NO_SIDE_EFFECTS__ */ export declare function makeDateQueryForDateStartsEndsFilter(find: DateItemQueryStartsEndsFilter & DateDayTimezoneHintFilter): RawDateQuery; export type DaysAndTimeFiltersFunction = (dateQueryInstance: RawDateQuery) => DaysAndTimeFilter; /** * Creates a function that splits a {@link RawDateQuery} into separate time * and day filters using the supplied {@link DateQueryBuilder}. * * The day filter is only produced when a timezone is present, allowing * timezone-aware day-level filtering alongside the UTC time filter. * * @param builder - Strategy for converting date bounds into backend-specific filters. * @returns Factory that splits each raw query into time-of-day and day-level filters. * * @example * ```ts * const filtersFunction = makeDaysAndTimeFiltersFunction(mongoBuilder); * const rawQuery = makeDateQueryForOccuringFilter({ occuringAt: new Date() }); * const { timeFilter, daysFilter } = filtersFunction(rawQuery); * ``` * * @__NO_SIDE_EFFECTS__ */ export declare function makeDaysAndTimeFiltersFunction(builder: DateQueryBuilder): DaysAndTimeFiltersFunction;