Skip to content

Commit

Permalink
added JSON DTO BibleBook converter
Browse files Browse the repository at this point in the history
  • Loading branch information
danzuep committed Nov 18, 2023
1 parent 4b6ac0b commit 9a3acad
Show file tree
Hide file tree
Showing 12 changed files with 299 additions and 85 deletions.
51 changes: 19 additions & 32 deletions Bible.Core/Models/BibleBook.cs
Original file line number Diff line number Diff line change
@@ -1,50 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace Bible.Core.Models
{
public class BibleBook : IComparable<BibleBook>
public class BibleBook : IComparable<BibleBook>, IEquatable<BibleBook>
{
private static int _createdOrder;
private readonly int _order;

/// <summary>
/// Bible book constructor.
/// </summary>
/// <param name="bookName">Book name</param>
/// <param name="bibleVersion">Bible version</param>
/// <param name="aliases">Alternative names</param>
/// <param name="reference">Translation and book name</param>
/// <param name="content">Book content</param>
internal BibleBook(string bookName, string bibleVersion, IEnumerable<string> aliases, BookContent content)
public BibleBook(BibleReference reference, IEnumerable<BibleChapter> chapters)
{
_order = _createdOrder++;
Name = bookName;
Version = bibleVersion;
Aliases = aliases;
Content = content;
Reference = reference;
Chapters = chapters.ToArray();
}

/// <summary>
/// Version of the bible used.
/// </summary>
public string Version { get; }
public BibleReference Reference { get; set; } = default!;

/// <summary>
/// Unabreviated name of the book.
/// </summary>
public string Name { get; }
public int BookNumber { get; set; }

/// <summary>
/// Abreviated names or common mis-spellings of the book.
/// Standard abbreviations and Thompson Chain references pulled from the 5th edition
/// of "The Christian Writer's Manual of Style", 2004 edition (ISBN: 9780310487715).
/// Chapters and verses.
/// </summary>
public IEnumerable<string> Aliases { get; set; }
public IReadOnlyList<BibleChapter> Chapters { get; }

/// <summary>
/// Chapters and verses.
/// Number of chapters.
/// </summary>
public BookContent Content { get; }
public int ChapterCount => Chapters.Count;

/// <summary>
/// Determines whether two objects are equal.
Expand All @@ -59,7 +48,7 @@ private static bool EqualityTest(BibleBook book1, BibleBook book2)
return true;

// one is null, but not both
if (book1 == null || book2 == null)
if (book1 is null || book2 is null)
return false;

return book1.Equals(book2);
Expand All @@ -78,22 +67,20 @@ private static bool EqualityTest(BibleBook book1, BibleBook book2)
public static bool operator != (BibleBook book1, BibleBook book2) =>
!EqualityTest(book1, book2);

public bool Equals(BibleBook? other) =>
other is BibleBook b && b.Reference.Equals(Reference);

public override bool Equals(object other) =>
other is BibleBook b && (b.Version, b.Name).Equals((Version, Name));
other is BibleBook b && b.Reference.Equals(Reference);

/// <inheritdoc cref="IComparable" />
public int CompareTo(BibleBook other) =>
_order.CompareTo(other._order);

public override int GetHashCode() =>
(Version, Name).GetHashCode();
Reference.GetHashCode();

public override string ToString() =>
$"{Name} ({Content.ChapterCount} Chapters)";

public bool Equals(BibleBook other)
{
throw new NotImplementedException();
}
$"{Reference} ({ChapterCount} Chapters)";
}
}
22 changes: 22 additions & 0 deletions Bible.Core/Models/BibleChapter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.Collections.Generic;

namespace Bible.Core.Models
{
public class BibleChapter
{
public BibleReference Reference { get; set; } = default!;

public int ChapterNumber { get; set; }

public IReadOnlyList<BibleVerse> Verses { get; set; } = default!;

public override bool Equals(object other) =>
other is BibleChapter p && p.Reference.Equals(Reference);

public override int GetHashCode() =>
Reference.GetHashCode();

public override string ToString() =>
Reference.ToString();
}
}
47 changes: 43 additions & 4 deletions Bible.Core/Models/BibleReference.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,50 @@
namespace Bible.Core.Models
using System.Collections.Generic;

