{"version":3,"sources":["../../../src/schema/types/decimal.ts"],"sourcesContent":["import Decimal from '../../core/decimal/decimal'\r\nimport Definitions from '../../core/definitions'\r\nimport ErrorCodes from '../../errors/io-error-codes'\r\nimport Node from '../../parser/nodes/nodes'\r\nimport Schema from '../../schema/schema'\r\nimport TypeDef from '../../schema/typedef'\r\nimport doCommonTypeCheck from './common-type'\r\nimport MemberDef from './memberdef'\r\nimport { NUMBER_TYPES, throwError, getIntegerDigits } from './common-number'\r\n\r\nconst decimalSchema = new Schema(\r\n  \"decimal\",\r\n  { type:       { type: \"string\", optional: false, null: false, choices: NUMBER_TYPES } },\r\n  { default:    { type: \"decimal\", optional: true,  null: false  } },\r\n  { choices:    { type: \"array\",  optional: true,  null: false, of: { type: \"decimal\" } } },\r\n  { precision:  { type: \"number\", optional: true, null: false } },\r\n  { scale:      { type: \"number\", optional: true, null: false } },\r\n  { min:        { type: \"decimal\", optional: true,  null: false } },\r\n  { max:        { type: \"decimal\", optional: true,  null: false } },\r\n  { multipleOf: { type: \"decimal\", optional: true,  null: false } },\r\n  { optional:   { type: \"bool\",   optional: true } },\r\n  { null:       { type: \"bool\",   optional: true } },\r\n)\r\n\r\n/**\r\n * Decimal type definition with support for 4 validation modes:\r\n * 1. Natural comparison (no precision/scale)\r\n * 2. Scale-only validation (exact decimal places)\r\n * 3. Precision-only validation (max significant digits)\r\n * 4. Strict validation (exact DECIMAL(precision, scale))\r\n *\r\n * @internal\r\n */\r\nclass DecimalDef implements TypeDef {\r\n  private _type: string = 'decimal'\r\n\r\n  get type(): string { return this._type }\r\n  get schema(): Schema { return decimalSchema }\r\n\r\n  parse(node: Node, memberDef: MemberDef, defs?: Definitions): Decimal {\r\n    const valueNode = defs?.getV(node) || node\r\n    let { value, changed } = doCommonTypeCheck(memberDef, valueNode, node, defs)\r\n    if (changed) return value\r\n\r\n    // Type check: reject regular numbers, only accept Decimal instances\r\n    if (typeof value === 'number') {\r\n      throwError(\r\n        ErrorCodes.invalidType,\r\n        memberDef.path!,\r\n        `Expected decimal value (with 'm' suffix), got number`,\r\n        node\r\n      )\r\n    }\r\n\r\n    value = this.validate(memberDef, value, node)\r\n\r\n    return value\r\n  }\r\n\r\n  load(value: any, memberDef: MemberDef, defs?: Definitions): Decimal {\r\n    const { value: checkedValue, changed } = doCommonTypeCheck(memberDef, value)\r\n    if (changed) return checkedValue\r\n\r\n    return this.validate(memberDef, value)\r\n  }\r\n\r\n  stringify(value: any, memberDef: MemberDef): string {\r\n    // Validate before stringifying\r\n    const valD = this.validate(memberDef, value)\r\n\r\n    return valD.toString() + 'm'\r\n  }\r\n\r\n  /**\r\n   * Validates decimal value according to the specified mode\r\n   */\r\n  validate(memberDef: MemberDef, value: any, node?: Node): Decimal {\r\n    let { min, max, precision: requiredPrecision, scale: requiredScale } = memberDef\r\n\r\n    const valD: Decimal = Decimal.ensureDecimal(value)\r\n\r\n    // Mode check: Determine validation mode based on precision and scale\r\n    const hasRequiredPrecision = requiredPrecision !== null && requiredPrecision !== undefined\r\n    const hasRequiredScale = requiredScale !== null && requiredScale !== undefined\r\n\r\n    // Validate scale if specified (modes 2 and 4)\r\n    if (hasRequiredScale) {\r\n      const actualScale = valD.getScale()\r\n      if (actualScale !== requiredScale) {\r\n        throwError(\r\n          ErrorCodes.invalidScale,\r\n          memberDef.path!,\r\n          `Value has scale ${actualScale}, expected ${requiredScale}`,\r\n          node\r\n        )\r\n      }\r\n    }\r\n\r\n    // Validate precision if specified (modes 3 and 4)\r\n    if (hasRequiredPrecision) {\r\n      const actualPrecision = valD.getPrecision()\r\n\r\n      if (hasRequiredScale) {\r\n        // Mode 4: Strict validation (both precision and scale)\r\n        // Check if value fits within DECIMAL(precision, scale)\r\n        const intDigits = getIntegerDigits(valD)\r\n        const maxIntDigits = requiredPrecision - requiredScale\r\n\r\n        if (intDigits > maxIntDigits) {\r\n          throwError(\r\n            ErrorCodes.invalidPrecision,\r\n            memberDef.path!,\r\n            `Integer part has ${intDigits} digits, DECIMAL(${requiredPrecision},${requiredScale}) allows ${maxIntDigits}`,\r\n            node\r\n          )\r\n        }\r\n      } else {\r\n        // Mode 3: Precision-only validation\r\n        if (actualPrecision > requiredPrecision) {\r\n          throwError(\r\n            ErrorCodes.invalidPrecision,\r\n            memberDef.path!,\r\n            `Value has precision ${actualPrecision}, max allowed is ${requiredPrecision}`,\r\n            node\r\n          )\r\n        }\r\n      }\r\n    }\r\n\r\n    // Validate min constraint - normalize to same scale for comparison\r\n    if (min !== null && min !== undefined) {\r\n      const minD: Decimal = Decimal.ensureDecimal(min)\r\n\r\n      // Use the larger scale for both\r\n      const targetScale = Math.max(valD.getScale(), minD.getScale())\r\n\r\n      // Calculate precision needed: max integer digits + target scale\r\n      const valIntDigits = getIntegerDigits(valD)\r\n      const minIntDigits = getIntegerDigits(minD)\r\n      const targetPrecision = Math.max(valIntDigits, minIntDigits) + targetScale\r\n\r\n      const normalizedVal = valD.convert(targetPrecision, targetScale)\r\n      const normalizedMin = minD.convert(targetPrecision, targetScale)\r\n\r\n      if (normalizedVal.compareTo(normalizedMin) < 0) {\r\n        throwError(ErrorCodes.invalidRange, memberDef.path!, value, node)\r\n      }\r\n    }\r\n\r\n    // Validate max constraint - normalize to same scale for comparison\r\n    if (max !== null && max !== undefined) {\r\n      const maxD: Decimal = Decimal.ensureDecimal(max)\r\n\r\n      // Use the larger scale for both\r\n      const targetScale = Math.max(valD.getScale(), maxD.getScale())\r\n\r\n      // Calculate precision needed: max integer digits + target scale\r\n      const valIntDigits = getIntegerDigits(valD)\r\n      const maxIntDigits = getIntegerDigits(maxD)\r\n      const targetPrecision = Math.max(valIntDigits, maxIntDigits) + targetScale\r\n\r\n      const normalizedVal = valD.convert(targetPrecision, targetScale)\r\n      const normalizedMax = maxD.convert(targetPrecision, targetScale)\r\n\r\n      if (normalizedVal.compareTo(normalizedMax) > 0) {\r\n        throwError(ErrorCodes.invalidRange, memberDef.path!, value, node)\r\n      }\r\n    }\r\n\r\n    // Validate multipleOf constraint\r\n    if (memberDef.multipleOf !== undefined && memberDef.multipleOf !== null) {\r\n      const multipleOfD: Decimal = Decimal.ensureDecimal(memberDef.multipleOf)\r\n\r\n      // For multipleOf check, we need to ensure both values have the same scale\r\n      const targetScale = Math.max(valD.getScale(), multipleOfD.getScale())\r\n      const valIntDigits = getIntegerDigits(valD)\r\n      const multipleIntDigits = getIntegerDigits(multipleOfD)\r\n      const targetPrecision = Math.max(valIntDigits, multipleIntDigits) + targetScale\r\n\r\n      const normalizedVal = valD.convert(targetPrecision, targetScale)\r\n      const normalizedMultiple = multipleOfD.convert(targetPrecision, targetScale)\r\n\r\n      // Check if value is a multiple using modulo operation\r\n      const remainder = normalizedVal.mod(normalizedMultiple)\r\n      const zero = new Decimal(0, targetPrecision, targetScale)\r\n      if (remainder.compareTo(zero) !== 0) {\r\n        throwError(\r\n          ErrorCodes.invalidValue,\r\n          memberDef.path!,\r\n          `Value must be a multiple of ${multipleOfD}`,\r\n          node\r\n        )\r\n      }\r\n    }\r\n\r\n    // Return the value as-is (don't convert unless necessary)\r\n    return valD\r\n  }\r\n}\r\n\r\nexport default DecimalDef\r\n"],"mappings":"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","names":["Schema","doCommonTypeCheck","ErrorCodes","Decimal"]}