0.1.3Updated 6 months ago
import type { EntityMetaConfig } from "@infinity-beyond/classes/entity_meta.ts";

// #region Ledger Options

export interface LedgerOptions<PEMC extends EntityMetaConfig = EntityMetaConfig> {
  /**
   * Should this ledger allow users to go into negative balances?
   * 
   * If this is false, `.AddEntry()` will *fail* when trying to subtract below a zero balance.
   * 
   * **Default**: `false`
   * */
  allow_negative_balances?: boolean

  /**
   * What is the maximum length a key value could be?
   * 
   * A *key* is used to identify ledger data based on a user. Usually the `msisdn`.
   * 
   * This is used when creating the ledger tables to improve performance.
   * 
   * **Default**: `11`
   */
  key_max_length?: number

  /**
   * Additional single-value records that can be stored alongside this ledger
   */
  meta_fields?: PEMC
  
  /**
   * Expiration options for a ledger instance
   */
  expiration?: LedgerExpiration

  /**
   * Used to process with all provided `key` values to ensure they follow the correct syntax.
   */
  key_validator?: KeyValidator

  /**
   * Used to process with all provided `key` values to ensure they follow the correct syntax.
   */
  key_formatter?: KeyFormatter
}

// #region Expiration

type expiration_measurement_singular = 'minute' | 'hour' | 'day' | 'week' | 'month'
type expiration_measurement_plural = `${expiration_measurement_singular}s`
export type LedgerExpirationMeasurement = expiration_measurement_singular | expiration_measurement_plural

export interface LedgerExpiration {
  /**
   * Whether entries expire.
   * 
   * Default: `false`
   */
  entries_expire?: boolean

  /**
   * How long entries have before they expire.
   * 
   * Only used if **entries_expire** is `true`.
   * 
   * Default: `[1, 'week']`
   */
  period?: [number, LedgerExpirationMeasurement]

  /**
   * After calculating an expiration timestamp, it will be rounded up to the end of this period.
   * 
   * Only used if **entries_expire** is `true`.
   * 
   * Default: `none`
   */
  round_up_to?: 'none' | expiration_measurement_singular

  /**
   * Instead of using **period** and **round_up_to**, pass a function 
   * 
   * @param entry The ledger entry being added. [Immutable]
   * @returns Date
   */
  custom_calculator?: () => Date

}

interface LedgerExpirationOverride_False {
  override_expiration_date?: false
}

interface LedgerExpirationOverride_True {
  override_expiration_date: true
  expiration_date: Date
}

export type LedgerExpirationOverride = LedgerExpirationOverride_False | LedgerExpirationOverride_True

interface KeyValidationSuccess {
  valid: true
  reason: null
}

interface KeyValidationFailure {
  valid: false
  reason: string
}

export type KeyValidation = KeyValidationSuccess | KeyValidationFailure
export type KeyValidationResponse = boolean | KeyValidationSuccess | KeyValidationFailure
export type KeyValidator = (key: string) => KeyValidationResponse

export type KeyFormatter = (key: string) => string | null