Skip to content

Commit

Permalink
fix: fix unique method types (#457)
Browse files Browse the repository at this point in the history
  • Loading branch information
ST-DDT authored Feb 10, 2022
1 parent 2a4f835 commit 14df7d3
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 28 deletions.
13 changes: 7 additions & 6 deletions src/unique.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as uniqueExec from './vendor/unique';
import type { RecordKey } from './vendor/unique';

/**
* Module to generate unique entries.
Expand Down Expand Up @@ -38,20 +39,20 @@ export class Unique {
* @param opts.compare The function used to determine whether a value was already returned.
*
* @example
* faker.unique(faker.name.firstName())
* faker.unique(faker.name.firstName)
*/
unique<Method extends (args: Args) => string, Args extends any[]>(
unique<Method extends (...parameters) => RecordKey>(
method: Method,
args: Args,
args?: Parameters<Method>,
opts?: {
startTime?: number;
maxTime?: number;
maxRetries?: number;
currentIterations?: number;
exclude?: string | string[];
compare?: (obj: Record<string, string>, key: string) => 0 | -1;
exclude?: RecordKey | RecordKey[];
compare?: (obj: Record<RecordKey, RecordKey>, key: RecordKey) => 0 | -1;
}
): string {
): ReturnType<Method> {
opts = opts || {};
opts.startTime = new Date().getTime();
if (typeof opts.maxTime !== 'number') {
Expand Down
27 changes: 15 additions & 12 deletions src/vendor/unique.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
export type RecordKey = string | number | symbol;

// global results store
// currently uniqueness is global to entire faker instance
// this means that faker should currently *never* return duplicate values across all API methods when using `Faker.unique`
// it's possible in the future that some users may want to scope found per function call instead of faker instance
const found: Record<string, string> = {};
const found: Record<RecordKey, RecordKey> = {};

// global exclude list of results
// defaults to nothing excluded
const exclude: string[] = [];
const exclude: RecordKey[] = [];

// current iteration or retries of unique.exec ( current loop depth )
const currentIterations = 0;

// uniqueness compare function
// default behavior is to check value as key against object hash
function defaultCompare<T, Key extends keyof T>(obj: T, key: Key): 0 | -1 {
function defaultCompare(
obj: Record<RecordKey, RecordKey>,
key: RecordKey
): 0 | -1 {
if (typeof obj[key] === 'undefined') {
return -1;
}
Expand Down Expand Up @@ -42,20 +47,18 @@ function errorMessage(
);
}

// TODO @Shinigami92 2022-01-24: We should investigate deeper into the types
// Especially the `opts.compare` parameter and `Result` type
export function exec<Method extends (args: Args) => string, Args extends any[]>(
export function exec<Method extends (...parameters) => RecordKey>(
method: Method,
args: Args,
args: Parameters<Method>,
opts: {
maxTime?: number;
maxRetries?: number;
exclude?: string | string[];
compare?: (obj: Record<string, string>, key: string) => 0 | -1;
exclude?: RecordKey | RecordKey[];
compare?: (obj: Record<RecordKey, RecordKey>, key: RecordKey) => 0 | -1;
currentIterations?: number;
startTime?: number;
}
): string {
): ReturnType<Method> {
const now = new Date().getTime();

opts = opts || {};
Expand All @@ -75,7 +78,7 @@ export function exec<Method extends (args: Args) => string, Args extends any[]>(
const startTime = opts.startTime;

// support single exclude argument as string
if (typeof opts.exclude === 'string') {
if (!Array.isArray(opts.exclude)) {
opts.exclude = [opts.exclude];
}

Expand Down Expand Up @@ -103,7 +106,7 @@ export function exec<Method extends (args: Args) => string, Args extends any[]>(
}

// execute the provided method to find a potential satisfied value
const result: string = method.apply(this, args);
const result: ReturnType<Method> = method.apply(this, args);

// if the result has not been previously found, add it to the found array and return the value as it's unique
if (
Expand Down
40 changes: 30 additions & 10 deletions test/unique.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,25 @@ const seededRuns = [
{
seed: 42,
expectations: {
withMethod: 'Test-188',
withCustomMethod: 'Test-188',
withNumberMethod: 37454,
withNumberMethodAndArgs: 19,
},
},
{
seed: 1337,
expectations: {
withMethod: 'Test-132',
withCustomMethod: 'Test-132',
withNumberMethod: 26202,
withNumberMethodAndArgs: 13,
},
},
{
seed: 1211,
expectations: {
withMethod: 'Test-465',
withCustomMethod: 'Test-465',
withNumberMethod: 92852,
withNumberMethodAndArgs: 47,
},
},
];
Expand All @@ -29,7 +35,7 @@ const MOCK_ARRAY = Array.from(
(_, index) => `Test-${index + 1}`
);

function method(prefix: string = ''): string {
function customMethod(prefix: string = ''): string {
const element = faker.random.arrayElement(MOCK_ARRAY);
return `${prefix}${element}`;
}
Expand All @@ -41,20 +47,34 @@ describe('unique', () => {

for (const { seed, expectations } of seededRuns) {
describe(`seed: ${seed}`, () => {
it(`unique(method)`, () => {
it(`unique(customMethod)`, () => {
faker.seed(seed);

const actual = faker.unique(method);
expect(actual).toEqual(expectations.withMethod);
const actual = faker.unique(customMethod);
expect(actual).toEqual(expectations.withCustomMethod);
});

it(`unique(method, args)`, () => {
it(`unique(customMethod, args)`, () => {
faker.seed(seed);

const prefix = 'prefix-1-';

const actual = faker.unique(method, [prefix]);
expect(actual).toEqual(prefix + expectations.withMethod);
const actual = faker.unique(customMethod, [prefix]);
expect(actual).toEqual(prefix + expectations.withCustomMethod);
});

it(`unique(() => number)`, () => {
faker.seed(seed);

const actual = faker.unique(faker.datatype.number);
expect(actual).toEqual(expectations.withNumberMethod);
});

it(`unique(() => number), args)`, () => {
faker.seed(seed);

const actual = faker.unique(faker.datatype.number, [50]);
expect(actual).toEqual(expectations.withNumberMethodAndArgs);
});
});
}
Expand Down

0 comments on commit 14df7d3

Please sign in to comment.