Better merging logic handle the cross chapter case

This commit is contained in:
Jeremy Wall 2020-08-07 21:16:22 -04:00
parent 80be335d2b
commit 8ed0da3c1d
2 changed files with 120 additions and 22 deletions

View File

@ -353,4 +353,58 @@ describe('Reference Overlap Detection', () => {
expect(BibleReference.mergeReference(leftRef, rightRef, Overlap.Subset)).toEqual(new BibleReference('Gen 1:1-10')); expect(BibleReference.mergeReference(leftRef, rightRef, Overlap.Subset)).toEqual(new BibleReference('Gen 1:1-10'));
expect(BibleReference.mergeReference(leftRef, rightRef, Overlap.None)).toBeNull(); expect(BibleReference.mergeReference(leftRef, rightRef, Overlap.None)).toBeNull();
}); });
it('Detects Left chapter Overlaps right chapter', () => {
const leftRef = new BibleReference('Gen 1:1-2:5');
const rightRef = new BibleReference('Gen 2:1-10');
expect(BibleReference.overlap(leftRef, rightRef)).toBe(Overlap.Intersect);
expect(BibleReference.mergeReference(leftRef, rightRef, Overlap.Intersect)).toEqual(new BibleReference('Gen 1:1-2:10'));
expect(BibleReference.mergeReference(leftRef, rightRef, Overlap.Subset)).toBeNull();
expect(BibleReference.mergeReference(leftRef, rightRef, Overlap.None)).toBeNull();
});
it('Detects Right chapter Overlaps Left chapter', () => {
const leftRef = new BibleReference('Gen 2:1-10');
const rightRef = new BibleReference('Gen 1:1-2:5');
expect(BibleReference.overlap(leftRef, rightRef)).toBe(Overlap.Intersect);
expect(BibleReference.mergeReference(leftRef, rightRef, Overlap.Intersect)).toEqual(new BibleReference('Gen 1:1-2:10'));
expect(BibleReference.mergeReference(leftRef, rightRef, Overlap.Subset)).toBeNull();
expect(BibleReference.mergeReference(leftRef, rightRef, Overlap.None)).toBeNull();
});
it('Detects discontinuous chapters', () => {
const leftRef = new BibleReference('Gen 2:6-10');
const rightRef = new BibleReference('Gen 1:1-2:5');
expect(BibleReference.overlap(leftRef, rightRef)).toBe(Overlap.None);
expect(BibleReference.mergeReference(leftRef, rightRef, Overlap.Intersect)).toBeNull();
expect(BibleReference.mergeReference(leftRef, rightRef, Overlap.Subset)).toBeNull();
expect(BibleReference.mergeReference(leftRef, rightRef, Overlap.None)).toBeNull();
});
it('Detects left side embedded chapters', () => {
const leftRef = new BibleReference('Gen 1:1-2:5');
const rightRef = new BibleReference('Gen 1:1-3:1');
expect(BibleReference.overlap(leftRef, rightRef)).toBe(Overlap.Subset);
expect(BibleReference.mergeReference(leftRef, rightRef, Overlap.Intersect).toString()).toEqual(
new BibleReference('Gen 1:1-3:1').toString()
);
expect(BibleReference.mergeReference(leftRef, rightRef, Overlap.Subset)).toEqual(new BibleReference('Gen 1:1-3:1'));
expect(BibleReference.mergeReference(leftRef, rightRef, Overlap.None)).toBeNull();
});
it('Detects right side embedded chapters', () => {
const leftRef = new BibleReference('Gen 1:1-3:1');
const rightRef = new BibleReference('Gen 1:1-2:5');
expect(BibleReference.overlap(leftRef, rightRef)).toBe(Overlap.Subset);
expect(BibleReference.mergeReference(leftRef, rightRef, Overlap.Intersect).toString()).toEqual(
new BibleReference('Gen 1:1-3:1').toString()
);
expect(BibleReference.mergeReference(leftRef, rightRef, Overlap.Subset)).toEqual(new BibleReference('Gen 1:1-3:1'));
expect(BibleReference.mergeReference(leftRef, rightRef, Overlap.None)).toBeNull();
});
}); });

View File

