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 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | 25x 25x 25x 25x 25x 25x 25x 25x 183x 185x 1171x 1171x 1171x 1171x 1x 1170x 1170x 9x 1169x 1169x 19x 5x 5x 1166x 185x 2x 1x 2x 2x 1x 183x 183x 183x 181x 1160x 181x 181x 156x 156x 156x 988x 156x 156x 988x 156x 183x 25x 183x 183x 183x 181x 183x | import { AutoClose, AutoCloseType, inlineAutoClose } from "@jonloucks/contracts-ts/api/AutoClose";
import { AutoOpen } from "@jonloucks/contracts-ts/api/AutoOpen";
import { BindStrategy, resolveBindStrategy } from "@jonloucks/contracts-ts/api/BindStrategy";
import { Contract } from "@jonloucks/contracts-ts/api/Contract";
import { ContractException } from "@jonloucks/contracts-ts/api/ContractException";
import { Contracts } from "@jonloucks/contracts-ts/api/Contracts";
import { Promisor, PromisorType, typeToPromisor } from "@jonloucks/contracts-ts/api/Promisor";
import { Config, Repository } from "@jonloucks/contracts-ts/api/Repository";
import { RequiredType, OptionalType } from "@jonloucks/contracts-ts/api/Types";
import { contractCheck, contractsCheck } from "@jonloucks/contracts-ts/auxiliary/Checks";
import { Idempotent } from "@jonloucks/contracts-ts/auxiliary/Idempotent";
import { create as createIdempotent } from "./Idempotent.impl";
import { StorageImpl } from "./Storage.impl";
/**
* Factory method to create Repository instance.
*
* @param contracts the Contracts instance to be used by the Repository
* @returns the Repository implementation
*/
export function create(config?: Config): RequiredType<Repository> {
return RepositoryImpl.internalCreate(config);
}
// ---- Implementation details below ----
/**
* Implementation for Repository
*/
class RepositoryImpl implements Repository, AutoOpen {
/**
* AutoOpen.autoOpen override.
*/
autoOpen(): AutoClose {
return this.open();
}
/**
* Open.open
*/
open(): AutoClose {
return this.idempotent.open();
}
/**
* Repository.store override.
*/
store<T>(contract: Contract<T>, promisor: PromisorType<T>, bindStrategy?: BindStrategy | undefined | null): AutoClose {
const validContract: Contract<T> = contractCheck(contract);
const validPromisor: Promisor<T> = typeToPromisor(promisor);
const validBindStrategy: BindStrategy = resolveBindStrategy(bindStrategy);
if (this.#storedContracts.has(validContract) && this.idempotent.isOpen()) {
throw new ContractException("The contract " + validContract + " is already stored.");
}
const storage: StorageImpl<T | null> = new StorageImpl<T | null>(this.contracts, validContract, validPromisor, validBindStrategy);
if (this.idempotent.isOpen()) {
storage.bind();
}
this.#storedContracts.set(validContract, storage);
return inlineAutoClose(() => {
if (this.#storedContracts.get(validContract) === storage) {
this.#storedContracts.delete(validContract);
storage.close();
}
});
}
/**
* Repository.keep override.
*/
keep<T>(contract: Contract<T>, promisor: PromisorType<T>, bindStrategy?: OptionalType<BindStrategy>): void {
this.store(contract, promisor, resolveBindStrategy(bindStrategy));
}
/**
* Repository.check override.
*/
check(): void {
this.#requiredContracts.forEach((contract) => {
if (!this.contracts.isBound(contract)) {
throw new ContractException("The contract " + contract + " is required.");
}
});
}
/**
* Repository.require override.
*/
require<T>(contract: Contract<T>): void {
const validContract: Contract<T> = contractCheck(contract);
this.#requiredContracts.add(validContract);
}
/**
* Object.toString override.
*/
toString(): string {
return `Repository(id=${this.id}, size=${this.#storedContracts.size})`;
}
private constructor(config?: Config) {
const validConfig: Config = config ?? {};
this.contracts = contractsCheck(validConfig.contracts);
Iif (validConfig.requiredContracts) {
validConfig.requiredContracts.forEach((contract) => this.require(contract));
}
}
private firstOpen(): AutoCloseType {
for (const storage of this.#storedContracts.values()) {
storage.bind();
}
this.check();
return () => {
this.reverseCloseStorage();
}
}
private reverseCloseStorage(): void {
const storageStack: StorageImpl<unknown>[] = [];
for (const storage of this.#storedContracts.values()) {
storageStack.push(storage);
}
try {
while (storageStack.length > 0) {
storageStack.pop()!.close();
}
} finally {
this.#storedContracts.clear();
}
}
static internalCreate(config?: Config): RequiredType<Repository> {
return new RepositoryImpl(config);
}
private static ID_GENERATOR: number = 1;
private readonly id: number = RepositoryImpl.ID_GENERATOR++;
readonly #storedContracts = new Map<Contract<unknown>, StorageImpl<unknown>>();
private readonly contracts: Contracts;
private readonly idempotent: Idempotent = createIdempotent({
open: () => this.firstOpen()
});
readonly #requiredContracts: Set<Contract<unknown>> = new Set<Contract<unknown>>();
}
|