Skip to content

Commit

Permalink
feat(web): improve size model
Browse files Browse the repository at this point in the history
- Add #auto.
- Use unsolved config info.
  • Loading branch information
joseivanlopez committed Nov 13, 2024
1 parent b1a4402 commit dc0796e
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 87 deletions.
151 changes: 82 additions & 69 deletions web/src/storage/model/config/size.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,99 +23,112 @@
import * as model from "~/storage/model/config/size";

describe("#generate", () => {
it("returns the size in bytes from the size section", () => {
it("returns the expected size object from a size section", () => {
expect(
model.generate({
size: 1024,
}),
).toEqual({ min: 1024, max: 1024 });
model.generate(
{},
{
size: "1 KiB",
},
),
).toEqual({ auto: true, min: 1024, max: 1024 });

expect(
model.generate({
size: "1 KiB",
}),
).toEqual({ min: 1024, max: 1024 });
model.generate(
{},
{
size: "1KiB",
},
),
).toEqual({ auto: true, min: 1024, max: 1024 });

expect(
model.generate({
size: "1KiB",
}),
).toEqual({ min: 1024, max: 1024 });
model.generate(
{},
{
size: "1kb",
},
),
).toEqual({ auto: true, min: 1000, max: 1000 });

expect(
model.generate({
size: "1kb",
}),
).toEqual({ min: 1000, max: 1000 });
model.generate(
{},
{
size: "1k",
},
),
).toEqual({ auto: true, min: 1000, max: 1000 });

expect(
model.generate({
size: "1k",
}),
).toEqual({ min: 1000, max: 1000 });
model.generate(
{},
{
size: "665.284 TiB",
},
),
).toEqual({ auto: true, min: 731487493773328, max: 731487493773328 });

expect(
model.generate({
size: "665.284 TiB",
}),
).toEqual({ min: 731487493773328, max: 731487493773328 });
expect(model.generate({ size: 1024 }, { size: { min: 1024, max: 1024 } })).toEqual({
auto: false,
min: 1024,
max: 1024,
});

expect(
model.generate({
size: [1024],
}),
).toEqual({ min: 1024 });
expect(model.generate({}, { size: { min: 1024, max: 1024 } })).toEqual({
auto: true,
min: 1024,
max: 1024,
});

expect(
model.generate({
size: [1024, 2048],
}),
).toEqual({ min: 1024, max: 2048 });
expect(model.generate({}, { size: [1024] })).toEqual({ auto: true, min: 1024 });

expect(
model.generate({
size: ["1 kib", "2 KIB"],
}),
).toEqual({ min: 1024, max: 2048 });
expect(model.generate({}, { size: [1024, 2048] })).toEqual({
auto: true,
min: 1024,
max: 2048,
});

expect(
model.generate({
size: {
min: 1024,
model.generate(
{},
{
size: ["1 kib", "2 KIB"],
},
}),
).toEqual({ min: 1024 });
),
).toEqual({ auto: true, min: 1024, max: 2048 });

expect(
model.generate({
size: {
min: 1024,
max: 2048,
},
}),
).toEqual({ min: 1024, max: 2048 });
expect(model.generate({}, { size: { min: 1024 } })).toEqual({ auto: true, min: 1024 });

expect(model.generate({}, { size: { min: 1024, max: 2048 } })).toEqual({
auto: true,
min: 1024,
max: 2048,
});

expect(
model.generate({
size: {
min: "1 kib",
max: "2 KiB",
model.generate(
{},
{
size: {
min: "1 kib",
max: "2 KiB",
},
},
}),
).toEqual({ min: 1024, max: 2048 });
),
).toEqual({ auto: true, min: 1024, max: 2048 });
});

// This scenario should not happen because the solved config does not return "custom" value.
it("returns undefined for 'custom' value", () => {
expect(
model.generate({
size: {
min: "custom",
max: 2048,
},
}),
).toEqual({ min: undefined, max: 2048 });
expect(model.generate({}, { size: { min: "custom", max: 2048 } })).toEqual({
auto: true,
min: undefined,
max: 2048,
});
});