namespace Bible.Core.Models
{
public class BibleReference
{
public string Book { get; set; } = string.Empty;
public BibleReference() { }

public BibleReference(BibleReference bibleReference)
{
Translation = bibleReference.Translation;
BookName = bibleReference.BookName;
Aliases = bibleReference.Aliases;
Reference = bibleReference.Reference;
}

/// <summary>
/// Version of the bible used.
/// </summary>
public string Translation { get; set; } = default!;

/// <summary>
/// Unabreviated name of the book.
/// </summary>
public string BookName { get; set; } = default!;

/// <summary>
/// Abreviated or alternative names of the book.
/// </summary>
public IReadOnlyList<string>? Aliases { get; set; }

/// <summary>
/// Optional chapter and verse reference.
/// </summary>
public string? Reference { get; set; }

public override bool Equals(object other) => other is BibleReference p &&
(p.Translation, p.BookName, p.Reference).Equals((Translation, BookName, Reference));

public int Chapter { get; set; } = 1;
public override int GetHashCode() =>
(Translation, BookName, Reference).GetHashCode();

public int[]? Verses { get; set; }
public override string ToString()
{
if (string.IsNullOrEmpty(Reference))
return $"{BookName} ({Translation})";
return $"{BookName} {Reference} {Translation}";
}
}
}
20 changes: 20 additions & 0 deletions Bible.Core/Models/BibleVerse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace Bible.Core.Models
{
public class BibleVerse
{
public BibleReference Reference { get; set; } = default!;

public int VerseNumber { get; set; }

public string Text { get; set; } = default!;

public override bool Equals(object other) =>
other is BibleVerse p && p.Reference.Equals(Reference);

public override int GetHashCode() =>
Reference.GetHashCode();

public override string ToString() =>
$"\"{Text}\" {Reference}";
}
}
22 changes: 0 additions & 22 deletions Bible.Core/Models/BookContent.cs

This file was deleted.

73 changes: 55 additions & 18 deletions Bible.Data.Tests/BibleBookServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,31 @@ public async Task GetBibleBooksFromFileAsync_WithJsonFilePath_ReturnsBibleBooks(
Assert.Equal(abbreviation, result.Abbreviation);
}

[Theory]
[InlineData("Genesis", 50)]
[InlineData("Exodus", 40)]
public async Task GetBibleBookFromFileAsync_WithJsonFilePath_ReturnsConvertedBibleBooks(string bookName, int chapterCount)
{
var jsonFilePath = GetJsonFilePath("kjv");
var bible = await SerializerService.GetFromFileAsync<IReadOnlyList<SimpleBibleBookJson>>(jsonFilePath) ?? [];
var books = bible.Select(b => b.GetBibleBook("KJV"));
var book = books.FirstOrDefault(book => book.Reference.BookName == bookName);
Assert.NotNull(book);
Assert.Equal(chapterCount, book.ChapterCount);
}

[Theory]
[InlineData("Jesus", 943)]
public async Task SearchBibleAsync_WithJsonFilePath_ReturnsVerses(string searchQuery, int expectedCount)
{
var jsonFilePath = GetJsonFilePath("kjv");
var bible = await SerializerService.GetFromFileAsync<IReadOnlyList<SimpleBibleBookJson>>(jsonFilePath) ?? [];
var books = bible.Select(b => b.GetBibleBook("KJV"));
var verses = await books.SearchBibleAsync(searchQuery);
Assert.NotNull(verses);
Assert.Equal(expectedCount, verses.Count);
}

[Theory]
[InlineData(BibleBookIndex.SecondCorinthians, 1, 3)]
public async Task GetBibleBooksFromFileAsync_WithJsonFilePath_ReturnsBibleBook(BibleBookIndex book, int chapter, int verse)
Expand Down Expand Up @@ -74,21 +99,49 @@ public async Task GetVersionsFromFileAsync_WithJsonFilePath_ReturnsBibleVersions
Assert.True(bible.GetValueOrDefault("WEBUS") == 206);
}

[Theory]
[InlineData("1 John 4:7", "webbe", "love one another")]
public async Task GetVerseAsync_WithUrlPath_ReturnsJson(string reference, string translation, string expected)
{
using var httpClient = new HttpClient();
var query = $"{Constants.BibleWebEndpointBibleApi}{reference}?translation={translation}";
var stream = await httpClient.GetStreamAsync(query);
var verse = await SerializerService.GetPropertyFromStreamAsync(stream); // ~1.1s
Assert.NotNull(verse);
Assert.Contains(expected, verse);
}

[Theory]
[InlineData("1John", "4", "7", "love one another")]
public async Task GetBibleBookAsync_WithUrlPath_ReturnsJsonBibleBook(string book, string chapter, string verse, string expected)
{
var query = $"{Constants.RawGitHubUserContentBibleKjvPath}{book}.json";
var response = await _httpClient.GetFromJsonAsync<SimpleBookJson>(query); // ~0.5s
Assert.NotNull(response?.Book);
var chapterIndex = int.Parse(chapter) - 1;
var chapterResponse = response.Chapters[chapterIndex];
Assert.Equal(chapter, chapterResponse.Chapter);
var verseIndex = int.Parse(verse) - 1;
var verseResponse = chapterResponse.Verses[verseIndex];
Assert.Equal(verse, verseResponse.Verse);
Assert.Contains(expected, verseResponse.Text);
}

[Theory]
[InlineData("Romans", "12", "1", "web", "living sacrifice")]
public async Task GetBibleFromJsonAsync_WithUrlPath_ReturnsBible(string book, string chapter, string verse, string version, string expected)
{
using var httpClient = new HttpClient { BaseAddress = new Uri(Constants.BibleWebEndpointSuperSearch) };
var query = $"api?bible={version}&reference={book}+{chapter}:{verse}";
var response = await httpClient.GetFromJsonAsync<BibleReferenceJsonResponse>(query); // ~1.3s
var response = await httpClient.GetFromJsonAsync<BibleReferenceResponseJson>(query); // ~1.3s
Assert.NotNull(response);
var result0 = response.Results[0];
Assert.Equal(book, result0.BookName);
var text = result0.Verses[version][chapter][verse].Text;
Assert.Contains(expected, text);
}

