Skip to content

Commit

Permalink
Control collision and race-condition for spread keys
Browse files Browse the repository at this point in the history
  • Loading branch information
abumq committed Jul 25, 2023
1 parent 59b58fa commit b9d56ef
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
## Unreleased
- Control collision and race-condition for spread keys

## 1.0.8
- Fix: Typed arrays are no longer going to return `Array`
Expand Down
7 changes: 4 additions & 3 deletions src/json.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ const NO_RESOLUTION_CLASS_LIST = [
...TYPED_ARRAY_NAMES,
];

let SPREAD_COUNTER = 0;
const SPREAD_KEY_NAME = '__airsync_spread_key';

// if [].from() is available use that otherwise use constructor
Expand Down Expand Up @@ -131,8 +130,10 @@ const createObject = (obj, depth, currentKey, opts = {}) => {
const finalResult = {};
for (let keyIdx in keys) {
const key = keys[keyIdx];
const finalValue = await createObject(values[keyIdx], 0, key)
const finalValue = await createObject(values[keyIdx], 0, key);

if (key.indexOf(SPREAD_KEY_NAME) === 0) {
console.log(key)
Object.assign(finalResult, finalValue);
} else {
Object.assign(finalResult, { [key] : finalValue });
Expand Down Expand Up @@ -177,7 +178,7 @@ const json = (val, opts = {}) => {
/**
* Flags the field to be spreaded in resulting JSON.
*/
const spread = () => SPREAD_KEY_NAME + ++SPREAD_COUNTER;
const spread = () => SPREAD_KEY_NAME + Math.random();

module.exports.json = json;
module.exports.spread = spread;
20 changes: 17 additions & 3 deletions tests/deep-json.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const assert = require('assert');
const { json } = require('../src');
const { json, spread } = require('../src');

describe('When we have JSON with deep promiss', async () => {
describe('When we have JSON with deep promise', async () => {
const item = async () => 1
const jsonItem = () => json({
result: item()
Expand All @@ -20,6 +20,10 @@ describe('When we have JSON with deep promiss', async () => {
}
}
}
const getMe = async () => ({ name: 'John' });
const getFather = async () => ({ name: 'Paul' });
const getGrandfather = async () => ({ name: 'Leaf' });

const produce = async () => {
return json({
depth1_1: item(),
Expand All @@ -32,7 +36,17 @@ describe('When we have JSON with deep promiss', async () => {
depth1_4: jsonItem(),
depth1_5: jsonItemAsync(),
depth1_6: itemAsync(),

data: {
user: {
[spread()]: getMe(),
father: {
[spread()]: getFather(),
grandfather: {
[spread()]: getGrandfather(),
}
},
},
},
})
}
const result = await produce();
Expand Down
31 changes: 24 additions & 7 deletions tests/spread.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ describe('When we have JSON with spread()', async () => {
const person = queryPerson();
const profile = queryProfile(person);

const raceTest = () => {
const raceTest = async () => {
const obj = {};
for (let i = 0; i <= RACE_NUMBERS; ++i) {
obj[`item-${i}`] = airsync.json({
Expand Down Expand Up @@ -41,14 +41,14 @@ describe('When we have JSON with spread()', async () => {
assert.equal(props.id, 1);
});

it('No race condition', () => {
it('No a lot of spreads', () => {
for (let i = 0; i <= RACE_NUMBERS; ++i) {
const raceItem = props[`item-${i}`];
assert.equal(raceItem.name, 'John', `Race condition test - number ${i} name failed`);
assert.equal(raceItem.age, 85, `Race condition test - number ${i} age failed`);
assert.equal(raceItem.height, 173, `Race condition test - number ${i} height failed`);
assert.equal(raceItem.weight, 70, `Race condition test - number ${i} weight failed`);
assert.equal(raceItem.id, 1, `Race condition test - number ${i} id failed`);
assert.equal(raceItem.name, 'John', `a lot of spreads test - number ${i} name failed`);
assert.equal(raceItem.age, 85, `a lot of spreads test - number ${i} age failed`);
assert.equal(raceItem.height, 173, `a lot of spreads test - number ${i} height failed`);
assert.equal(raceItem.weight, 70, `a lot of spreads test - number ${i} weight failed`);
assert.equal(raceItem.id, 1, `a lot of spreads test - number ${i} id failed`);
}
});

Expand All @@ -60,3 +60,20 @@ describe('When we have JSON with spread()', async () => {
});
});

describe('Test collision for spread key', () => {
const TEST_COUNT = 10000;
const LOG_FREQ = 1000;
const list = [];

it(`Ensure no spread key is same when produced ${TEST_COUNT} times`, () => {
for (let i = 1; i <= TEST_COUNT; ++i) {
const r = airsync.spread();
if (i % LOG_FREQ === 0) console.log('No collion so far ', i)
if (list.indexOf(r) > -1) {
assert.fail(`Spread key collided at index ${i} (${r})`)
}
list.push(r);
}
})
})

0 comments on commit b9d56ef

Please sign in to comment.