it("returns undefined if there is no size section", () => {
expect(model.generate({})).toBeUndefined;
expect(model.generate({}, {})).toBeUndefined;
});
});
64 changes: 46 additions & 18 deletions web/src/storage/model/config/size.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,28 @@ import * as checks from "~/api/storage/types/checks";
import xbytes from "xbytes";

export type Size = {
auto: boolean;
min?: number;
max?: number;
};

export interface WithSize {
interface WithSize {
size?: config.Size;
}

type AnyConfig = object | undefined;

class SizeGenerator<TypeWithSize extends WithSize> {
private config: TypeWithSize;
private config: AnyConfig;
private solvedConfig: TypeWithSize;

constructor(config: TypeWithSize) {
constructor(config: AnyConfig, solvedConfig: TypeWithSize) {
this.config = config;
this.solvedConfig = solvedConfig;
}

// TODO: detect auto size by checking the unsolved config.
generate(): Size | undefined {
const size = this.config.size;
const size = this.solvedConfig.size;

if (!size) return;
if (checks.isSizeValue(size)) return this.fromSizeValue(size);
Expand All @@ -52,23 +56,50 @@ class SizeGenerator<TypeWithSize extends WithSize> {

private fromSizeValue(value: config.SizeValue): Size {
const bytes = this.bytes(value);
return { min: bytes, max: bytes };

return {
auto: this.generateAuto(),
min: bytes,
max: bytes,
};
}

private fromSizeTuple(sizeTuple: config.SizeTuple): Size {
const size: Size = { min: this.bytes(sizeTuple[0]) };
if (sizeTuple.length === 2) size.max = this.bytes(sizeTuple[1]);
const size: Size = {
auto: this.generateAuto(),
min: this.bytes(sizeTuple[0]),
};

if (sizeTuple.length === 2) {
size.max = this.bytes(sizeTuple[1]);
}

return size;
}

private fromSizeRange(sizeRange: config.SizeRange): Size {
const size: Size = { min: this.bytes(sizeRange.min) };
if (sizeRange.max) size.max = this.bytes(sizeRange.max);
const size: Size = {
auto: this.generateAuto(),
min: this.bytes(sizeRange.min),
};

if (sizeRange.max) {
size.max = this.bytes(sizeRange.max);
}

return size;
}

private generateAuto(): boolean {
return this.config === undefined || !("size" in this.config);
}

private bytes(value: config.SizeValueWithCurrent): number | undefined {
if (checks.isSizeCurrent(value)) return;
if (checks.isSizeString(value)) return this.parseSizeString(value);
if (checks.isSizeBytes(value)) return value;
}

private parseSizeString(value: string): number | undefined {
// xbytes.parseSize will not work with a string like '10k', the unit must end with 'b' or 'B'
let adapted = value.trim();
Expand All @@ -77,14 +108,11 @@ class SizeGenerator<TypeWithSize extends WithSize> {
const parsed = xbytes.parseSize(adapted, { bits: false }) || parseInt(adapted);
if (parsed) return Math.trunc(parsed);
}

private bytes(value: config.SizeValueWithCurrent): number | undefined {
if (checks.isSizeCurrent(value)) return;
if (checks.isSizeString(value)) return this.parseSizeString(value);
if (checks.isSizeBytes(value)) return value;
}
}

export function generate<TypeWithSize extends WithSize>(config: TypeWithSize): Size | undefined {
return new SizeGenerator<TypeWithSize>(config).generate();
export function generate<TypeWithSize extends WithSize>(
config: AnyConfig,
solvedConfig: TypeWithSize,
): Size | undefined {
return new SizeGenerator<TypeWithSize>(config, solvedConfig).generate();
}

0 comments on commit dc0796e

Please sign in to comment.