# EbookRepository

- File ID: file:veuxa3:ebookrepository-cs
- Path: NexusReader.Infrastructure/Persistence/EbookRepository.cs
- Role: repository
- Layer: infrastructure

## Purpose

EF Core implementation of the IEbookRepository providing data access for Ebook and Author entities; contains search, add and save operations with provider-specific behavior for case-insensitive author lookup.

## Key Details

Uses provider-aware case-insensitive matching (Postgres ILike vs ToLower fallback). Newly added ebooks are explicitly marked IsReadyForReading = false before being added to the context.

## Symbols

- EbookRepository: EF Core implementation of the IEbookRepository providing data access for Ebook and Author entities; contains search, add and save operations with provider-specific behavior for case-insensitive author lookup.
- EbookRepository(): Constructs the repository and stores the provided AppDbContext for later use.
- FindAuthorByNameAsync(): Finds an Author by name using a case-insensitive search; uses PostgreSQL ILike when running on Npgsql, otherwise falls back to ToLower string comparison.
- AddAuthor(): Adds a new Author entity to the DbContext for later persistence.
- AddEbook(): Prepares a new Ebook for persistence by setting readiness to false and adding it to the DbContext.
- SaveChangesAsync(): Saves tracked changes in the DbContext to the underlying database.
- EbookRepository: Concrete EF Core repository implementing IEbookRepository to manage Ebook and Author entities using AppDbContext.

## Dependencies

- imports NexusReader.Data/Persistence/AppDbContext.cs
- imports NexusReader.Application/Abstractions/Persistence/IEbookRepository.cs
- imports NexusReader.Domain/Entities/Author.cs
- imports NexusReader.Domain/Entities/Ebook.cs

## Calls

- No resolved calls.

## Unresolved References

- call-target: NexusReader.Data/Persistence/AppDbContext.cs
- call-target: NexusReader.Data/Persistence/AppDbContext.cs
- call-target: NexusReader.Data/Persistence/AppDbContext.cs
- call-target: NexusReader.Data/Persistence/AppDbContext.cs
- call-target: NexusReader.Data/Persistence/AppDbContext.cs
- interaction-target: public async Task<Author?> FindAuthorByNameAsync(string name, CancellationToken cancellationToken = default)
- interaction-target: _context.Ebooks.Add(ebook);

## Coverage

- Symbols: 7
- Executable symbols: 5
- Executable symbols with control flow: 5
- Grounded edges: 11
- Unresolved references: 7
- Control-flow fragments: 5
- Unresolved jumps: 5
- Unsupported constructs: 0
- Control-flow coverage: 100%
- Required diagrams: 2
- Generated diagrams: 6

## Control Flow Fragments

- EbookRepository: 3 nodes, 2 edges, 0 jumps, 0 unsupported constructs
- FindAuthorByNameAsync: 18 nodes, 19 edges, 2 jumps, 0 unsupported constructs
- AddAuthor: 4 nodes, 3 edges, 1 jumps, 0 unsupported constructs
- AddEbook: 6 nodes, 5 edges, 1 jumps, 0 unsupported constructs
- SaveChangesAsync: 4 nodes, 3 edges, 1 jumps, 0 unsupported constructs

## Diagrams

### EbookRepository Neighborhood

```mermaid
flowchart LR
    class_frxocr_ebookrepository("EbookRepository")
    file_veuxa3_ebookrepository_cs("EbookRepository")
    method_101vezb_findauthorbynameasync[["FindAuthorByNameAsync()"]]
    method_13rxvog_ebookrepository[["EbookRepository()"]]
    method_1dgp7fr_addauthor[["AddAuthor()"]]
    method_vkortc_addebook[["AddEbook()"]]
    method_xqcyw0_savechangesasync[["SaveChangesAsync()"]]
    file_1hlb3r7_iebookrepository_cs[/"IEbookRepository"/]
    file_1pacvtg_appdbcontext_cs[/"AppDbContext"/]
    file_1y56eud_author_cs[/"Author"/]
    file_lcvwj6_ebook_cs[/"Ebook"/]
    type_14vwagc_ebookrepository[/"EbookRepository"/]
    file_veuxa3_ebookrepository_cs -->|IEbookRepository| file_1hlb3r7_iebookrepository_cs
    file_veuxa3_ebookrepository_cs -->|AppDbContext| file_1pacvtg_appdbcontext_cs
    file_veuxa3_ebookrepository_cs -->|Author| file_1y56eud_author_cs
    file_veuxa3_ebookrepository_cs -->|Ebook| file_lcvwj6_ebook_cs
```

