mirror of
https://gitlab.com/walljm/dynamicbible.git
synced 2025-07-23 07:19:50 -04:00
CardList merging with unit tests for passage cards
This commit is contained in:
parent
b53ae39bb0
commit
bafd755134
56
app/db/src/app/common/card-operations.spec.ts
Normal file
56
app/db/src/app/common/card-operations.spec.ts
Normal 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());
|
||||
}
|
||||
});
|
||||
});
|
55
app/db/src/app/common/card-operations.ts
Normal file
55
app/db/src/app/common/card-operations.ts
Normal 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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
},
|
||||
]);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user