Skip to content

Commit

Permalink
feat(core): normalize collection types
Browse files Browse the repository at this point in the history
BREAKING CHANGES: `Collection`'s `add()` and `remove()` methods now returns the new length.
  • Loading branch information
capt-nemo429 committed Dec 10, 2022
1 parent f0f55ca commit 821ebcc
Show file tree
Hide file tree
Showing 10 changed files with 149 additions and 153 deletions.
5 changes: 4 additions & 1 deletion packages/core/src/builder/outputBuilder.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,10 @@ describe("Token handling", () => {

it("Should add tokens from context ejector", () => {
builder.eject(({ tokens }) =>
tokens.add({ tokenId: tokenA, amount: 50n }).add({ tokenId: tokenB, amount: 10n })
tokens.add([
{ tokenId: tokenA, amount: 50n },
{ tokenId: tokenB, amount: 10n }
])
);

expect(builder.tokens).toHaveLength(2);
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/builder/selector/boxSelector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@ export class BoxSelector<T extends Box<bigint>> {
}

if (isDefined(remaining.tokens) && selected.some((input) => !isEmpty(input.assets))) {
remaining.tokens.forEach((tokenTarget) => {
for (const tokenTarget of remaining.tokens) {
if (tokenTarget.amount) {
tokenTarget.amount -= utxoSum(selected, tokenTarget.tokenId);
}
});
}
}
} else {
selected = [];
Expand Down
12 changes: 8 additions & 4 deletions packages/core/src/models/collections/collection.spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { Collection } from "./collection";

class MockCollection extends Collection<number> {
class MockCollection extends Collection<number, number> {
constructor() {
super();
}

public add(numb: number[]) {
numb.forEach((n) => this._items.push(n));
protected override _addOne(numb: number) {
this._items.push(numb);

return this;
return this.length;
}

public remove(item: number): number {
throw Error("Not implemented for " + item);
}
}

Expand Down
28 changes: 24 additions & 4 deletions packages/core/src/models/collections/collection.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export abstract class Collection<T> implements Iterable<T> {
protected readonly _items: T[];
export abstract class Collection<InternalType, ExternalType> implements Iterable<InternalType> {
protected readonly _items: InternalType[];

constructor() {
this._items = [];
Expand All @@ -9,7 +9,7 @@ export abstract class Collection<T> implements Iterable<T> {
return index < 0 || index >= this._items.length;
}

[Symbol.iterator](): Iterator<T> {
[Symbol.iterator](): Iterator<InternalType> {
let counter = 0;

return {
Expand All @@ -30,7 +30,27 @@ export abstract class Collection<T> implements Iterable<T> {
return this.length === 0;
}

public toArray(): T[] {
public add(items: ExternalType[] | ExternalType): number {
return this._addOneOrMore(items);
}

abstract remove(item: unknown): number;

protected abstract _addOne(item: ExternalType, options?: unknown): number;

protected _addOneOrMore(items: ExternalType[] | ExternalType, options?: unknown): number {
if (Array.isArray(items)) {
for (const item of items) {
this._addOne(item, options);
}
} else {
this._addOne(items, options);
}

return this.length;
}

public toArray(): InternalType[] {
return [...this._items];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe("inputs collection", () => {
expect(first(collection.toArray()).boxId).toBe(box.boxId);
});

it("Should add a multiple items", () => {
it("Should append items", () => {
const collection = new InputsCollection();
collection.add(regularBoxesMock);

Expand Down
31 changes: 8 additions & 23 deletions packages/core/src/models/collections/inputsCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { DuplicateInputError, NotFoundError } from "../../errors";
import { ErgoUnsignedInput } from "../ergoUnsignedInput";
import { Collection } from "./collection";

export class InputsCollection extends Collection<ErgoUnsignedInput> {
export class InputsCollection extends Collection<ErgoUnsignedInput, Box<Amount>> {
constructor();
constructor(box: Box<Amount>);
constructor(boxes: Box<Amount>[]);
Expand All @@ -16,34 +16,19 @@ export class InputsCollection extends Collection<ErgoUnsignedInput> {
}
}

public add(box: Box<Amount>): InputsCollection;
public add(boxes: Box<Amount>[]): InputsCollection;
public add(boxes: Box<Amount> | Box<Amount>[]): InputsCollection;
public add(boxOrBoxes: Box<Amount> | Box<Amount>[]): InputsCollection {
if (!Array.isArray(boxOrBoxes)) {
this._add(boxOrBoxes);

return this;
}

for (const box of boxOrBoxes) {
this._add(box);
}

return this;
}

private _add(box: Box<Amount>): void {
protected override _addOne(box: Box<Amount>): number {
if (this._items.some((item) => item.boxId === box.boxId)) {
throw new DuplicateInputError(box.boxId);
}

this._items.push(box instanceof ErgoUnsignedInput ? box : new ErgoUnsignedInput(box));

return this._items.length;
}

public remove(boxId: BoxId): InputsCollection;
public remove(index: number): InputsCollection;
public remove(boxIdOrIndex: BoxId | number): InputsCollection {
public remove(boxId: BoxId): number;
public remove(index: number): number;
public remove(boxIdOrIndex: BoxId | number): number {
let index = -1;
if (typeof boxIdOrIndex === "number") {
if (this._isIndexOutOfBounds(boxIdOrIndex)) {
Expand All @@ -65,6 +50,6 @@ export class InputsCollection extends Collection<ErgoUnsignedInput> {
this._items.splice(index, 1);
}

return this;
return this.length;
}
}
61 changes: 34 additions & 27 deletions packages/core/src/models/collections/outputsCollection.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ describe("outputs collection", () => {
new OutputBuilder(SAFE_MIN_BOX_VALUE, address, height),
new OutputBuilder(SAFE_MIN_BOX_VALUE, address, height)
]);

expect(collection).toHaveLength(2);
});

Expand All @@ -30,14 +31,17 @@ describe("outputs collection", () => {
expect(first(collection.toArray())).toBe(output);
});

it("Should add a multiple items", () => {
it("Should append items", () => {
const collection = new OutputsCollection();

const outputs = [
new OutputBuilder(SAFE_MIN_BOX_VALUE, address, height),
new OutputBuilder(SAFE_MIN_BOX_VALUE * 2n, address, height)
];
collection.add(outputs);

const newLen = collection.add(outputs);

expect(newLen).toBe(2);
expect(collection).toHaveLength(2);
expect(collection.toArray()).toEqual(outputs);
});
Expand Down Expand Up @@ -123,18 +127,20 @@ describe("Target building", () => {
const tokenD = "5614535ba46927145c3d30fed8f14b08bd48a143b24136809f9e47afc40643c4";

it("Should sum amounts", () => {
const collection = new OutputsCollection()
.add(
new OutputBuilder(SAFE_MIN_BOX_VALUE, address, height).addTokens({
tokenId: tokenA,
amount: 12348n
})
)
.add(
new OutputBuilder(SAFE_MIN_BOX_VALUE, address, height)
.addTokens({ tokenId: tokenA, amount: "11" })
.addTokens({ tokenId: tokenB, amount: 50n })
);
const collection = new OutputsCollection();

collection.add(
new OutputBuilder(SAFE_MIN_BOX_VALUE, address, height).addTokens({
tokenId: tokenA,
amount: 12348n
})
);

collection.add(
new OutputBuilder(SAFE_MIN_BOX_VALUE, address, height)
.addTokens({ tokenId: tokenA, amount: "11" })
.addTokens({ tokenId: tokenB, amount: 50n })
);

expect(collection.sum()).toEqual({
nanoErgs: SAFE_MIN_BOX_VALUE * 2n,
Expand All @@ -146,7 +152,8 @@ describe("Target building", () => {
});

it("Should ignore minting tokens", () => {
const collection = new OutputsCollection().add(
const collection = new OutputsCollection();
collection.add(
new OutputBuilder(SAFE_MIN_BOX_VALUE, address, height)
.addTokens({ tokenId: tokenA, amount: 12348n })
.mintToken({ name: "testToken", amount: 10n })
Expand All @@ -168,18 +175,18 @@ describe("Target building", () => {
]
};

const collection = new OutputsCollection()
.add(
new OutputBuilder(SAFE_MIN_BOX_VALUE, address, height).addTokens({
tokenId: tokenA,
amount: 12348n
})
)
.add(
new OutputBuilder(SAFE_MIN_BOX_VALUE, address, height)
.addTokens({ tokenId: tokenA, amount: "11" })
.addTokens({ tokenId: tokenB, amount: 50n })
);
const collection = new OutputsCollection();
collection.add(
new OutputBuilder(SAFE_MIN_BOX_VALUE, address, height).addTokens({
tokenId: tokenA,
amount: 12348n
})
);
collection.add(
new OutputBuilder(SAFE_MIN_BOX_VALUE, address, height)
.addTokens({ tokenId: tokenA, amount: "11" })
.addTokens({ tokenId: tokenB, amount: 50n })
);

expect(collection.sum(basis)).toEqual({
nanoErgs: SAFE_MIN_BOX_VALUE * 2n + basis.nanoErgs,
Expand Down
33 changes: 9 additions & 24 deletions packages/core/src/models/collections/outputsCollection.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,27 @@
import { _0n, BoxAmounts, isUndefined, some } from "@fleet-sdk/common";
import { _0n, BoxAmounts, isDefined, isUndefined, some } from "@fleet-sdk/common";
import { OutputBuilder } from "../../builder/outputBuilder";
import { SelectionTarget } from "../../builder/selector/boxSelector";
import { NotFoundError } from "../../errors";
import { Collection } from "./collection";

export class OutputsCollection extends Collection<OutputBuilder> {
export class OutputsCollection extends Collection<OutputBuilder, OutputBuilder> {
constructor(outputs?: OutputBuilder | OutputBuilder[]) {
super();

if (outputs) {
if (isDefined(outputs)) {
this.add(outputs);
}
}

private _add(outputBuilder: OutputBuilder) {
protected override _addOne(outputBuilder: OutputBuilder): number {
this._items.push(outputBuilder);
}

public add(output: OutputBuilder): OutputsCollection;
public add(outputs: OutputBuilder[]): OutputsCollection;
public add(outputs: OutputBuilder | OutputBuilder[]): OutputsCollection;
public add(outputs: OutputBuilder | OutputBuilder[]): OutputsCollection {
if (!Array.isArray(outputs)) {
this._add(outputs);

return this;
}

for (const output of outputs) {
this._add(output);
}

return this;
return this._items.length;
}

public remove(output: OutputBuilder): OutputsCollection;
public remove(index: number): OutputsCollection;
public remove(outputs: OutputBuilder | number): OutputsCollection {
public remove(output: OutputBuilder): number;
public remove(index: number): number;
public remove(outputs: OutputBuilder | number): number {
let index = -1;
if (typeof outputs === "number") {
if (this._isIndexOutOfBounds(outputs)) {
Expand All @@ -58,7 +43,7 @@ export class OutputsCollection extends Collection<OutputBuilder> {
this._items.splice(index, 1);
}

return this;
return this.length;
}

public clone(): OutputsCollection {
Expand Down
Loading

0 comments on commit 821ebcc

Please sign in to comment.