Conversation
Allow user to set length priority to length or unique (POC) ✅ Closes: #220
|
@NetanelBasal @shaharkazaz - This is a super sloppy implementation that I threw together at lunch today, what are your thoughts? |
|
Thanks @theryansmee, @shaharkazaz will go over it asap. |
Move randUniqueElement logic into fakFromArray. Simplified fakeFromFunction while loop logic #220
#223 (comment): I've fixed the other bits |
Add default comparison functions for most likely use cases. Implimented them ✅ Closes: #220
|
@shaharkazaz @NetanelBasal I've still got to write tests and clean up a few bits, but I think this is mostly there now. What are your thoughts? 😊 |
|
@theryansmee I'll re-review it again today 👍 |
Add comparison function and start change over to using it ✅ Closes: #220
|
@shaharkazaz I've ended up creating That said, I think this is actually quite an elegant solution. PS
|
|
🙃 Just seen theres been commits to |
|
Cool, thanks! |
|
I will be fixing the conflicts and merging this later this week :) |
# Conflicts: # packages/falso/src/lib/core/core.ts # packages/falso/src/lib/text.ts
✅ Closes: #220
|
@NetanelBasal - I've merged in the latest changes but now the build is failing on the Any thoughts on what might be happening? |
|
Nopehttps://stackoverflow.com/questions/72598852/getcacheentry-failed-cache-service-responded-with-503 |
# Conflicts: # packages/falso/src/lib/number.ts # packages/falso/src/lib/octal.ts
✅ Closes: 220
✅ Closes: 220
Add tests for simple array and function scenarios. Fix typo in unique checker logic ✅ Closes: 220
|
@NetanelBasal @shaharkazaz - Hi guys, sorry for the radio silence from me (Life got a little hectic). I have fixed the merge conflicts and added a few essential tests to prove priority logic works as expected with data from arrays and from functions. I think it's ready to be reviewed again 😊 |
|
@theryansmee Hi Ryan always a pleasure to hear from you 😁 |
I'm back for good this time! haha Cheers mate 😊 |
shaharkazaz
left a comment
There was a problem hiding this comment.
This is the first cycle, I'll go in-depth over the core files, these are the first things that I saw
packages/falso/src/lib/core/core.ts
Outdated
| uniqueComparer: ( | ||
| item: T, | ||
| items: T[], | ||
| comparisonKeys?: string[] |
There was a problem hiding this comment.
In the case of an object, you always pass comparisonKeys right?
If so, let's make this type stricter, and the values should also be a sub-set of T's keys.
There was a problem hiding this comment.
If i'm honest I was having a little trouble with the types for this. I had a lot of issues when I tried to make this not optional. I have changed the comparisonKeys type from string[] to (keyof T)[] though
| ) => boolean = (item, items) => objectIsUnique(item, items, ['id']); | ||
|
|
||
| export const objectIsUnique: ( | ||
| item: any, |
There was a problem hiding this comment.
Why any and not a generic?
There was a problem hiding this comment.
Yeah I wasn't a fan of this either. On further inspection i've managed to change it to objectIsUnique<T extends Record<string, any>>. I think this should be ok for now
| }; | ||
|
|
||
| return fake(factory, options); | ||
| return fake(factory, options, { uniqueComparer: checkUnique }); |
| }); | ||
| } | ||
|
|
||
| const checkUnique: ( |
| }); | ||
|
|
||
| describe('object id is unique', () => { | ||
| it('should return true', () => { |
There was a problem hiding this comment.
I agree with Netanel's previous comment about the naming.
Maybe something like:
it(Should pass when object ids are unique) instead of the describe. This goes to all the specs I've seen in the recent files.
@NetanelBasal thoughts?
Cheers mate, i'll have a look through and get these sorted tomorrow 👍 |
Change comparison of valueOf to getTime with dateIsUnique. Combine describe block and it labels for comparison function tests ✅ Closes: 220
Change checkUnique arrow functions to function declorations. Change unique-validators from inline arrow functions to actual function. Make function more type safe ✅ Closes: 220
Strengthen type checking. Remove redundant error and test ✅ Closes: 220
Strengthen type checking for comparisonKeys ✅ Closes: 220
|
@shaharkazaz - Hello mate, I have made all of the requested changes and left a few comments 😊 |
| config: FakeConfig<T>, | ||
| options?: Options | ||
| ): T | T[] { | ||
| if (!options?.length) { |
There was a problem hiding this comment.
You are handling the length options both here and in the fake function, please choose one place
| const maxAttempts = options.length * 2; | ||
|
|
||
| while (items.length < options.length && attempts < maxAttempts) { | ||
| const item = data(0); |
There was a problem hiding this comment.
I think it makes sense to pass the attempts as the function's argument.
There was a problem hiding this comment.
@shaharkazaz - How do you mean? To allow the user to decide the total number of attempts?
There was a problem hiding this comment.
You are passing 0 to that factory function, I think it makes more sense to pass the attempts, if the factory is using the index passed than you will increase the chances of getting the same result.
@NetanelBasal WDYT?
| data: T[], | ||
| options?: Options | ||
| ): T | T[] { | ||
| if (!options?.length) { |
| const newArray: T[] = []; | ||
|
|
||
| while (clonedData.length && newArray.length !== options.length) { | ||
| const randomIndex = getRandomInRange({ |
There was a problem hiding this comment.
There is a hidden assumption here that the array you are given holds unique values.
Please change the code to support non-unique arrays.
There was a problem hiding this comment.
@shaharkazaz - You are correct. How did I not spot that :/
I have reworked it to shuffle the data array and then pick the first n items from it. A positive of doing it this way is that the user will receive an array with a length as close as possible to their desired length. The issue is that this will be more expensive for large data sets.
export function fakeFromArray<T, Options extends FakeOptions>(
data: T[],
options?: Options
): T | T[] {
if (options?.length === 0) {
return [];
}
if (!options?.length) {
return randElement(data);
}
const priority = options?.priority ?? 'length';
if (priority === 'length') {
return Array.from({ length: options.length }, () => randElement(data));
}
let clonedData: T[] = JSON.parse(JSON.stringify(data));
// Randomise order of data
clonedData = shuffleArray<T>(clonedData);
if (options.length >= clonedData.length) {
return clonedData;
}
return clonedData.slice(0, length);
}
function shuffleArray<T>(array: T[]): T[] {
for (let i = array.length - 1; i > 0; i--) {
const randomIndex = Math.floor(random() * (i + 1));
[
array[i],
array[randomIndex],
] = [
array[randomIndex],
array[i],
];
}
return array;
}What are your thoughts?
| if (Array.isArray(data)) { | ||
| return fakeFromArray(data, options) as any; | ||
| } | ||
|
|
||
| return fakeFromFunction(data as FactoryFunction<T>, config, options) as any; |
There was a problem hiding this comment.
You have a lot of shared code here, I think I would normalize the array data source to also work on a function with a random element and just use factory-based fake for both.
There was a problem hiding this comment.
I'm happy to do this I just felt like this whole fake logic was getting quite complex so keeping them separate made it easier to read for me. But i'm happy either way.
I think in hindsight, if we were starting over i'd suggest that instead of option.length property we have singular and plural function for each. E.G randId that returns a string & randIds that uses randId to generate & return a string[]. But it might be a bit late for that ;) haha
There was a problem hiding this comment.
Personally I prefer the length property, adding a plural will double the API for not a good enough reason from my point of view
There was a problem hiding this comment.
Fair play. It works pretty well for our users, it just adds a lot of headaches for deving haha. All good though
| return fake(factory, options, { uniqueComparer: checkUnique }); | ||
| } | ||
|
|
||
| function checkUnique(card: CreditCard, cards: CreditCard[]): boolean { |
There was a problem hiding this comment.
This is repreated several times, maybe create a factory function that creates the chacker
function uniqueByKeys(keys){
return (a, b) => objectIsUnique(keys)
}There was a problem hiding this comment.
@shaharkazaz - Sorry I don't know how I missed this. Do you mean something like:
export function randCreditCard<Options extends CreditCardOptions = never>(
options?: Options
) {
const factory: () => CreditCard = () => {
const fullName =
options?.fullName ??
`${randPersonTitle()} ${randFullName({ withAccents: false })}`;
const brand = options?.brand ?? (randCreditCardBrand() as Brand);
const dateOptions: Intl.DateTimeFormatOptions = {
month: 'numeric',
year: '2-digit',
};
const validFrom = randPastDate({ years: 1 }).toLocaleDateString(
'en-GB',
dateOptions
);
const untilEnd = randFutureDate({ years: 2 }).toLocaleDateString(
'en-GB',
dateOptions
);
return {
fullName,
brand,
validFrom,
untilEnd,
ccv: randCreditCardCVV(),
number: randCreditCardNumber({ brand }),
account: randAccount(),
type: rand(['Credit', 'Debit']),
};
};
return fake(
factory,
options,
{
// Moved logic into here rather than wrapping objectIsUnique call in new function
uniqueComparer: (card, cards) => objectIsUnique(card, cards, ['number'])
}
);
}
packages/falso/src/lib/json.ts
Outdated
| } | ||
|
|
||
| function checkUnique(item: object, items: object[]): boolean { | ||
| return items.some((i) => JSON.stringify(i) === JSON.stringify(item)); |
| } | ||
|
|
||
| function checkUnique(coordinate: number[], coordinates: number[][]): boolean { | ||
| return coordinates.some((c) => c.join('') === c.join('')); |
There was a problem hiding this comment.
Same comment as the json unique
Co-authored-by: Shahar Kazaz <shahar.kazaz@gmail.com>
Change type back to original. Move option.length short circuit checks into fakeFromFunction/fakeFromArray functions. Fix typos in checkUnique logic for randJSON & randNearbyGPSCoordinate. Add missing tests tests. ✅ Closes: 220
|
@shaharkazaz - I have made the requested changes for all the comments that I understood and left you queries everywhere else :) I hope these all make sense |
|
Ok, I think all of the requested changes have been made with just a few outstanding queries left to be answered |
|
@theryansmee I'm actually on vacation in Thailand 😀 |

Allow user to set length priority to length or unique (POC)
✅ Closes: #220
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
Issue Number: N/A
What is the new behavior?
Does this PR introduce a breaking change?
Other information