{"version":3,"sources":["../src/projection.ts","../src/multiStreamProjection.ts","../src/schemaHelpers.ts","../src/eventDbHelpers.ts","../src/utils.ts","../src/index.ts"],"sourcesContent":["import { EventClient } from \"./eventDbHelpers\";\nimport { GenericEventBase, GenericEventInput } from \"./schemaHelpers\";\nimport {\n  ObjectWithOnlyStringOrNumberValues,\n  ObjectWithOnlyStringOrNumberValuesOrArrayValues,\n  EventFromType,\n} from \"./utils\";\n\nconst isUnsavedEvent = <E extends GenericEventBase<any>>(\n  event: E | GenericEventInput<E>\n): event is GenericEventInput<E> => {\n  return (event as GenericEventInput<E>).id === undefined;\n};\n\nexport class ProjectionBase<\n  EventType extends string,\n  Event extends GenericEventBase<EventType>,\n  Client extends EventClient,\n  V extends Record<string, unknown>,\n  ET extends EventType = EventType,\n  E extends EventFromType<ET, Event> = EventFromType<ET, Event>,\n  O extends ObjectWithOnlyStringOrNumberValuesOrArrayValues<\n    E[\"data\"]\n  > = ObjectWithOnlyStringOrNumberValues<E[\"data\"]>,\n  K extends keyof O = keyof O,\n  P extends Partial<Pick<O, K>> = Partial<Pick<O, K>>\n> {\n  /** The types of events required to reconstruct this projection */\n  protected get eventTypes(): ET[] {\n    throw new Error(\"eventTypes must be implemented\");\n  }\n  /** The type of this projection, used to look up the projection in the database */\n  protected get projectionType(): string {\n    throw new Error(\"projectionType must be implemented\");\n  }\n\n  protected _events?: Promise<(E | GenericEventInput<E>)[]>;\n  protected _stagedEvents: (E | GenericEventInput<E>)[] = [];\n  private _savedProjection?: Promise<\n    { data: V; latestEventId: string } | undefined\n  >;\n  private _eventIdentifiers?: Promise<P> | P;\n\n  constructor(\n    protected eventsClient: Client,\n    private loadExistingProjection = true\n  ) {}\n\n  protected get savedProjection() {\n    this._savedProjection ||= this.loadExistingProjection\n      ? this.eventsClient.getProjection({\n          type: this.projectionType,\n          id: this.id,\n        })\n      : Promise.resolve(undefined);\n    return this._savedProjection;\n  }\n\n  private eventIdentifiers() {\n    this._eventIdentifiers ||= this.getEventIdentifiers();\n    return this._eventIdentifiers;\n  }\n\n  private async getEventsAfterIdentifiers() {\n    const data = (await this.eventIdentifiers()) as unknown as Partial<\n      ObjectWithOnlyStringOrNumberValues<E[\"data\"]>\n    >;\n    const projection = await this.savedProjection;\n    return this.eventsClient.getEventStream(this.eventTypes, {\n      data,\n      after: projection?.latestEventId,\n    }) as Promise<(E | GenericEventInput<E>)[]>;\n  }\n\n  private get events() {\n    this._events ||= this.getEventsAfterIdentifiers();\n    return this._events!;\n  }\n\n  protected async projectionEvents() {\n    return (await this.events)\n      .concat(this._stagedEvents)\n      .sort((a, b) => ((a.id ?? \"\") < (b.id ?? \"\") ? -1 : 1));\n  }\n\n  /** Stage events without saving them to the database */\n  public apply(events: GenericEventInput<E>[]) {\n    this._stagedEvents.push(...events);\n    return this;\n  }\n\n  /** Replace internal events array without affecting database */\n  public fromHistory(events: E[]) {\n    this._events = Promise.resolve(events);\n    return this;\n  }\n\n  /** Clear cached events and projection to force fresh data on next access */\n  public refresh(): this {\n    this._events = undefined;\n    this._savedProjection = undefined;\n    this._eventIdentifiers = undefined;\n    this._stagedEvents = [];\n    return this;\n  }\n\n  /** Reduce events with a custom reducer function */\n  protected async reduceEvents<T>(\n    reducer: (acc: T, event: E | GenericEventInput<E>) => T,\n    initialValue: T\n  ): Promise<T> {\n    return (await this.projectionEvents()).reduce(reducer, initialValue);\n  }\n\n  /** Check if there are events to save */\n  public async isDirty(): Promise<boolean> {\n    const events = await this.projectionEvents();\n    return events?.length > 0;\n  }\n\n  /** Save the projection only if it has events to save, returns true if saved */\n  public async saveIfDirty(overwrite = false): Promise<boolean> {\n    if (await this.isDirty()) {\n      await this.saveProjection(overwrite);\n      return true;\n    }\n    return false;\n  }\n\n  /** Save the projection to the database */\n  public async saveProjection(overwrite = false) {\n    const unsavedEvents = this._stagedEvents.filter(isUnsavedEvent);\n    if (unsavedEvents.length > 0) {\n      throw new Error(\"Cannot save projection with unpersisted events\");\n    }\n\n    const events = await this.projectionEvents();\n    if (!events?.length && !overwrite) {\n      throw new Error(\"No events to save\");\n    }\n\n    const latestEventId = events.at(-1)?.id;\n    if (latestEventId === undefined) {\n      throw new Error(\"Latest event ID is undefined\");\n    }\n    const result = await this.eventsClient.saveProjection({\n      type: this.projectionType,\n      id: this.id,\n      data: await this.asJson(),\n      latestEventId,\n      forceUpdate: overwrite,\n    });\n\n    // After successful save, clear events since they're now part of the saved projection\n    this._events = Promise.resolve([]);\n    this._stagedEvents = [];\n    return result;\n  }\n\n  /** Get a value from the saved projection or return the fallback */\n  protected async fromProjectionOrDefault<T>(\n    key: keyof V,\n    fallback: T\n  ): Promise<T> {\n    const projection = await this.savedProjection;\n    if (projection === undefined) return fallback;\n\n    return projection.data[key] as T;\n  }\n\n  public get id(): string {\n    throw new Error(\"id must be implemented\");\n  }\n\n  protected getEventIdentifiers(): Promise<P> | P {\n    throw new Error(\"getEventIdentifiers must be implemented\");\n  }\n\n  public async asJson(): Promise<V> {\n    throw new Error(\"asJson must be implemented\");\n  }\n}\n","import { EventClient } from \"./eventDbHelpers\";\nimport { GenericEventBase, GenericEventInput } from \"./schemaHelpers\";\nimport {\n  EventFromType,\n  StreamOptionsForEvents,\n} from \"./utils\";\n\nconst isUnsavedEvent = <E extends GenericEventBase<any>>(\n  event: E | GenericEventInput<E>\n): event is GenericEventInput<E> => {\n  return (event as GenericEventInput<E>).id === undefined;\n};\n\nexport class MultiStreamProjectionBase<\n  EventType extends string,\n  Event extends GenericEventBase<EventType>,\n  Client extends EventClient,\n  V extends Record<string, unknown>,\n  ET extends EventType = EventType,\n  E extends EventFromType<ET, Event> = EventFromType<ET, Event>,\n> {\n  /** The type of this projection, used to look up the projection in the database */\n  protected get projectionType(): string {\n      throw new Error(\"projectionType must be implemented\"); \n  }\n\n  protected _events?: Promise<(E | GenericEventInput<E>)[]>;\n  protected _stagedEvents: (E | GenericEventInput<E>)[] = [];\n  private _savedProjection?: Promise<{ data: V; latestEventId: string } | undefined>;\n\n  constructor(\n    protected eventsClient: Client,\n    private loadExistingProjection = true\n  ) {}\n\n  protected get savedProjection() {\n    this._savedProjection ||= this.loadExistingProjection\n      ? this.eventsClient.getProjection({\n          type: this.projectionType,\n          id: this.id,\n        })\n      : Promise.resolve(undefined);\n    return this._savedProjection;\n  }\n\n  private async getEventsAfterIdentifiers() {\n    const projection = await this.savedProjection;\n    const streams = await this.getStreamOptions();\n    streams.forEach(stream => {\n      if (projection?.latestEventId) {\n        stream.options = { ...stream.options, after: projection.latestEventId };\n      }\n    });\n    return this.eventsClient.getEventStreams(streams) as Promise<(E | GenericEventInput<E>)[]>;\n  }\n\n  private get events() {\n    this._events ||= this.getEventsAfterIdentifiers();\n    return this._events!;\n  }\n\n  protected async projectionEvents() {\n    return (await this.events)\n      .concat(this._stagedEvents)\n      .sort((a, b) => (a.id ?? \"\") < (b.id ?? \"\") ? -1 : 1);\n  }\n\n  /** Stage events without saving them to the database */\n  public apply(events: GenericEventInput<E>[]) {\n    this._stagedEvents.push(...events);\n    return this;\n  }\n\n  /** Replace internal events array without affecting database */\n  public fromHistory(events: E[]) {\n    this._events = Promise.resolve(events);\n    return this;\n  }\n\n  /** Clear cached events and projection to force fresh data on next access */\n  public refresh(): this {\n    this._events = undefined;\n    this._savedProjection = undefined;\n    this._stagedEvents = [];\n    return this;\n  }\n\n  /** Reduce events with a custom reducer function */\n  protected async reduceEvents<T>(\n    reducer: (acc: T, event: E | GenericEventInput<E>) => T,\n    initialValue: T\n  ): Promise<T> {\n    return (await this.projectionEvents()).reduce(reducer, initialValue);\n  }\n\n  /** Check if there are events to save */\n  public async isDirty(): Promise<boolean> {\n    const events = await this.projectionEvents();\n    return events?.length > 0;\n  }\n\n  /** Save the projection only if it has events to save, returns true if saved */\n  public async saveIfDirty(overwrite = false): Promise<boolean> {\n    if (await this.isDirty()) {\n      await this.saveProjection(overwrite);\n      return true;\n    }\n    return false;\n  }\n\n  /** Save the projection to the database */\n  public async saveProjection(overwrite = false) {\n    const unsavedEvents = this._stagedEvents.filter(isUnsavedEvent);\n    if (unsavedEvents.length > 0) {\n      throw new Error(\"Cannot save projection with unpersisted events\");\n    }\n\n    const events = await this.projectionEvents();\n    if (!events?.length && !overwrite) {\n      throw new Error(\"No events to save\");\n    }\n\n    const latestEventId = events.at(-1)?.id;\n    if (latestEventId === undefined) {\n      throw new Error(\"Latest event ID is undefined\");\n    }\n    const result = await this.eventsClient.saveProjection({\n      type: this.projectionType,\n      id: this.id,\n      data: await this.asJson(),\n      latestEventId,\n      forceUpdate: overwrite,\n    });\n\n    // After successful save, clear events since they're now part of the saved projection\n    this._events = Promise.resolve([]);\n    this._stagedEvents = [];\n    return result;\n  }\n\n  /** Get a value from the saved projection or return the fallback */\n  protected async fromProjectionOrDefault<T>(key: keyof V, fallback: T): Promise<T> {\n    const projection = await this.savedProjection;\n    if (projection === undefined) return fallback;\n\n    return projection.data[key] as T;\n  }\n\n  public get id(): string {\n      throw new Error(\"id must be implemented\");\n  }\n\n  protected getStreamOptions(): Promise<StreamOptionsForEvents<E, ET>[]> | StreamOptionsForEvents<E, ET>[] {\n      throw new Error(\"getStreamOptions must be implemented\");\n  }\n\n  public async asJson(): Promise<V> {\n      throw new Error(\"asJson must be implemented\");\n  }\n} ","import { SQL, sql } from 'drizzle-orm';\nimport { \n  text,\n  jsonb,\n  timestamp,\n  primaryKey,\n  index,\n  pgTable,\n  ExtraConfigColumn,\n  PgInsertValue,\n} from 'drizzle-orm/pg-core';\nimport { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\nimport { ulid } from 'ulidx';\n\nexport type InputOf<T> = Omit<T, 'id' | 'createdAt' | 'updatedAt'> & { id?: string, createdAt?: Date, updatedAt?: Date };\n\nexport type EventsTableConfig = {\n  schema?: string;\n  name?: string;\n  dataIndexes?: string[];\n  additionalIndexes?: {\n    name: string;\n    columns: [Partial<ExtraConfigColumn> | SQL, ...Partial<ExtraConfigColumn | SQL>[]];\n  }[];\n};\n\nexport type ProjectionsTableConfig = {\n  schema?: string;\n  name?: string;\n  dataIndexes?: string[];\n  additionalIndexes?: {\n    name: string;\n    columns: [Partial<ExtraConfigColumn> | SQL, ...Partial<ExtraConfigColumn | SQL>[]];\n  }[];\n};\n\nexport function createEventsTable(config: EventsTableConfig = {}) {\n  const {\n    schema,\n    name = 'events',\n    dataIndexes = [],\n    additionalIndexes = []\n  } = config;\n\n  return pgTable(\n    schema ? `${schema}.${name}` : name,\n    {\n      id: text('id').primaryKey().$defaultFn(() => ulid()),\n      type: text('type').notNull(),\n      data: jsonb('data').notNull(),\n      createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(),\n      updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow(),\n    },\n    (table) => [\n      index(`${name}_type_idx`).on(table.type),\n      // Create indexes for each data field\n      ...dataIndexes.map(field => \n        index(`${name}_data_${field}_idx`).on(\n          sql`(${table.data}->>'${sql.raw(field)}')`\n        )\n      ),\n      // Add any additional custom indexes\n      ...additionalIndexes.map(additionalIndex => \n        index(additionalIndex.name).on(...additionalIndex.columns)\n      )\n    ]\n  );\n}\n\nexport function createProjectionsTable(config: ProjectionsTableConfig = {}) {\n  const {\n    schema,\n    name = 'projections',\n    dataIndexes = [],\n    additionalIndexes = []\n  } = config;\n\n  return pgTable(\n    schema ? `${schema}.${name}` : name,\n    {\n      type: text('type').notNull(),\n      id: text('id').notNull(),\n      data: jsonb('data').notNull(),\n      latestEventId: text('latest_event_id').notNull(),\n      createdAt: timestamp(\"created_at\", { withTimezone: true }).defaultNow(),\n      updatedAt: timestamp(\"updated_at\", { withTimezone: true }).defaultNow(),\n    },\n    (table) => [\n      primaryKey({ columns: [table.type, table.id] }),\n      index(`${name}_type_idx`).on(table.type),\n      // Create indexes for each data field\n      ...dataIndexes.map(field => \n        index(`${name}_data_${field}_idx`).on(\n          sql`(${table.data}->>'${sql.raw(field)}')`\n        )\n      ),\n      // Add any additional custom indexes\n      ...additionalIndexes.map(additionalIndex => \n        index(additionalIndex.name).on(...additionalIndex.columns)\n      )\n    ]\n  );\n}\n\nexport type GenericEventsType = (ReturnType<typeof createEventsTable>)['$inferSelect'];\nexport type GenericProjectionsType = (ReturnType<typeof createProjectionsTable>)['$inferSelect'];\nexport type GenericEventsTable = ReturnType<typeof createEventsTable>;\nexport type GenericProjectionsTable = ReturnType<typeof createProjectionsTable>;\n\nexport type GenericEventBase<T> = GenericEventsType & {\n  type: T;\n};\n\nexport type GenericEventInput<K> = (ReturnType<typeof createEventsTable>)['$inferInsert'] & K;\n\nexport type PgInsertEvent = PgInsertValue<ReturnType<typeof createEventsTable>>;\n\nexport type DbOrTx<T extends PostgresJsDatabase<any>> =\n  | T\n  | Parameters<Parameters<T['transaction']>[0]>[0];\n","import {\n  and,\n  asc,\n  desc,\n  eq,\n  gt,\n  inArray,\n  or,\n  sql,\n  SQL,\n  TablesRelationalConfig,\n} from \"drizzle-orm\";\nimport {\n  PostgresJsDatabase,\n  PostgresJsTransaction,\n} from \"drizzle-orm/postgres-js\";\nimport {\n  DbOrTx,\n  GenericEventBase,\n  GenericEventsTable,\n  GenericProjectionsTable,\n  InputOf,\n} from \"./schemaHelpers\";\nimport {\n  isDefined,\n  ObjectWithOnlyStringOrNumberValuesOrArrayValues,\n} from \"./utils\";\nimport { PgInsertValue, PgUpdateSetSource, PgDialect } from \"drizzle-orm/pg-core\";\nimport { monotonicFactory } from \"ulidx\";\n\n\nexport type EventClient<\n  EventType extends string = any,\n  Events extends GenericEventBase<EventType> = any,\n  J extends Record<string, unknown> = any,\n  K extends TablesRelationalConfig = any,\n  Db extends PostgresJsDatabase<any> = any\n> = {\n  readonly saveEvent: (eventInput: InputOf<Events>, tx?: PostgresJsTransaction<J, K>) => Promise<Events & {\n    type: EventType;\n  }>;\n  readonly saveEvents: <T extends InputOf<Events>>(eventInputs: T[], tx?: DbOrTx<Db>) => Promise<(Events & {\n    type: EventType;\n  })[]>;\n  readonly getLatestEvent: (eventType: EventType, options?: EventQueryOptions<EventType, Events>) => Promise<Events & {\n    type: EventType;\n  }>;\n  readonly getEventStream: <T extends EventType>(eventTypes: T[], options?: EventQueryOptions<T, Events & {\n    type: T;\n  }>) => Promise<(Events & {\n    type: T;\n  })[]>;\n  readonly getEventStreams: <T extends EventType>(streams: { eventTypes: T[], options?: EventQueryOptions<T, Events & { type: T }> }[]) => Promise<(Events & {\n    type: T;\n  })[]>;\n  readonly saveProjection: (params: {\n    type: string;\n    id: string;\n    data: Record<string, unknown>;\n    latestEventId: string;\n    forceUpdate?: boolean;\n  } & PgInsertValue<GenericProjectionsTable> & PgUpdateSetSource<GenericProjectionsTable>) => Promise<{\n    id: string;\n    data: unknown;\n    type: string;\n    latestEventId: string;\n    status: \"created\" | \"updated\" | \"skipped\";\n  }>;\n  readonly forceUpdateProjection: (params: Parameters<EventClient['saveProjection']>[0]) => Promise<{\n    id: string;\n    data: unknown;\n    type: string;\n    latestEventId: string;\n    status: \"created\" | \"updated\" | \"skipped\";\n  }>;\n  readonly conditionalUpdateProjection: (params: Parameters<EventClient['saveProjection']>[0]) => Promise<{\n    id: string;\n    data: unknown;\n    type: string;\n    latestEventId: string;\n    status: \"created\" | \"updated\" | \"skipped\";\n  }>;\n  readonly getProjection: <T>(params: {\n    type: string;\n    id: string;\n  }) => Promise<{\n    data: T;\n    latestEventId: string;\n  } | undefined>;\n  readonly queryProjections: <T extends {asJson: () => Promise<Record<string, unknown>>}>(params: {\n    type: string;\n    data?: Partial<Awaited<ReturnType<T['asJson']>>>;\n  }) => Promise<{\n    data: Awaited<ReturnType<T['asJson']>>;\n    latestEventId: string;\n  }[]>;\n  readonly saveEventWithStreamValidation: (eventInput: InputOf<Events>, latestEventId: string, streams: StreamDefinition<EventType, Events>[]) => Promise<Events & {\n    type: EventType;\n  }>;\n};\n\n/** This is a utility type that helps to get type safety and autocomplete for the data field in the query options. */\ntype EventQueryOptions<\n  T extends string,\n  E extends GenericEventBase<T>,\n  D extends DbOrTx<PostgresJsDatabase<any>> = DbOrTx<PostgresJsDatabase<any>>\n> = {\n  /** The id of the event after which to query. */\n  after?: string;\n  /** The data to filter the events by. If an array is provided, the events will be filtered as if\n   * any one of the values in the array matches. Only string and number values are supported.\n   */\n  data?: Partial<ObjectWithOnlyStringOrNumberValuesOrArrayValues<E[\"data\"]>>;\n  tx?: D;\n};\n\ntype StreamDefinition<T extends string, E extends GenericEventBase<T>> = {\n  types: T[];\n  identifier: Partial<\n    ObjectWithOnlyStringOrNumberValuesOrArrayValues<E[\"data\"]>\n  >;\n};\n\nexport function createEventClient<\n  EventType extends string,\n  Events extends GenericEventBase<EventType>,\n  J extends Record<string, unknown>,\n  K extends TablesRelationalConfig,\n  Db extends PostgresJsDatabase<Record<string, any>>\n>(\n  db: DbOrTx<Db>,\n  events: GenericEventsTable,\n  projections: GenericProjectionsTable,\n  ulidGenerator = monotonicFactory()\n) {\n  return {\n    async saveEvent(\n      eventInput: InputOf<Events>,\n      tx?: PostgresJsTransaction<J, K>\n    ) {\n      const dbOrTx = tx ?? db;\n      const [savedEvent] = await dbOrTx\n        .insert(events)\n        .values(eventInput)\n        .returning();\n      return savedEvent as Events & { type: EventType };\n    },\n\n    async saveEvents<T extends InputOf<Events>>(\n      eventInputs: T[],\n      tx?: DbOrTx<Db>\n    ) {\n      const dbOrTx = tx ?? db;\n      const result = (await dbOrTx\n        .insert(events)\n        .values(eventInputs.map((event) => ({ ...event, id: event.id ?? ulidGenerator() })))\n        .returning()) as (Events & { type: EventType })[];\n      return result;\n    },\n\n    async getLatestEvent(\n      eventType: EventType,\n      options?: EventQueryOptions<EventType, Events>\n    ) {\n      const dbOrTx = options?.tx ?? db;\n      const conditions = [eq(events.type, eventType)];\n\n      if (options?.after) {\n        conditions.push(gt(events.id, options.after));\n      }\n\n      if (options?.data) {\n        const dataConditions = Object.entries(options.data)\n          .map(([key, value]): SQL<unknown> | undefined => {\n            if (value === undefined) {\n              return undefined;\n            }\n            if (Array.isArray(value)) {\n              return value.length > 0\n                ? or(\n                    ...value.map(\n                      (v) => sql`${events.data}->>${key} = ${v.toString()}`\n                    )\n                  )\n                : undefined;\n            }\n            return isDefined(value)\n              ? sql`${events.data}->>${key} = ${value.toString()}`\n              : undefined;\n          })\n          .filter(isDefined);\n\n        const dataSql =\n          dataConditions.length > 0 ? and(...dataConditions) : undefined;\n        if (dataSql) {\n          conditions.push(dataSql);\n        }\n      }\n\n      const [event] = await dbOrTx\n        .select()\n        .from(events)\n        .where(and(...conditions))\n        .orderBy(desc(events.id))\n        .limit(1);\n\n      return event as Events & { type: EventType };\n    },\n\n    async getEventStream<T extends EventType>(\n      eventTypes: T[],\n      options?: EventQueryOptions<T, Events & { type: T }>\n    ): Promise<(Events & { type: T })[]> {\n      const dbOrTx = options?.tx ?? db;\n      const conditions = [inArray(events.type, eventTypes)];\n\n      if (options?.after) {\n        conditions.push(gt(events.id, options.after));\n      }\n\n      if (options?.data) {\n        const dataConditions = Object.entries(options.data)\n          .map(([key, value]): SQL<unknown> | undefined => {\n            if (value === undefined) {\n              return undefined;\n            }\n            if (Array.isArray(value)) {\n              return value.length > 0\n                ? or(\n                    ...value.map(\n                      (v) => sql`${events.data}->>${key} = ${v.toString()}`\n                    )\n                  )\n                : undefined;\n            }\n            return isDefined(value)\n              ? sql`${events.data}->>${key} = ${value.toString()}`\n              : undefined;\n          })\n          .filter(isDefined);\n\n        const dataSql =\n          dataConditions.length > 0 ? and(...dataConditions) : undefined;\n        if (dataSql) {\n          conditions.push(dataSql);\n        }\n      }\n\n      const result = (await dbOrTx\n        .select()\n        .from(events)\n        .where(and(...conditions))\n        .orderBy(asc(events.id))) as (Events & { type: T })[];\n      return result;\n    },\n\n    async getEventStreams<T extends EventType>(\n      streams: { eventTypes: T[], options?: EventQueryOptions<T, Events & { type: T }> }[]\n    ): Promise<(Events & { type: T })[]> {\n      const dbOrTx = streams[0]?.options?.tx ?? db;\n      const conditions: SQL<unknown>[] = [];\n\n      streams.forEach(({ eventTypes, options }) => {\n        const streamConditions: SQL<unknown>[] = [inArray(events.type, eventTypes)];\n\n        if (options?.after) {\n          streamConditions.push(gt(events.id, options.after));\n        }\n\n        if (options?.data) {\n          const dataConditions = Object.entries(options.data)\n            .map(([key, value]): SQL<unknown> | undefined => {\n              if (value === undefined) return undefined;\n              if (Array.isArray(value)) {\n                return value.length > 0\n                  ? or(...value.map((v) => sql`${events.data}->>${key} = ${v.toString()}`))\n                  : undefined;\n              }\n              return isDefined(value)\n                ? sql`${events.data}->>${key} = ${value.toString()}`\n                : undefined;\n            })\n            .filter(isDefined);\n\n          const dataSql = dataConditions.length > 0 ? and(...dataConditions) : undefined;\n          if (dataSql) {\n            streamConditions.push(dataSql);\n          }\n        }\n\n        const streamSql = streamConditions.length > 0 ? and(...streamConditions) : undefined;\n        if (streamSql) {\n          conditions.push(streamSql);\n        }\n      });\n\n      if (conditions.length === 0) {\n        return [];\n      }\n\n      const result = await dbOrTx\n        .select()\n        .from(events)\n        .where(or(...conditions))\n        .orderBy(asc(events.id)) as (Events & { type: T })[];\n\n      return result;\n    },\n\n    /**\n     * Save a projection to the database. If the projection already exists,\n     * it will be updated as long as the incoming latestEventId\n     * is greater than the current latestEventId. If the projection\n     * does not exist, it will be created. A projection will be returned\n     * regardless of whether it was updated or created, but the\n     * `updated` field will be false if the projection already exists and\n     * the incoming latestEventId was not greater than the current\n     * latestEventId.\n     */\n    async saveProjection(\n      params: {\n        type: string;\n        id: string;\n        data: Record<string, unknown>;\n        latestEventId: string;\n        forceUpdate?: boolean;\n      } & PgInsertValue<GenericProjectionsTable> &\n        PgUpdateSetSource<GenericProjectionsTable>\n    ) {\n      return params.forceUpdate\n        ? this.forceUpdateProjection(params)\n        : this.conditionalUpdateProjection(params);\n    },\n\n    async forceUpdateProjection(params: Parameters<EventClient['saveProjection']>[0]) {\n      const [result] = await db\n        .insert(projections)\n        .values(params)\n        .onConflictDoUpdate({\n          target: [projections.type, projections.id],\n          set: {\n            data: sql`${JSON.stringify(params.data)}::jsonb`,\n            latestEventId: params.latestEventId,\n          },\n        })\n        .returning({\n          status: sql<\"created\" | \"updated\" | \"skipped\">`\n            CASE \n              WHEN xmax::text::int = 0 THEN 'created'\n              ELSE 'updated'\n            END`,\n          type: projections.type,\n          id: projections.id,\n          data: projections.data,\n          latestEventId: projections.latestEventId,\n        });\n\n      return result;\n    },\n\n    async conditionalUpdateProjection(params: Parameters<EventClient['saveProjection']>[0]) {\n      const [result] = await db\n        .insert(projections)\n        .values(params)\n        .onConflictDoUpdate({\n          target: [projections.type, projections.id],\n          set: {\n            data: sql`CASE \n              WHEN ${projections.latestEventId} <= ${params.latestEventId} \n              THEN ${JSON.stringify(params.data)}::jsonb \n              ELSE ${projections.data} \n            END`,\n            latestEventId: sql`CASE \n              WHEN ${projections.latestEventId} <= ${params.latestEventId} \n              THEN ${params.latestEventId}\n              ELSE ${projections.latestEventId}\n            END`,\n          },\n        })\n        .returning({\n          status: sql<\"created\" | \"updated\" | \"skipped\">`\n            CASE \n              WHEN xmax::text::int = 0 THEN 'created'\n              WHEN ${projections.latestEventId} <= ${params.latestEventId} THEN 'updated'\n              ELSE 'skipped'\n            END`,\n          type: projections.type,\n          id: projections.id,\n          data: projections.data,\n          latestEventId: projections.latestEventId,\n        });\n\n      return result;\n    },\n\n    async getProjection<T>(params: { type: string; id: string }): Promise<\n      | {\n          data: T;\n          latestEventId: string;\n        }\n      | undefined\n    > {\n      const [projection] = await db\n        .select({\n          data: projections.data,\n          latestEventId: projections.latestEventId,\n        })\n        .from(projections)\n        .where(\n          and(eq(projections.type, params.type), eq(projections.id, params.id))\n        );\n      return projection as { data: T; latestEventId: string } | undefined;\n    },\n\n    async queryProjections<T extends {asJson: () => Promise<Record<string, unknown>>}>(params: {\n      type: string;\n      data?: Partial<Awaited<ReturnType<T['asJson']>>>;\n    }): Promise<{data: Awaited<ReturnType<T['asJson']>>, latestEventId: string}[]> {\n      const conditions = [eq(projections.type, params.type)];\n\n      if (params.data) {\n        const dataConditions = Object.entries(params.data)\n          .map(([key, value]): SQL<unknown> | undefined => {\n            if (value === undefined) {\n              return undefined;\n            }\n            if (Array.isArray(value)) {\n              return value.length > 0\n                ? or(\n                    ...value.map(\n                      (v) => sql`${projections.data}->>${key} = ${v.toString()}`\n                    )\n                  )\n                : undefined;\n            }\n            return isDefined(value)\n              ? sql`${projections.data}->>${key} = ${value.toString()}`\n              : undefined;\n          })\n          .filter(isDefined);\n\n        const dataSql =\n          dataConditions.length > 0 ? and(...dataConditions) : undefined;\n        if (dataSql) {\n          conditions.push(dataSql);\n        }\n      }\n\n      const foundProjections = await db\n        .select({\n          data: projections.data,\n          latestEventId: projections.latestEventId,\n        })\n        .from(projections)\n        .where(and(...conditions));\n      return foundProjections as {data: Awaited<ReturnType<T['asJson']>>, latestEventId: string}[];\n    },\n\n    async saveEventWithStreamValidation(\n      eventInput: InputOf<Events>,\n      latestEventId: string,\n      streams: StreamDefinition<EventType, Events>[]\n    ): Promise<Events & { type: EventType }> {\n      const eventWithId = eventInput.id ? eventInput : { ...eventInput, id: ulidGenerator() };\n\n      // Build each stream check\n      const streamChecks = streams.map((stream, i) => {\n        const check = sql`NOT EXISTS (\n          SELECT 1 FROM ${events}\n          WHERE ${inArray(events.type, stream.types)}\n          AND ${events.id}::text > ${latestEventId}::text\n          AND ${sql.join(\n            Object.entries(stream.identifier).map(\n              ([key, value]) => sql`${events.data}->>${key} = ${value}`\n            ),\n            sql` AND `\n          )}\n        )`;\n\n        return check;\n      });\n\n      const query = sql`\n        WITH new_event AS (\n          INSERT INTO ${events} (id, type, data, created_at, updated_at)\n          VALUES (${eventWithId.id}, ${eventWithId.type}, ${JSON.stringify(eventWithId.data)}::jsonb, DEFAULT, DEFAULT)\n          RETURNING *\n        )\n        SELECT * FROM new_event\n        WHERE ${sql.join(streamChecks, sql` AND `)}\n      `;\n\n      const [savedEvent] = await db.execute<Events>(query);\n\n      if (!savedEvent) {\n        throw new Error(\n          \"Concurrent modification detected - newer events exist in one or more streams\"\n        );\n      }\n      return savedEvent as Events & { type: EventType };\n    },\n  } as const;\n}\n","import { GenericEventsType } from \"./schemaHelpers\";\n\nexport const isDefined = <T>(val: T | null | undefined): val is T =>\n  val !== null && val !== undefined;\n\nexport type EventFromType<T, K extends GenericEventsType> = K & {\n  type: T;\n};\n\nexport type ExtractDataFromEvents<Events, Types> = Events extends { type: Types; data: infer Data }\n  ? ObjectWithOnlyStringOrNumberValues<Data>\n  : never;\n\nexport type UnionToIntersection<U> = \n  (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;\n\nexport type DataForEventTypes<Events, Types> = UnionToIntersection<ExtractDataFromEvents<Events, Types>>;\n\ntype ExtractEventData<Event, Type> = Event extends { type: Type; data: infer Data }\n  ? Data\n  : never;\n\ntype IntersectEventData<Events, Types> = UnionToIntersection<ExtractEventData<Events, Types>>;\n\n\n\n\n\nexport type StreamOptionsForEvents<\n  Events extends { type: Type },\n  Type extends string | number | symbol\n> = {\n  eventTypes: Type[];\n  options?: {\n    data?: Partial<ObjectWithOnlyStringOrNumberValuesOrArrayValues<IntersectEventData<Events, Type>>>;\n    after?: string;\n  };\n};\n\ntype KeysWithNumericValues<T> = {\n  [key in keyof T]: T[key] extends number | undefined ? key : never;\n}[keyof T];\ntype KeysWithStringValues<T> = {\n  [key in keyof T]: T[key] extends string | undefined ? key : never;\n}[keyof T];\ntype ObjectWithOnlyNumericValues<T> = {\n  [key in KeysWithNumericValues<T>]: number;\n};\ntype ObjectWithOnlyStringValues<T> = {\n  [key in KeysWithStringValues<T>]: string;\n};\ntype ObjectWithOnlyNumericArrayValues<T> = {\n  [key in KeysWithNumericValues<T>]: number[];\n};\ntype ObjectWithOnlyStringArrayValues<T> = {\n  [key in KeysWithStringValues<T>]: string[];\n};\n\nexport type ObjectWithOnlyStringOrNumberValues<T> =\n  ObjectWithOnlyNumericValues<T> & ObjectWithOnlyStringValues<T>;\nexport type ObjectWithOnlyStringOrNumberArrayValues<T> =\n  ObjectWithOnlyNumericArrayValues<T> & ObjectWithOnlyStringArrayValues<T>;\nexport type ObjectWithOnlyStringOrNumberValuesOrArrayValues<T> =\n  ObjectWithOnlyStringOrNumberValues<T> |\n    ObjectWithOnlyStringOrNumberArrayValues<T>;\n","import { type EventClient } from \"./eventDbHelpers\";\nimport { type GenericEventBase } from \"./schemaHelpers\";\nimport { ProjectionBase } from \"./projection\";\nimport { MultiStreamProjectionBase } from \"./multiStreamProjection\";\n\nexport {\n  createEventsTable,\n  createProjectionsTable,\n  type GenericEventsType,\n  type GenericProjectionsType,\n  type GenericEventsTable,\n  type GenericProjectionsTable,\n  type GenericEventBase,\n  type GenericEventInput,\n  type PgInsertEvent,\n  type InputOf,\n} from \"./schemaHelpers\";\n\nexport {\n  type EventClient,\n  createEventClient,\n} from \"./eventDbHelpers\";\n\nexport {\n  type ObjectWithOnlyStringOrNumberValues,\n  type ObjectWithOnlyStringOrNumberValuesOrArrayValues,\n  type EventFromType,\n  type StreamOptionsForEvents,\n} from \"./utils\";\n\nexport { ProjectionBase, type ProjectionBase as ProjectionBaseType } from \"./projection\";\nexport { MultiStreamProjectionBase, type MultiStreamProjectionBase as MultiStreamProjectionBaseType } from \"./multiStreamProjection\";\n\nexport const createProjectionBaseClass = <\n  EventType extends string,\n  Event extends GenericEventBase<EventType>,\n  Client extends EventClient<EventType, Event>,\n  V extends Record<string, unknown>\n>() => ProjectionBase<EventType, Event, Client, V>;\n\nexport const createMultiStreamProjectionBaseClass = <\n  EventType extends string,\n  Event extends GenericEventBase<EventType>,\n  Client extends EventClient<EventType, Event>,\n  V extends Record<string, unknown>\n>() => MultiStreamProjectionBase<EventType, Event, Client, V>;\n"],"mappings":"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","names":["isUnsavedEvent","sql","sql"]}