[Theory]
[Theory(Skip = "API key required.")]
[InlineData(Constants.BibleYouVersionWebbeId, "ROM.12.1")]
public async Task GetBibleBooksAsync_WithUrlPath_ReturnsBible(string bibleId, string verseId)
{
Expand All @@ -100,22 +153,6 @@ public async Task GetBibleBooksAsync_WithUrlPath_ReturnsBible(string bibleId, st
Assert.Equal(verseId, response.Data.Id);
}

[Theory]
[InlineData("1John", "4", "7")]
public async Task GetBibleBookAsync_WithUrlPath_ReturnsJsonBibleBook(string book, string chapter, string verse)
{
var query = $"{Constants.RawGitHubUserContentBibleKjvPath}{book}.json";
var response = await _httpClient.GetFromJsonAsync<SimpleBookJson>(query); // ~0.5s
Assert.NotNull(response?.Book);
var chapterIndex = int.Parse(chapter) - 1;
var chapterResponse = response.Chapters[chapterIndex];
Assert.Equal(chapter, chapterResponse.Chapter);
var verseIndex = int.Parse(verse) - 1;
var verseResponse = chapterResponse.Verses[verseIndex];
Assert.Equal(verse, verseResponse.Verse);
Assert.NotNull(verseResponse.Text);
}

[Theory(Skip = "Takes too long (~2.8s).")]
[InlineData("eng-gb-webbe.usfx.xml", "GEN", "1", "1")]
public async Task GetBibleAsync_WithUrlPath_ReturnsXmlBible(string fileName, string bookId, string chapter, string verse)
Expand Down
5 changes: 4 additions & 1 deletion Bible.Data/Bible.Data.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
</AssemblyAttribute>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Bible.Core\Bible.Core.csproj" />
</ItemGroup>

<ItemGroup>
<!--https://github.com/Glowstudent777/YouVersion-API/blob/main/src/api/v1/db/books.json-->
<None Update="Json\books.json">
Expand All @@ -21,7 +25,6 @@
<None Update="Json\endpoints.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<!--https://github.com/aruljohn/Bible-kjv-->
<!--https://github.com/king-Alex-d-great/BibleIndexer-v2/blob/master/BibleIndexerV2/Data/books.json-->
<None Update="Json\kjv.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
Expand Down
10 changes: 7 additions & 3 deletions Bible.Data/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
public const string BibleWebEndpointYouVersion2 = "https://www.bible.com/en/bible/1/";
public const string BibleWebEndpointYouVersion3 = "https://www.bible.com/bible/1204/";
public const string BibleWebEndpointSuperSearch = "https://api.biblesupersearch.com/";
public const string BibleWebEndpoint04 = "https://bible-api.com/";
public const string BibleWebEndpointBibleApi = "https://bible-api.com/";
public const string BibleWebEndpoint05 = "http://labs.bible.org/api/";
public const string BibleWebEndpoint06 = "https://api.getbible.net/v2/";
public const string BibleWebEndpoint07 = "https://bible.sonnylab.com/";
Expand All @@ -13,10 +13,14 @@
public const string BibleWebEndpoint11 = "https://english.global.bible/bible";
public const string BibleWebEndpoint12 = "https://www.biblica.com/bible/";
public const string RawGitHubUserContentWebEndpoint = "https://raw.githubusercontent.com/";
// https://github.com/aruljohn/Bible-kjv/
public const string RawGitHubUserContentBibleKjvPath = "aruljohn/Bible-kjv/master/";
// https://github.com/seven1m/open-bibles/ (source files for https://bible-api.com/)
public const string RawGitHubUserContentOpenBiblesPath = "seven1m/open-bibles/master/";
public const string BibleWebEndpointKjv2 = "https://github.com/aruljohn/Bible-kjv";
//"https://bible4u.net/static/bible_files/xml/WEB_xml.zip" //https://hackathon.bible/data/
// https://github.com/king-Alex-d-great/BibleIndexer-v2/blob/master/BibleIndexerV2/Data/books.json
public const string RawGitHubUserContentBibleKjvAltPath = "king-Alex-d-great/BibleIndexer-v2/master/BibleIndexerV2/Data/books.json";
// List of data sources: https://hackathon.bible/data/
// XML file: "https://bible4u.net/static/bible_files/xml/WEB_xml.zip"
public static readonly string BibleAppEndpoint = "youversion://bible?reference=";
internal static readonly string BibleYouVersionApiKey = "YOUR_KEY_GOES_HERE";
internal const string BibleYouVersionWebId = "9879dbb7cfe39e4d-01";
Expand Down
Loading

0 comments on commit 9a3acad

Please sign in to comment.