### EbookRepository Execution Overview

```mermaid
flowchart TD
    class_frxocr_ebookrepository("EbookRepository")
    method_101vezb_findauthorbynameasync[["FindAuthorByNameAsync()"]]
    method_13rxvog_ebookrepository[["EbookRepository()"]]
    method_1dgp7fr_addauthor[["AddAuthor()"]]
    method_vkortc_addebook[["AddEbook()"]]
    method_xqcyw0_savechangesasync[["SaveChangesAsync()"]]
    unresolved_unresolved_1a8t80g_call_target{"Unresolved: Authors.FirstOrDefaultAsync (Npgsql branch)"}
    unresolved_unresolved_1bci86y_interaction_target{"Unresolved: public async Task<Author?> FindAuthorByNameAsync(string name, CancellationToken cancellationToken = default)"}
    unresolved_unresolved_1ks8yhx_interaction_target{"Unresolved: _context.Ebooks.Add(ebook);"}
    unresolved_unresolved_1ob3ud7_call_target{"Unresolved: Ebooks.Add"}
    unresolved_unresolved_1suxvrt_call_target{"Unresolved: Authors.Add"}
    unresolved_unresolved_aftwfz_call_target{"Unresolved: SaveChangesAsync"}
    unresolved_unresolved_ged6nf_call_target{"Unresolved: Authors.FirstOrDefaultAsync (fallback)"}
    class_frxocr_ebookrepository -->|contains| method_101vezb_findauthorbynameasync
    class_frxocr_ebookrepository -->|contains| method_13rxvog_ebookrepository
    class_frxocr_ebookrepository -->|contains| method_1dgp7fr_addauthor
    class_frxocr_ebookrepository -->|contains| method_vkortc_addebook
    class_frxocr_ebookrepository -->|contains| method_xqcyw0_savechangesasync
    class_frxocr_ebookrepository -->|unresolved interaction| unresolved_unresolved_1bci86y_interaction_target
    class_frxocr_ebookrepository -->|unresolved interaction| unresolved_unresolved_1ks8yhx_interaction_target
    method_101vezb_findauthorbynameasync -->|unresolved call| unresolved_unresolved_1a8t80g_call_target
    method_101vezb_findauthorbynameasync -->|unresolved call| unresolved_unresolved_ged6nf_call_target
    method_1dgp7fr_addauthor -->|unresolved call| unresolved_unresolved_1suxvrt_call_target
    method_vkortc_addebook -->|unresolved call| unresolved_unresolved_1ob3ud7_call_target
    method_xqcyw0_savechangesasync -->|unresolved call| unresolved_unresolved_aftwfz_call_target
```

### FindAuthorByNameAsync() Control Flow

