All files / src/ram RamSequence.ts

81.25% Statements 39/48
40% Branches 4/10
100% Functions 6/6
80.85% Lines 38/47

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 1038x 8x 8x     8x   8x       39x 39x       43x 43x 43x 24x   19x 19x       19x 19x                           199x             32x   32x 32x       32x   32x 32x               32x     32x 32x   12x     12x     32x       28x 28x       4x 4x 4x       4x 4x 116x   4x   4x      
import { Sequence as Seq } from "./model/RamSequence";
import { InternalError, NotFoundError } from "@decaf-ts/db-decorators";
import { Sequence } from "../persistence";
import { SequenceOptions } from "../interfaces";
import { RamAdapter } from "./RamAdapter";
import { Repo, Repository } from "../repository";
 
export class RamSequence extends Sequence {
  protected repo: Repo<Seq>;
 
  constructor(options: SequenceOptions, adapter: RamAdapter) {
    super(options);
    this.repo = Repository.forModel(Seq, adapter.flavour);
  }
 
  async current(): Promise<string | number | bigint> {
    const { name, startWith } = this.options;
    try {
      const sequence: Seq = await this.repo.read(name as string);
      return this.parse(sequence.current as string | number);
    } catch (e: any) {
      if (e instanceof NotFoundError) {
        Iif (typeof startWith === "undefined")
          throw new InternalError(
            "Starting value is not defined for a non existing sequence"
          );
        try {
          return this.parse(startWith);
        } catch (e: any) {
          throw new InternalError(
            `Failed to parse initial value for sequence ${startWith}: ${e}`
          );
        }
      }
      throw new InternalError(
        `Failed to retrieve current value for sequence ${name}: ${e}`
      );
    }
  }
 
  private parse(value: string | number | bigint): string | number | bigint {
    return Sequence.parseValue(this.options.type, value);
  }
 
  private async increment(
    current: string | number | bigint,
    count?: number
  ): Promise<string | number | bigint> {
    const { type, incrementBy, name } = this.options;
    let next: string | number | bigint;
    const toIncrementBy = count || incrementBy;
    Iif (toIncrementBy % incrementBy !== 0)
      throw new InternalError(
        `Value to increment does not consider the incrementBy setting: ${incrementBy}`
      );
    switch (type) {
      case "Number":
        next = (this.parse(current) as number) + toIncrementBy;
        break;
      case "BigInt":
        next = (this.parse(current) as bigint) + BigInt(toIncrementBy);
        break;
      default:
        throw new InternalError("Should never happen");
    }
    let seq: Seq;
    const repo = this.repo.override({
      ignoredValidationProperties: ["updatedOn"],
    });
    try {
      seq = await repo.update(new Seq({ id: name, current: next }));
    } catch (e: any) {
      Iif (!(e instanceof NotFoundError)) {
        throw e;
      }
      seq = await repo.create(new Seq({ id: name, current: next }));
    }
 
    return seq.current as string | number | bigint;
  }
 
  async next(): Promise<number | string | bigint> {
    const current = await this.current();
    return this.increment(current);
  }
 
  async range(count: number): Promise<(number | string | bigint)[]> {
    const current = (await this.current()) as number;
    const incrementBy = this.parse(this.options.incrementBy) as number;
    const next: string | number | bigint = await this.increment(
      current,
      (this.parse(count) as number) * incrementBy
    );
    const range: (number | string | bigint)[] = [];
    for (let i: number = 1; i <= count; i++) {
      range.push(current + incrementBy * (this.parse(i) as number));
    }
    Iif (range[range.length - 1] !== next)
      throw new InternalError("Miscalculation of range");
    return range;
  }
}