CardList merging with unit tests for passage cards

This commit is contained in:
Jeremy Wall 2020-08-09 09:31:18 -04:00
parent b53ae39bb0
commit bafd755134
4 changed files with 127 additions and 3 deletions

View File

@ -0,0 +1,56 @@
import { maybeMergeCards, mergeCardList } from './card-operations';
import { BibleReference, Overlap } from './bible-reference';
describe('Card Merging', () => {
it('Should merge two equal cards', () => {
let cardList = [
{ type: 'Passage', qry: 'Genesis 1:1', data: null, dict: '' },
{ type: 'Passage', qry: 'Genesis 1:1', data: null, dict: '' },
];
for (const strat of [Overlap.Equal, Overlap.Subset]) {
let merged = mergeCardList(cardList, strat);
expect(merged.length).toBe(1);
expect(merged[0].qry).toEqual(new BibleReference('Genesis 1:1').toString());
}
});
it('Should merge two equal cards with one in the middle', () => {
let cardList = [
{ type: 'Passage', qry: 'Genesis 1:1', data: null, dict: '' },
{ type: 'Passage', qry: 'Genesis 1:2', data: null, dict: '' },
{ type: 'Passage', qry: 'Genesis 1:1', data: null, dict: '' },
];
for (const strat of [Overlap.Equal, Overlap.Subset]) {
let merged = mergeCardList(cardList, strat);
expect(merged.length).toBe(2);
expect(merged[0].qry).toEqual(new BibleReference('Genesis 1:1').toString());
expect(merged[1].qry).toEqual(new BibleReference('Genesis 1:2').toString());
}
});
it('Should merge two intersecting cards', () => {
let cardList = [
{ type: 'Passage', qry: 'Genesis 1:1-2', data: null, dict: '' },
{ type: 'Passage', qry: 'Genesis 1:1', data: null, dict: '' },
];
for (const strat of [Overlap.Intersect, Overlap.Subset]) {
let merged = mergeCardList(cardList, strat);
expect(merged.length).toBe(1);
expect(merged[0].qry).toEqual(new BibleReference('Genesis 1:1 - 2').toString());
}
});
it('Should merge two intersecting cards with one in the middle', () => {
let cardList = [
{ type: 'Passage', qry: 'Genesis 1:1-2', data: null, dict: '' },
{ type: 'Passage', qry: 'Genesis 1:4', data: null, dict: '' },
{ type: 'Passage', qry: 'Genesis 1:1', data: null, dict: '' },
];
for (const strat of [Overlap.Intersect, Overlap.Subset]) {
let merged = mergeCardList(cardList, strat);
expect(merged.length).toBe(2);
expect(merged[0].qry).toEqual(new BibleReference('Genesis 1:1 - 2').toString());
expect(merged[1].qry).toEqual(new BibleReference('Genesis 1:4').toString());
}
});
});

View File

@ -0,0 +1,55 @@
import { BibleReference, Overlap } from './bible-reference';
import { CardItem } from '../models/app-state';
export function maybeMergeCards(leftCard: CardItem, rightCard: CardItem, strategy: Overlap): CardItem | null {
if (leftCard.type === rightCard.type) {
switch (strategy) {
case Overlap.Equal:
if (leftCard.qry === rightCard.qry) {
return { ...leftCard };
}
break;
case Overlap.Intersect:
case Overlap.Subset:
if (leftCard.type === 'Passage') {
const leftRef = new BibleReference(leftCard.qry);
const rightRef = new BibleReference(rightCard.qry);
let mergedRef = BibleReference.mergeReference(leftRef, rightRef, strategy);
if (mergedRef !== null) {
return {
...leftCard,
qry: mergedRef.toString(),
};
}
}
break;
}
}
return null;
}
export function mergeCardList(cardList: CardItem[], strategy: Overlap) {
if (strategy == Overlap.None || cardList.length === 0) {
return [...cardList];
}
let cardListCopy = [...cardList];
let removals = [];
for (const cardIdx in cardListCopy) {
if (cardIdx in removals) {
continue;
}
for (let compareIdx = Number(cardIdx) + 1; compareIdx < cardListCopy.length; compareIdx++) {
const leftCard = cardListCopy[cardIdx];
const rightCard = cardListCopy[compareIdx];
let mergedCard = maybeMergeCards(leftCard, rightCard, strategy);
if (mergedCard != null) {
cardListCopy[cardIdx] = mergedCard;
removals.push(compareIdx);
}
}
}
for (const idx of removals) {
cardListCopy.splice(idx, 1);
}
return cardListCopy;
}

View File

@ -3,12 +3,14 @@ import { NoteItem } from './note-state';
import { BiblePassageResult } from './passage-state';
import { StrongsResult } from './strongs-state';
import { WordLookupResult } from './words-state';
import { Overlap } from '../common/bible-reference';
export interface AppState {
readonly currentSavedPage: SavedPage;
readonly savedPages: IStorable<readonly SavedPage[]>;
readonly notes: IStorable<readonly NoteItem[]>;
readonly displaySettings: IStorable<DisplaySettings>;
readonly pageSettings: IStorable<PageSettings>;
readonly savedPagesLoaded: boolean;
readonly mainPages: readonly Page[];
readonly cards: readonly CardItem[];
@ -38,6 +40,10 @@ export interface CardIcons {
readonly note: string;
}
export interface PageSettings {
readonly mergeStrategy: Overlap;
}
export interface DisplaySettings {
readonly showStrongsAsModal: boolean;
@ -72,6 +78,7 @@ export interface SavedPage {
export interface CardItem {
readonly qry: string;
readonly data: Data;
// TODO(jwall): This should probably be an enum
readonly type: string;
readonly dict: string;
}

View File

@ -1,7 +1,7 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { AppState, SavedPage, Error, CardItem, DisplaySettings, User } from '../models/app-state';
import { Section, BibleReference } from '../common/bible-reference';
import { Section, BibleReference, Overlap } from '../common/bible-reference';
import { PageTitles, PageIcons } from '../constants';
import { createStateService } from '../common/state-service';
import { UUID } from 'angular2-uuid';
@ -68,6 +68,12 @@ const initialState: AppState = {
syncCardsAcrossDevices: false,
},
},
pageSettings: {
createdOn: new Date(0).toISOString(),
value: {
mergeStrategy: Overlap.Subset,
},
},
cardIcons: {
words: 'font_download',
passage: 'menu_book',
@ -245,7 +251,7 @@ function reducer(state: AppState, action: AppAction): AppState {
{
id: state.currentSavedPage.id,
title: state.currentSavedPage.title,
queries: [...state.cards],
queries: [...state.cards], // need a function that processes the cards to merge references.
},
]);
@ -261,7 +267,7 @@ function reducer(state: AppState, action: AppAction): AppState {
// create a new saved page object
title: action.title,
id: UUID.UUID().toString(),
queries: [...state.cards],
queries: [...state.cards], // need a function that processes the cards to merge references.
},
]);