```mermaid
flowchart TD
    method_101vezb_findauthorbynameasync__call_29_Authors_FirstOrDefaultAsync_Npgsql_branch_[["Authors.FirstOrDefaultAsync (Npgsql branch)"]]
    method_101vezb_findauthorbynameasync__call_33_Authors_FirstOrDefaultAsync_fallback_[["Authors.FirstOrDefaultAsync (fallback)"]]
    method_101vezb_findauthorbynameasync__action_26_branch_26__condition{"_context.Database.IsNpgsql()"}
    method_101vezb_findauthorbynameasync__action_26_branch_26__false("use ToLower fallback")
    method_101vezb_findauthorbynameasync__action_26_branch_26__merge("merge")
    method_101vezb_findauthorbynameasync__action_26_branch_26__true("use ILike (Postgres)")
    method_101vezb_findauthorbynameasync__action_26_findauthorbynameasync_branch_26_1__condition{"_context.Database.IsNpgsql()"}
    method_101vezb_findauthorbynameasync__action_26_findauthorbynameasync_branch_26_1__false("false")
    method_101vezb_findauthorbynameasync__action_26_findauthorbynameasync_branch_26_1__merge("merge")
    method_101vezb_findauthorbynameasync__action_26_findauthorbynameasync_branch_26_1__true("true")
    method_101vezb_findauthorbynameasync__action_28_external_query_28__linear("Query Authors DbSet")
    method_101vezb_findauthorbynameasync__action_28_findauthorbynameasync_await_28_2__await[["Waits for async work"]]
    method_101vezb_findauthorbynameasync__action_32_findauthorbynameasync_await_32_4__await[["Waits for async work"]]
    method_101vezb_findauthorbynameasync__entry(["FindAuthorByNameAsync entry"])
    method_101vezb_findauthorbynameasync__action_22_findauthorbynameasync_repository_read_22_0__linear[("Reads repository or persistence state")]
    method_101vezb_findauthorbynameasync__action_28_findauthorbynameasync_return_28_3__return(["Returns result"])
    method_101vezb_findauthorbynameasync__action_32_findauthorbynameasync_return_32_5__return(["Returns result"])
    method_101vezb_findauthorbynameasync__implicit_return(["return"])
    method_101vezb_findauthorbynameasync__action_22_findauthorbynameasync_repository_read_22_0__linear -->|next| method_101vezb_findauthorbynameasync__action_26_branch_26__condition
    method_101vezb_findauthorbynameasync__action_26_branch_26__condition -->|use ToLower fallback| method_101vezb_findauthorbynameasync__action_26_branch_26__false
    method_101vezb_findauthorbynameasync__action_26_branch_26__condition -->|use ILike Postgres| method_101vezb_findauthorbynameasync__action_26_branch_26__true
    method_101vezb_findauthorbynameasync__action_26_branch_26__false -->|next| method_101vezb_findauthorbynameasync__action_26_branch_26__merge
    method_101vezb_findauthorbynameasync__action_26_branch_26__merge -->|next| method_101vezb_findauthorbynameasync__action_26_findauthorbynameasync_branch_26_1__condition
    method_101vezb_findauthorbynameasync__action_26_branch_26__true -->|next| method_101vezb_findauthorbynameasync__action_26_branch_26__merge
    method_101vezb_findauthorbynameasync__action_26_findauthorbynameasync_branch_26_1__condition -->|false| method_101vezb_findauthorbynameasync__action_26_findauthorbynameasync_branch_26_1__false
    method_101vezb_findauthorbynameasync__action_26_findauthorbynameasync_branch_26_1__condition -->|true| method_101vezb_findauthorbynameasync__action_26_findauthorbynameasync_branch_26_1__true
    method_101vezb_findauthorbynameasync__action_26_findauthorbynameasync_branch_26_1__false -->|next| method_101vezb_findauthorbynameasync__action_26_findauthorbynameasync_branch_26_1__merge
    method_101vezb_findauthorbynameasync__action_26_findauthorbynameasync_branch_26_1__merge -->|next| method_101vezb_findauthorbynameasync__action_28_findauthorbynameasync_await_28_2__await
    method_101vezb_findauthorbynameasync__action_26_findauthorbynameasync_branch_26_1__true -->|next| method_101vezb_findauthorbynameasync__action_26_findauthorbynameasync_branch_26_1__merge
    method_101vezb_findauthorbynameasync__action_28_external_query_28__linear -->|predicate using EF.Functions.ILike a.Name, name, cancellationToken| method_101vezb_findauthorbynameasync__call_29_Authors_FirstOrDefaultAsync_Npgsql_branch_
    method_101vezb_findauthorbynameasync__action_28_findauthorbynameasync_await_28_2__await -->|return| method_101vezb_findauthorbynameasync__action_28_findauthorbynameasync_return_28_3__return
    method_101vezb_findauthorbynameasync__action_28_findauthorbynameasync_return_28_3__return -->|next| method_101vezb_findauthorbynameasync__action_28_external_query_28__linear
    method_101vezb_findauthorbynameasync__action_32_findauthorbynameasync_await_32_4__await -->|return| method_101vezb_findauthorbynameasync__action_32_findauthorbynameasync_return_32_5__return
    method_101vezb_findauthorbynameasync__action_32_findauthorbynameasync_return_32_5__return -->|predicate using a.Name.ToLower == name.ToLower , cancellationToken| method_101vezb_findauthorbynameasync__call_33_Authors_FirstOrDefaultAsync_fallback_
    method_101vezb_findauthorbynameasync__call_29_Authors_FirstOrDefaultAsync_Npgsql_branch_ -->|next| method_101vezb_findauthorbynameasync__action_32_findauthorbynameasync_await_32_4__await
    method_101vezb_findauthorbynameasync__call_33_Authors_FirstOrDefaultAsync_fallback_ -->|return| method_101vezb_findauthorbynameasync__implicit_return
    method_101vezb_findauthorbynameasync__entry -->|next| method_101vezb_findauthorbynameasync__action_22_findauthorbynameasync_repository_read_22_0__linear
```