@ -1885,6 +1885,13 @@ export class BibleReference {
return this.Books[booknum]; return this.Books[booknum];
} }
public static locationToIndex(book: number, loc: Location): number {
let ref = book * 100000000;
ref = ref + loc.chapter * 10000;
ref = ref + loc.verse;
return ref;
}
static formatReferenceKey( static formatReferenceKey(
book: number | string, book: number | string,
chapter: number | string, chapter: number | string,
@ -1899,29 +1906,40 @@ export class BibleReference {
return new BibleReference(`${book} ${keyArray[1]}:${keyArray[2]}`); return new BibleReference(`${book} ${keyArray[1]}:${keyArray[2]}`);
} }
static overlap(leftRef: BibleReference, rightRef: BibleReference): Overlap { public static overlap(
leftRef: BibleReference,
rightRef: BibleReference
): Overlap {
if (leftRef.section.book !== rightRef.section.book) { if (leftRef.section.book !== rightRef.section.book) {
// either of the above means we are not overlapping // either of the above means we are not overlapping
return Overlap.None; return Overlap.None;
} }
if (leftRef.section.start.chapter === rightRef.section.end.chapter) { let leftStartIndex = leftRef.startIndex();
if (leftRef.section.start.verse >= rightRef.section.start.verse) { let leftEndIndex = leftRef.endIndex();
if (leftRef.section.end.verse <= rightRef.section.end.verse) { let rightStartIndex = rightRef.startIndex();
return Overlap.Subset; let rightEndIndex = rightRef.endIndex();
}
return Overlap.Intersect; if (
} else if (rightRef.section.start.verse > leftRef.section.start.verse) { // left is subset of right
if (rightRef.section.end.verse < leftRef.section.end.verse) { (leftStartIndex >= rightStartIndex && leftEndIndex <= rightEndIndex) ||
return Overlap.Subset; // right is subset of left
} (rightStartIndex >= leftStartIndex && rightEndIndex <= leftEndIndex)
return Overlap.Intersect; ) {
} return Overlap.Subset;
}
if (
// left overlaps the right
(leftEndIndex >= rightStartIndex && leftEndIndex <= rightEndIndex) ||
// right overlaps the left
(rightEndIndex >= leftStartIndex && rightEndIndex <= leftEndIndex)
) {
return Overlap.Intersect;
} }
return Overlap.None; return Overlap.None;
} }
static mergeReference( public static mergeReference(
ref1: BibleReference, ref1: BibleReference,
ref2: BibleReference, ref2: BibleReference,
strategy: Overlap strategy: Overlap
@ -1950,18 +1968,30 @@ export class BibleReference {
ref1.section.start.chapter <= ref2.section.start.chapter ref1.section.start.chapter <= ref2.section.start.chapter
? ref1.section.start.chapter ? ref1.section.start.chapter
: ref2.section.start.chapter; : ref2.section.start.chapter;
mergedRef.section.start.verse = if (ref1.section.start.chapter < ref2.section.start.chapter) {
ref1.section.start.verse <= ref2.section.start.verse mergedRef.section.start.verse = ref1.section.start.verse;
? ref1.section.start.verse } else if (ref2.section.start.chapter < ref1.section.start.chapter) {
: ref2.section.start.verse; mergedRef.section.start.verse = ref2.section.start.verse;
} else {
mergedRef.section.start.verse =
ref1.section.start.verse <= ref2.section.start.verse
? ref1.section.start.verse
: ref2.section.start.verse;
}
mergedRef.section.end.chapter = mergedRef.section.end.chapter =
ref1.section.end.chapter >= ref2.section.end.chapter ref1.section.end.chapter >= ref2.section.end.chapter
? ref1.section.end.chapter ? ref1.section.end.chapter
: ref2.section.end.chapter; : ref2.section.end.chapter;
mergedRef.section.end.verse = if (ref1.section.end.chapter > ref2.section.end.chapter) {
ref1.section.end.verse >= ref2.section.end.verse mergedRef.section.end.verse = ref1.section.end.verse;
? ref1.section.end.verse } else if (ref2.section.end.chapter > ref1.section.end.chapter) {
: ref2.section.end.verse; mergedRef.section.end.verse = ref2.section.end.verse;
} else {
mergedRef.section.end.verse =
ref1.section.end.verse >= ref2.section.end.verse
? ref1.section.end.verse
: ref2.section.end.verse;
}
return mergedRef; return mergedRef;
} }
@ -2136,6 +2166,20 @@ export class BibleReference {
// get the starting book, chapter, verse // get the starting book, chapter, verse
return BibleReference.toString(this.section); return BibleReference.toString(this.section);
} }
public startIndex(): Number {
return BibleReference.locationToIndex(
this.section.book.bookNumber,
this.section.start
);
}
public endIndex(): Number {
return BibleReference.locationToIndex(
this.section.book.bookNumber,
this.section.end
);
}
} }
class StringUtils { class StringUtils {