Skip to content

fix: support narrowing filters in fundamentals data (#57)#58

Open
alexpipipi wants to merge 2 commits into
masterfrom
fix/fundamentals-filter-shape
Open

fix: support narrowing filters in fundamentals data (#57)#58
alexpipipi wants to merge 2 commits into
masterfrom
fix/fundamentals-filter-shape

Conversation

@alexpipipi

@alexpipipi alexpipipi commented Jun 16, 2026

Copy link
Copy Markdown

Closes #57 (reported by @vlad-rob).

Problem

GetFundamentalDataAsync("AAPL.US", "Financials") returns a FundamentalData with every property null, while the unfiltered call is fully populated.

Root cause: the EODHD /fundamentals endpoint reshapes the response when a filter narrows below the top level:

filter response shape
(none) { General, Highlights, Financials, ... } ✅ maps to FundamentalData
General,Highlights { General, Highlights } ✅ maps
Financials { Balance_Sheet, Cash_Flow, Income_Statement } ❌ all FundamentalData props null
General { Code, Type, Name, ... }
General::Code "AAPL" (scalar) ❌

The method always deserialized into FundamentalData, so any narrowing filter produced an empty object.

Fix (backward compatible — no breaking changes)

Added two filter-aware overloads + matching interface members:

  • Task<T> GetFundamentalDataAsync<T>(ticker, filter) — deserialize into a caller-chosen type
  • Task<JToken> GetFundamentalDataRawAsync(ticker, filter) — return raw JSON for any shape (object/array/scalar)

The original GetFundamentalDataAsync is untouched; its XML doc now warns about the filter-reshaping and points to the new overloads.

Verification

Built with .NET SDK 8; live API tested through the compiled library:

  • GetFundamentalDataAsync("AAPL.US", "Financials")General == null (reproduces the bug)
  • GetFundamentalDataRawAsync("AAPL.US", "Financials") → JToken with Balance_Sheet populated ✅
  • GetFundamentalDataAsync<string>("AAPL.US", "General::Code")"AAPL"
  • GetFundamentalDataAsync("AAPL.US") (no filter) → still fully populated ✅

Added regression tests GetFundamentalDataRawAsyncTest_WithFilter and GetFundamentalDataAsyncGenericTest_ScalarFilter (both pass against the live API).


Update

  • Added API documentation on GetFundamentalDataAsync<T>: T must match the response shape for the chosen filter; use GetFundamentalDataRawAsync when the shape is unknown or varies.

GetFundamentalDataAsync(ticker, filter) always deserialized into the full
FundamentalData model. But when a filter narrows the response below the top
level (e.g. "Financials" or "General"), the API returns that inner
object/array/scalar instead of the {General, Financials, ...} shape — so
every property of the returned FundamentalData was null.

Added two filter-aware overloads (and the matching interface members):
- GetFundamentalDataAsync<T>(ticker, filter): deserialize into a caller type
- GetFundamentalDataRawAsync(ticker, filter): return a JToken for any shape
  (object/array/scalar)

The original typed method is unchanged; its XML doc now warns that narrowing
filters won't map to FundamentalData and points to the new overloads. Added
regression tests for both. Verified against the live API: filter=Financials
returns Balance_Sheet/Income_Statement via the raw method; filter=General::Code
returns the scalar "AAPL" via the generic method.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vlad-rob

Copy link
Copy Markdown

Do you plan publish new package version with this changes?

…lter shape (#57)

Follow-up to PR #58 review (Codex GPT-5.4 + Gemini Pro both flagged the generic
overload can throw on a T/shape mismatch). Adds an XML <remarks> pointing callers
to GetFundamentalDataRawAsync when the response shape is unknown/varies.
Comment-only; no behavior change. (dotnet not available locally — not built here.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Filters do not work in GetFundamentalDataAsync

2 participants