Skip to content

Commit

Permalink
issue-171 many-to-many replacement (without increase)
Browse files Browse the repository at this point in the history
  • Loading branch information
dhilt committed Dec 7, 2020
1 parent da3af67 commit 9202091
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 50 deletions.
113 changes: 74 additions & 39 deletions tests/adapter.replace.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,31 @@ const baseSettings = {

interface ICustom {
token: 'first' | 'last' | 'middle';
indexToReplace?: number;
indexesToReplace?: number[];
indexesToReplace: number[]; // indexes to remove
amount: number; // amount of new items
increase?: boolean;
}

const configList: TestBedConfig[] = [{
datasourceSettings: { ...baseSettings },
custom: {
indexToReplace: baseSettings.minIndex + 1,
token: 'middle'
}
indexesToReplace: [baseSettings.minIndex + 1],
token: 'middle',
amount: 1
} as ICustom
}, {
datasourceSettings: { ...baseSettings },
custom: {
indexToReplace: baseSettings.minIndex,
token: 'first'
indexesToReplace: [baseSettings.minIndex],
token: 'first',
amount: 1
} as ICustom
}, {
datasourceSettings: { ...baseSettings, startIndex: baseSettings.maxIndex },
custom: {
indexToReplace: baseSettings.maxIndex,
token: 'last'
indexesToReplace: [baseSettings.maxIndex],
token: 'last',
amount: 1
} as ICustom
}].map(config => ({
...config,
Expand All @@ -49,7 +52,8 @@ const manyToOneConfigList: TestBedConfig[] = [{
baseSettings.minIndex + 2,
baseSettings.minIndex + 3
],
token: 'middle'
token: 'middle',
amount: 1
} as ICustom
}, {
datasourceSettings: { ...baseSettings },
Expand All @@ -59,7 +63,8 @@ const manyToOneConfigList: TestBedConfig[] = [{
baseSettings.minIndex + 1,
baseSettings.minIndex + 2
],
token: 'first'
token: 'first',
amount: 1
} as ICustom
}, {
datasourceSettings: { ...baseSettings, startIndex: baseSettings.maxIndex },
Expand All @@ -69,7 +74,8 @@ const manyToOneConfigList: TestBedConfig[] = [{
baseSettings.maxIndex - 1,
baseSettings.maxIndex
],
token: 'last'
token: 'last',
amount: 1
} as ICustom
}].map(config => ({
...config,
Expand All @@ -81,38 +87,53 @@ const manyToOneIncreaseConfigList = manyToOneConfigList.map(config => ({
custom: {
...config.custom,
increase: true
}
} as ICustom
}));

const manyToManyConfigList = [
...manyToOneConfigList.map(config => ({
...config, custom: { ...config.custom, amount: 2 } as ICustom
})),
...manyToOneConfigList.map(config => ({
...config, custom: { ...config.custom, amount: 3 } as ICustom
})),
...manyToOneConfigList.map(config => ({
...config, custom: { ...config.custom, amount: 4 } as ICustom
})),
];

const shouldReplace = (config: TestBedConfig) => (misc: Misc) => async (done: Function) => {
await misc.relaxNext();
const { adapter } = misc;
const { indexToReplace: index, indexesToReplace: indexes, token, increase } = config.custom;
const { indexesToReplace: indexes, amount, token, increase } = config.custom;
const { datasourceSettings: { minIndex, itemSize } } = config;
const diff = indexes ? indexes.length : 1;
const diff = amount - indexes.length; // inserted - removed
const viewportSize = misc.getScrollableSize();
const sizeToRemove = (diff - 1) * misc.getItemSize();
const maxScrollPosition = misc.getMaxScrollPosition() - sizeToRemove;
const newIndex = indexes ? indexes[increase ? indexes.length - 1 : 0] : index;
const newMinIndex = increase ? minIndex + diff - 1 : minIndex;
const position = token === 'last' ? maxScrollPosition : (newIndex - newMinIndex) * itemSize;
const newItem = generateItem(newIndex);
newItem.text += '*';
const sizeToChange = diff * misc.getItemSize();
const maxScrollPosition = misc.getMaxScrollPosition() + sizeToChange;
const newIndexFirst = indexes[increase ? indexes.length - 1 : 0];
const newIndexLast = newIndexFirst + amount - 1;
const newAbsMinIndex = increase ? minIndex - diff : minIndex;
const position = token === 'last' ? maxScrollPosition : (newIndexFirst - newAbsMinIndex) * itemSize;
const items = Array.from({ length: amount }).map((j, i) => generateItem(newIndexFirst + i, false, '*'));

// replace at the Datasource level (component)
if (index) {
(misc.datasource as any).replaceOneToOne(index, newItem);
} else if (indexes) {
(misc.datasource as any).replaceManyToOne(indexes, newItem, increase);
if (indexes.length === 1 && amount === 1) {
(misc.datasource as any).replaceOneToOne(indexes[0], items[0]);
} else if (indexes.length > 1 && amount === 1) {
(misc.datasource as any).replaceManyToOne(indexes, items[0], increase);
} else if (indexes.length > 1 && amount > 1) {
(misc.datasource as any).replaceManyToMany(indexes, items, increase);
}

// replace at the Viewport level (scroller)
await adapter.replace({
predicate: ({ $index }) => (indexes || [index]).includes($index),
items: [newItem],
predicate: ({ $index }) => indexes.includes($index),
items,
increase
});

// refresh the view via scroll to edges
await misc.scrollMinMax();

// scroll to replaced item
Expand All @@ -121,31 +142,35 @@ const shouldReplace = (config: TestBedConfig) => (misc: Misc) => async (done: Fu
await misc.relaxNext();
}

// check replaced item
// check edge replaced items
if (token === 'last') {
expect(adapter.lastVisible.$index).toEqual(newIndex);
expect(adapter.lastVisible.$index).toEqual(newIndexLast);
} else {
expect(adapter.firstVisible.$index).toEqual(newIndex);
expect(adapter.firstVisible.$index).toEqual(newIndexFirst);
}
expect(misc.getElementText(newIndex)).toEqual(newIndex + ': ' + newItem.text);
expect(misc.getElementText(newIndexFirst)).toEqual(newIndexFirst + ': ' + items[0].text);
expect(misc.getElementText(newIndexLast)).toEqual(newIndexLast + ': ' + items[items.length - 1].text);

// check the next item
// check the item next to the last replaced one
if (token === 'last') {
expect(misc.checkElementContent(newIndex - 1, newIndex - (increase ? diff : 1))).toEqual(true);
expect(misc.checkElementContent(newIndexFirst - 1, newIndexFirst - (increase ? 1 - diff : 1))).toEqual(true);
} else {
expect(misc.checkElementContent(newIndex + 1, newIndex + (increase ? 1 : diff))).toEqual(true);
expect(misc.checkElementContent(newIndexLast + 1, newIndexLast + (increase ? 1 : 1 - diff))).toEqual(true);
}

expect(misc.getScrollableSize()).toBe(viewportSize - sizeToRemove);
expect(misc.getScrollableSize()).toBe(viewportSize + sizeToChange);
done();
};

describe('Adapter Replace Spec', () => {

const getTitle = ({ custom: { token, indexesToReplace: { length }, amount } }: TestBedConfig) =>
`should replace ${token} ${length === 1 ? 'one' : length} to ${amount === 1 ? 'one' : amount}`;

describe('one-to-ne replacement', () =>
configList.forEach(config =>
makeTest({
title: `should work (${config.custom.token})`,
title: getTitle(config),
config,
it: shouldReplace(config)
})
Expand All @@ -155,7 +180,7 @@ describe('Adapter Replace Spec', () => {
describe('many-to-one replacement', () =>
manyToOneConfigList.forEach(config =>
makeTest({
title: `should work (${config.custom.token})`,
title: getTitle(config),
config,
it: shouldReplace(config)
})
Expand All @@ -165,7 +190,17 @@ describe('Adapter Replace Spec', () => {
describe('many-to-one increase replacement', () =>
manyToOneIncreaseConfigList.forEach(config =>
makeTest({
title: `should work (${config.custom.token})`,
title: getTitle(config),
config,
it: shouldReplace(config)
})
)
);

describe('many-to-many replacement', () =>
manyToManyConfigList.filter((i, j) => j >= 0).forEach(config =>
makeTest({
title: getTitle(config),
config,
it: shouldReplace(config)
})
Expand Down
32 changes: 21 additions & 11 deletions tests/scaffolding/datasources/class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,20 +76,30 @@ export const getDatasourceReplacementsClass = (settings: Settings) =>
}

replaceManyToOne(idsToReplace: number[], item: Item, increase: boolean) {
this.replaceManyToMany(idsToReplace, [item], increase);
}

replaceManyToMany(idsToReplace: number[], items: Item[], increase: boolean) {
idsToReplace.sort((a, b) => a - b);
const minId = idsToReplace[0];
const maxId = idsToReplace.slice(1).reduce((acc, id) =>
// only continuous series allowed
id === acc + 1 ? id : acc, minId
const minRem = idsToReplace[0];
const maxRem = idsToReplace.slice(1).reduce((acc, id) =>
id === acc + 1 ? id : acc, minRem // only continuous series allowed
);
const diff = maxId - minId;
this.data = this.data.reduce((acc, _item: Item) => {
if ((!increase && _item.id < minId) || (increase && _item.id > maxId)) {
acc.push(_item);
} else if ((increase && _item.id === minId) || (!increase && _item.id === maxId)) {
const itemsToRemove = maxRem - minRem + 1;
const diff = itemsToRemove - items.length;

let inserted = false;
this.data = this.data.reduce((acc, item: Item) => {
if ((!increase && item.id < minRem) || (increase && item.id > maxRem)) {
// below (or above if increase): persist
acc.push(item);
} else if ((!increase && _item.id > maxId) || (increase && _item.id < minId)) {
acc.push({ ..._item, id: _item.id + (increase ? 1 : -1) * diff });
} else if ((!increase && item.id > maxRem) || (increase && item.id < minRem)) {
// above (or below if increase): shift
acc.push({ ...item, id: item.id + (!increase ? -1 : 1) * diff });
} else if (!inserted) {
// in the middle: replace
acc.push(...items);
inserted = true;
}
return acc;
}, [] as Item[]);
Expand Down

0 comments on commit 9202091

Please sign in to comment.