### AddAuthor() Control Flow

```mermaid
flowchart TD
    method_1dgp7fr_addauthor__call_39_Authors_Add[["Authors.Add"]]
    method_1dgp7fr_addauthor__action_39_persistence_write_39__linear("Stage Author for insert")
    method_1dgp7fr_addauthor__entry(["AddAuthor entry"])
    method_1dgp7fr_addauthor__implicit_return(["return"])
    method_1dgp7fr_addauthor__action_39_persistence_write_39__linear -->|author| method_1dgp7fr_addauthor__call_39_Authors_Add
    method_1dgp7fr_addauthor__call_39_Authors_Add -->|return| method_1dgp7fr_addauthor__implicit_return
    method_1dgp7fr_addauthor__entry -->|next| method_1dgp7fr_addauthor__action_39_persistence_write_39__linear
```

### AddEbook() Control Flow

```mermaid
flowchart TD
    method_vkortc_addebook__call_46_Ebooks_Add[["Ebooks.Add"]]
    method_vkortc_addebook__action_45_state_change_45__linear("Clear readiness flag")
    method_vkortc_addebook__action_46_persistence_write_46__linear("Stage Ebook for insert")
    method_vkortc_addebook__entry(["AddEbook entry"])
    method_vkortc_addebook__action_46_addebook_repository_write_46_0__linear[("Writes repository or persistence state")]
    method_vkortc_addebook__implicit_return(["return"])
    method_vkortc_addebook__action_45_state_change_45__linear -->|next| method_vkortc_addebook__action_46_addebook_repository_write_46_0__linear
    method_vkortc_addebook__action_46_addebook_repository_write_46_0__linear -->|next| method_vkortc_addebook__action_46_persistence_write_46__linear
    method_vkortc_addebook__action_46_persistence_write_46__linear -->|ebook| method_vkortc_addebook__call_46_Ebooks_Add
    method_vkortc_addebook__call_46_Ebooks_Add -->|return| method_vkortc_addebook__implicit_return
    method_vkortc_addebook__entry -->|next| method_vkortc_addebook__action_45_state_change_45__linear
```

### SaveChangesAsync() Control Flow

```mermaid
flowchart TD
    method_xqcyw0_savechangesasync__call_51_SaveChangesAsync[["SaveChangesAsync"]]
    method_xqcyw0_savechangesasync__action_51_persistence_commit_51__linear("Persist staged changes")
    method_xqcyw0_savechangesasync__entry(["SaveChangesAsync entry"])
    method_xqcyw0_savechangesasync__implicit_return(["return"])
    method_xqcyw0_savechangesasync__action_51_persistence_commit_51__linear -->|cancellationToken| method_xqcyw0_savechangesasync__call_51_SaveChangesAsync
    method_xqcyw0_savechangesasync__call_51_SaveChangesAsync -->|return| method_xqcyw0_savechangesasync__implicit_return
    method_xqcyw0_savechangesasync__entry -->|next| method_xqcyw0_savechangesasync__action_51_persistence_commit_51__linear
```

## Diagram Validation

- Status: warn
- Warning: Control-flow extraction left 5 unresolved jumps.
