-
-
Notifications
You must be signed in to change notification settings - Fork 27
Conversation
Summary
Major upgrade migrating from NEST (Elasticsearch.Net 7.x) to Elastic.Clients.Elasticsearch (official ES 8.x/9.x client). This is a breaking change release (v8.0) that replaces the entire Elasticsearch client layer and serialization stack.
Depends on FoundatioFx/Foundatio.Parsers#84
Core Changes
- Elasticsearch Client:
IElasticClient(NEST) ->ElasticsearchClient(Elastic.Clients.Elasticsearch) - Serialization: Newtonsoft.Json (
JToken/JObject) -> System.Text.Json (JsonNode/JsonElement) throughout - JsonPatch: Full port from Newtonsoft to System.Text.Json with RFC 6902 compliance
- Query DSL: All query builders ported from
QueryContainer/SearchDescriptortoQuery/SearchRequestDescriptor - Index Configuration: All mapping/settings APIs ported to new descriptor types
- Docker: Elasticsearch/Kibana images updated to 9.3.1
Breaking API Changes
All breaking changes are direct 1:1 type replacements required by the client migration:
| Old (NEST) | New (Elastic.Clients) |
|---|---|
IElasticClient |
ElasticsearchClient |
ConnectionSettings |
ElasticsearchClientSettings |
IConnectionPool |
NodePool |
QueryContainer |
Query |
SearchDescriptor |
SearchRequestDescriptor |
CreateIndexDescriptor |
CreateIndexRequestDescriptor |
JToken/JObject |
JsonNode/JsonObject |
Known Limitation: PartialPatch Cannot Set Fields to Null
This is a behavioral change from NEST. The DefaultSourceSerializer in Elastic.Clients.Elasticsearch sets JsonIgnoreCondition.WhenWritingNull by default, which means any property explicitly set to null in a PartialPatch document is silently stripped from the serialized JSON before it reaches Elasticsearch. The field retains its original value instead of being set to null.
await repository.PatchAsync(id, new PartialPatch(new { companyName = (string)null }));
Root cause: Decompiled source of DefaultSourceSerializerOptionsProvider.MutateOptions in Elastic.Clients.Elasticsearch 9.3.1 confirms this is intentional:
Why we cannot work around it globally: Setting JsonIgnoreCondition.Never on the SourceSerializer (the obvious fix) is not viable because:
- It causes all null properties on all documents to be serialized on every index/update operation, bloating payloads and potentially overwriting fields in multi-writer scenarios
- Some Elastic request types with
object-typed fields get routed through the SourceSerializer and fail withNever(as reported in the upstream issue) - Foundatio.Repositories is a library -- changing a global serializer default would silently affect all consumer documents
Upstream tracking: elastic/elasticsearch-net#8763 -- still open. We have commented on the issue with our specific use case.
Workarounds for consumers who need to set a field to null:
- Use
ScriptPatch:new ScriptPatch("ctx._source.companyName = null;") - Use
JsonPatch(RFC 6902):new JsonPatch(new PatchDocument(new ReplaceOperation { Path = "companyName", Value = null }))
A regression test (PartialPatchAsync_WithNullField_RetainsOriginalValue) documents this behavior and will flip automatically once the upstream issue is resolved.
Quality & Robustness Improvements
- Zero build warnings (down from 190): Fixed all xUnit1051, CS8002, AsyncFixer02 warnings
- 441 total tests passing (96 core + 345 ES integration, 0 skipped, 0 failed)
- All previously-skipped tests unskipped and passing (7 tests that were skipped on main have been fixed and re-enabled)
- Fixed query timeout format to use ES duration syntax (
30s) instead of .NET TimeSpan format - Fixed
DoubleSystemTextJsonConverter.Read()(was throwingNotImplementedException) - Added
NotSupportedExceptionfor JSONPath ($-prefixed) paths in patch operations with clear error message - Added null guard in
Operation.Build()for malformed patch JSON - Strict validation in
PatchDocument.Load()-- now throws on non-object elements - Fixed null-conditional constant conditions in
JsonDiffer,LoggerExtensions,ElasticReindexer - Fixed potential null dereferences in test assertions (split
Assert.NotNull(x?.Y)into proper two-step assertions) - Fixed
GetAliasIndexCountto only treat HTTP 404 as "no aliases" and throw on real failures - Added
PatchDocument.Add/Replaceconvenience overloads forstring,int,long,double,bool - Improved
RuntimeFieldsQueryBuildertest to verify builder output, not just input state - Removed all dead/commented-out code
- Passed
TestContext.Current.CancellationTokento all test async calls for proper cancellation support - Clean
dotnet format-- no unused usings or style issues - Made
ConfigureFoundatioRepositoryDefaults()idempotent to prevent duplicate converter registration - Fixed
TopHitsAggregate._hitsfield to initialize with empty list in parameterless constructor - Fixed
ElasticReindexer.CreateRangeQueryto usestartTime.ValueafterHasValueguard for explicit intent
Review Feedback Addressed
All github-code-quality and Copilot review comments have been resolved:
partsToCreateunused container removed (was already fixed in prior commit)- Constant condition warnings in
JsonDiffer.GetHashCodefixed with explicit null guard - Redundant null-conditional in
LoggerExtensions.LogRequestfixed startTime.Valuechanged inElasticReindexerfor explicit intent after null guardascasts replaced with direct casts in test assertions- Query timeout format fixed from
.ToString()to ES duration format Operation.Buildnull guard addedPatchDocument.Loadstrict validation addedGetAliasIndexCounterror handling improved- Stale NEST-style mapping syntax in docs updated to ES9 API
- Silent bucket type skip in
GetKeyedBucketsreplaced with explicit error
- Adapted DefaultSortQueryBuilder from NEST to new client (SortOptions pattern)
- Fixed Xunit.Abstractions -> Xunit namespace (xUnit v3 migration)
- Fixed Task -> ValueTask for InitializeAsync/DisposeAsync
- Removed ct: parameter from RefreshAsync (not in new client API)
- Adapted NestedFieldTests aggregation API to new client fluent pattern
- Took newer package versions from main (RandomData 2.0.1, Jint 4.6.0)
* Changes wildcard index resolution from `ResolveIndexAsync` to `GetAsync` to avoid an issue where the ES 9.x client sends a body that Elasticsearch rejects.
* Refines `Indices` parameter passing for delete operations using `Indices.Parse` or `Indices.Index`.
* Ensures `Reopen()` is invoked when updating index settings that necessitate it.
* Improves bulk operation reliability by checking `hit.IsValid` rather than specific status codes.
* Corrects reindex tests to account for `Version` (SeqNo/PrimaryTerm) not being preserved across reindex operations.
* Includes minor project file cleanup and type aliasing for improved readability.
Elastic 9 subbranch work.
src/Foundatio.Repositories.Elasticsearch/Queries/Builders/FieldConditionsQueryBuilder.cs
Fixed
Show fixed
Hide fixed
src/Foundatio.Repositories.Elasticsearch/Repositories/ElasticReindexer.cs
Fixed
Show fixed
Hide fixed
tests/Foundatio.Repositories.Elasticsearch.Tests/AggregationQueryTests.cs
Fixed
Show fixed
Hide fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Updates Foundatio.Repositories' Elasticsearch integration and supporting utilities/tests to use Elastic.Clients.Elasticsearch (System.Text.Json-based) instead of NEST/Elasticsearch.Net/Newtonsoft, aligning serialization, query building, and index/mapping APIs with the new client.
Changes:
- Migrate repository/query/index configuration code from NEST types (
IElasticClient,SearchDescriptor,QueryContainer, etc.) toElastic.Clients.Elasticsearchequivalents. - Convert JsonPatch implementation and related tests from Newtonsoft (
JToken) to System.Text.Json (JsonNode/Utf8JsonWriter). - Update test infrastructure/helpers and docker-compose to run against newer Elasticsearch/Kibana images; adjust versioning/build settings.
Reviewed changes
Copilot reviewed 104 out of 104 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Foundatio.Repositories.Tests/JsonPatch/JsonPatchTests.cs | Switch JsonPatch tests to System.Text.Json JsonNode and update serialization assertions. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/VersionedTests.cs | Update client usage and request/response validation for new Elasticsearch client. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/RepositoryTests.cs | Refresh calls updated for new client API. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/Repositories/Queries/EmailAddressQuery.cs | Replace NEST query DSL with Elastic.Clients.Elasticsearch.QueryDsl queries. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/Repositories/Queries/CompanyQuery.cs | Replace NEST term/terms queries with new client equivalents. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/Repositories/Queries/AgeQuery.cs | Replace NEST term/terms queries with new client equivalents. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/Repositories/ParentRepository.cs | Update parent-child discriminator assignment for new JoinField type. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/Repositories/Models/Parent.cs | Expose discriminator as public property and set JSON name for join field. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/Repositories/Models/Child.cs | Expose discriminator as public property and set JSON name for join field. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/Repositories/EmployeeWithCustomFieldsRepository.cs | Update missing-field filters to new query DSL. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/Repositories/EmployeeRepository.cs | Update missing-field filters to new query DSL. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/Repositories/Configuration/MyAppElasticConfiguration.cs | Replace connection pool/client setup with ElasticsearchClientSettings/NodePool. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/Repositories/Configuration/Indexes/ParentChildIndex.cs | Port index creation/mappings to new client descriptors and join mapping API. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/Repositories/Configuration/Indexes/MonthlyLogEventIndex.cs | Port create-index configuration to new descriptors. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/Repositories/Configuration/Indexes/MonthlyFileAccessHistoryIndex.cs | Port create-index configuration to new descriptors. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/Repositories/Configuration/Indexes/IdentityIndex.cs | Port mapping/configuration to new mapping types. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/Repositories/Configuration/Indexes/EmployeeWithCustomFieldsIndex.cs | Port complex mappings (aliases, nested/object props) to new mapping APIs. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/Repositories/Configuration/Indexes/EmployeeIndex.cs | Port employee mappings and versioned index hooks to new mapping APIs. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/Repositories/Configuration/Indexes/DailyLogEventIndex.cs | Port daily index mapping/config to new mapping APIs. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/Repositories/Configuration/Indexes/DailyFileAccessHistoryIndex.cs | Port create-index configuration to new descriptors. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/Repositories/Configuration/ElasticsearchJsonNetSerializer.cs | Disable old JsonNet serializer shim (kept as reference). |
| tests/Foundatio.Repositories.Elasticsearch.Tests/Repositories/ChildRepository.cs | Update parent-child discriminator assignment for new JoinField type. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/ReadOnlyRepositoryTests.cs | Adjust snapshot paging assertions and scroll cleanup for new client. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/QueryTests.cs | Update logging/options usage for queries. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/QueryBuilderTests.cs | Adjust runtime fields test for new request/runtime mapping behavior. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/ParentChildTests.cs | Ensure immediate consistency and adjust query logging for parent/child tests. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/NestedFieldTests.cs | Port nested aggregations API usage to new client aggregations builder. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/MigrationTests.cs | Refresh calls updated for new client API. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/Foundatio.Repositories.Elasticsearch.Tests.csproj | Remove NEST JsonNet serializer package reference. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/Extensions/ElasticsearchExtensions.cs | Update alias helpers for new client response shapes and add convenience methods. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/ElasticRepositoryTestBase.cs | Add wildcard index deletion helper compatible with ES destructive settings. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/CustomFieldTests.cs | Adjust custom field value assertions to handle JsonElement-backed values. |
| tests/Foundatio.Repositories.Elasticsearch.Tests/AggregationQueryTests.cs | Add/adjust aggregation tests for new client aggregation response conversion/roundtrips. |
| src/Foundatio.Repositories/Models/Aggregations/ObjectValueAggregate.cs | Support JsonNode/JsonElement values in aggregate value conversion. |
| src/Foundatio.Repositories/JsonPatch/TestOperation.cs | Port JsonPatch operation to System.Text.Json read/write. |
| src/Foundatio.Repositories/JsonPatch/ReplaceOperation.cs | Port JsonPatch operation to System.Text.Json read/write. |
| src/Foundatio.Repositories/JsonPatch/RemoveOperation.cs | Port JsonPatch operation to System.Text.Json read/write. |
| src/Foundatio.Repositories/JsonPatch/PatchDocumentConverter.cs | Implement System.Text.Json converter for PatchDocument. |
| src/Foundatio.Repositories/JsonPatch/PatchDocument.cs | Port PatchDocument model/serialization to System.Text.Json. |
| src/Foundatio.Repositories/JsonPatch/Operation.cs | Port operation base class to System.Text.Json writer/reader APIs. |
| src/Foundatio.Repositories/JsonPatch/MoveOperation.cs | Port JsonPatch operation to System.Text.Json read/write. |
| src/Foundatio.Repositories/JsonPatch/JsonPatcher.cs | Port patching engine to JsonNode, plus pointer navigation helpers. |
| src/Foundatio.Repositories/JsonPatch/JsonDiffer.cs | Port diff generation to JsonNode and System.Text.Json output. |
| src/Foundatio.Repositories/JsonPatch/CopyOperation.cs | Port JsonPatch operation to System.Text.Json read/write. |
| src/Foundatio.Repositories/JsonPatch/AddOperation.cs | Port JsonPatch operation to System.Text.Json read/write. |
| src/Foundatio.Repositories/Extensions/StringExtensions.cs | Remove ToJTokenPath helper (Newtonsoft-specific). |
| src/Foundatio.Repositories/Extensions/AggregationsExtensions.cs | Adjust keyed bucket extraction to handle multiple generic bucket key types. |
| src/Foundatio.Repositories.Elasticsearch/Repositories/MigrationStateRepository.cs | Port migration index mapping/config to new mapping/index descriptors. |
| src/Foundatio.Repositories.Elasticsearch/Repositories/IParentChildDocument.cs | Switch JoinField import to new client package. |
| src/Foundatio.Repositories.Elasticsearch/Repositories/ElasticReindexer.cs | Port reindex orchestration (tasks, aliases, failures) to new client APIs. |
| src/Foundatio.Repositories.Elasticsearch/Repositories/ElasticReadOnlyRepositoryBase.cs | Port search/mget/exists/scroll/async search flows to new client APIs. |
| src/Foundatio.Repositories.Elasticsearch/Queries/Builders/SortQueryBuilder.cs | Change sort handling to store sorts in context data for later application. |
| src/Foundatio.Repositories.Elasticsearch/Queries/Builders/SoftDeletesQueryBuilder.cs | Update has_parent query usage and parent type naming for new client. |
| src/Foundatio.Repositories.Elasticsearch/Queries/Builders/SearchAfterQueryBuilder.cs | Rework applying/reversing sorts + ID tiebreaker for search_after paging. |
| src/Foundatio.Repositories.Elasticsearch/Queries/Builders/RuntimeFieldsQueryBuilder.cs | Port runtime field mapping to RuntimeMappings dictionary model. |
| src/Foundatio.Repositories.Elasticsearch/Queries/Builders/ParentQueryBuilder.cs | Port has_parent query construction to new DSL. |
| src/Foundatio.Repositories.Elasticsearch/Queries/Builders/PageableQueryBuilder.cs | Port paging options to From/SearchAfter with FieldValue conversion. |
| src/Foundatio.Repositories.Elasticsearch/Queries/Builders/IdentityQueryBuilder.cs | Port ids query/exclude ids behavior to new DSL types. |
| src/Foundatio.Repositories.Elasticsearch/Queries/Builders/IElasticQueryBuilder.cs | Core query-builder context now uses Query + SearchRequestDescriptor. |
| src/Foundatio.Repositories.Elasticsearch/Queries/Builders/FieldIncludesQueryBuilder.cs | Port source includes/excludes to new SourceConfig/SourceFilter. |
| src/Foundatio.Repositories.Elasticsearch/Queries/Builders/FieldConditionsQueryBuilder.cs | Port term/terms/must_not/exists queries to new DSL with FieldValue. |
| src/Foundatio.Repositories.Elasticsearch/Queries/Builders/ExpressionQueryBuilder.cs | Store sorts in context data instead of applying directly to search descriptor. |
| src/Foundatio.Repositories.Elasticsearch/Queries/Builders/ElasticFilterQueryBuilder.cs | Change elastic filter option type from QueryContainer to Query. |
| src/Foundatio.Repositories.Elasticsearch/Queries/Builders/DefaultSortQueryBuilder.cs | Ensure default ID sort is always present (via context data). |
| src/Foundatio.Repositories.Elasticsearch/Queries/Builders/DateRangeQueryBuilder.cs | Port date range query properties to new names (Gte/Lte). |
| src/Foundatio.Repositories.Elasticsearch/Queries/Builders/ChildQueryBuilder.cs | Port has_child query construction to new DSL. |
| src/Foundatio.Repositories.Elasticsearch/Options/ElasticCommandOptions.cs | Switch Elasticsearch imports to new client package. |
| src/Foundatio.Repositories.Elasticsearch/Jobs/SnapshotJob.cs | Port snapshot creation/status polling to new snapshot APIs. |
| src/Foundatio.Repositories.Elasticsearch/Jobs/ReindexWorkItemHandler.cs | Port handler to accept ElasticsearchClient. |
| src/Foundatio.Repositories.Elasticsearch/Jobs/CleanupSnapshotJob.cs | Port snapshot listing/deletion to new snapshot APIs. |
| src/Foundatio.Repositories.Elasticsearch/Jobs/CleanupIndexesJob.cs | Port index enumeration/deletion to new indices APIs. |
| src/Foundatio.Repositories.Elasticsearch/Foundatio.Repositories.Elasticsearch.csproj | Normalize project file header/formatting (and supports other changes). |
| src/Foundatio.Repositories.Elasticsearch/Extensions/ResolverExtensions.cs | Port sort resolution from IFieldSort to SortOptions. |
| src/Foundatio.Repositories.Elasticsearch/Extensions/LoggerExtensions.cs | Port logging helpers to ElasticsearchResponse and new ApiCall details. |
| src/Foundatio.Repositories.Elasticsearch/Extensions/IBodyWithApiCallDetailsExtensions.cs | Update raw deserialization helper and add OriginalException() accessor. |
| src/Foundatio.Repositories.Elasticsearch/Extensions/FindHitExtensions.cs | Handle new sort value representation (FieldValue) and update reverse-sort logic. |
| src/Foundatio.Repositories.Elasticsearch/Extensions/ElasticLazyDocument.cs | Replace NEST LazyDocument reflection with new hit/source-based lazy deserialization. |
| src/Foundatio.Repositories.Elasticsearch/ElasticUtility.cs | Port snapshot/index listing and snapshot creation to new APIs. |
| src/Foundatio.Repositories.Elasticsearch/CustomFields/StandardFieldTypes/StringFieldType.cs | Update custom field mapping signature to PropertyFactory function. |
| src/Foundatio.Repositories.Elasticsearch/CustomFields/StandardFieldTypes/LongFieldType.cs | Update custom field mapping signature to PropertyFactory function. |
| src/Foundatio.Repositories.Elasticsearch/CustomFields/StandardFieldTypes/KeywordFieldType.cs | Update custom field mapping signature to PropertyFactory function. |
| src/Foundatio.Repositories.Elasticsearch/CustomFields/StandardFieldTypes/IntegerFieldType.cs | Update custom field mapping signature to PropertyFactory function. |
| src/Foundatio.Repositories.Elasticsearch/CustomFields/StandardFieldTypes/FloatFieldType.cs | Update custom field mapping signature to PropertyFactory function. |
| src/Foundatio.Repositories.Elasticsearch/CustomFields/StandardFieldTypes/DoubleFieldType.cs | Update custom field mapping signature to PropertyFactory function. |
| src/Foundatio.Repositories.Elasticsearch/CustomFields/StandardFieldTypes/DateFieldType.cs | Update custom field mapping signature to PropertyFactory function. |
| src/Foundatio.Repositories.Elasticsearch/CustomFields/StandardFieldTypes/BooleanFieldType.cs | Update custom field mapping signature to PropertyFactory function. |
| src/Foundatio.Repositories.Elasticsearch/CustomFields/ICustomFieldType.cs | Update mapping contract to return Func. |
| src/Foundatio.Repositories.Elasticsearch/CustomFields/CustomFieldDefinitionRepository.cs | Port mapping/index config and remove NEST-specific constructs. |
| src/Foundatio.Repositories.Elasticsearch/Configuration/VersionedIndex.cs | Port alias/index/mapping update flows to new indices/mapping APIs. |
| src/Foundatio.Repositories.Elasticsearch/Configuration/MonthlyIndex.cs | Port monthly index config/mapping to new APIs. |
| src/Foundatio.Repositories.Elasticsearch/Configuration/Index.cs | Port index lifecycle (create/update/delete/settings) to new APIs and wildcard delete handling. |
| src/Foundatio.Repositories.Elasticsearch/Configuration/IIndex.cs | Update settings/mapping method signatures for new client descriptors. |
| src/Foundatio.Repositories.Elasticsearch/Configuration/IElasticConfiguration.cs | Switch configuration client type to ElasticsearchClient. |
| src/Foundatio.Repositories.Elasticsearch/Configuration/ElasticConfiguration.cs | Port client creation/settings/pool types to new client. |
| src/Foundatio.Repositories.Elasticsearch/Configuration/DynamicIndex.cs | Port dynamic mapping configuration to new mapping API. |
| src/Foundatio.Repositories.Elasticsearch/Configuration/DailyIndex.cs | Port daily index creation/aliasing/mapping update flows to new APIs. |
| samples/Foundatio.SampleApp/Server/Repositories/Configuration/SampleAppElasticConfiguration.cs | Port sample app configuration to new client settings/pool types. |
| samples/Foundatio.SampleApp/Server/Repositories/Configuration/Indexes/GameReviewIndex.cs | Port sample index settings/mapping configuration to new APIs. |
| docker-compose.yml | Update Elasticsearch/Kibana images to 9.3.1. |
| build/common.props | Set MinVer minimum major/minor to 8.0. |
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
tests/Foundatio.Repositories.Elasticsearch.Tests/QueryBuilderTests.cs
Outdated
Show resolved
Hide resolved
tests/Foundatio.Repositories.Elasticsearch.Tests/AggregationQueryTests.cs
Show resolved
Hide resolved
(no external dep) and re-add 3 previously deleted JSONPath tests
- Re-add 3 pagination tests deleted during upgrade (no-duplicate paging)
- Enable TopHits aggregation round-trip for caching: serialize raw hit JSON
in new Hits property; update both JSON converters to handle tophits type
- Implement ElasticUtility stubs: WaitForTaskAsync, WaitForSafeToSnapshotAsync,
DeleteSnapshotsAsync, DeleteIndicesAsync, and complete CreateSnapshotAsync
- Fix Foundatio.Parsers.ElasticQueries package ref to published pre-release
so CI builds without source reference override
- Remove CA2264 no-op ThrowIfNull on non-nullable param in IElasticQueryBuilder
- Delete PipelineTests.cs and ElasticsearchJsonNetSerializer.cs (dead code)
- Update all docs to ES9 API: ConnectionPool, ConnectionSettings, ConfigureIndex
and ConfigureIndexMapping void return, property mapping syntax, IsValidResponse
- Add upgrading-to-es9.md migration guide with full breaking changes checklist
Made-with: Cursor
Adjusts build configuration to conditionally reference Foundatio.Repositories source.
Refines nullability checks in Elasticsearch logger extensions and improves JSON patch logic with better pattern matching, simplified path creation, and robust error handling for unknown operations.
Includes a fix for a test case ID assignment and adds a new test for runtime fields query builder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 120 out of 124 changed files in this pull request and generated 4 comments.
Files not reviewed (3)
- .idea/.idea.Foundatio.Repositories/.idea/indexLayout.xml: Language not supported
- .idea/.idea.Foundatio.Repositories/.idea/projectSettingsUpdater.xml: Language not supported
- .idea/.idea.Foundatio.Repositories/.idea/vcs.xml: Language not supported
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/Foundatio.Repositories.Elasticsearch/Repositories/ElasticReadOnlyRepositoryBase.cs
Outdated
Show resolved
Hide resolved
tests/Foundatio.Repositories.Elasticsearch.Tests/Extensions/ElasticsearchExtensions.cs
Outdated
Show resolved
Hide resolved
(JsonNode.DeepEquals) instead of raw string equality for TopHits encoding
- Replace TestContext.Current.CancellationToken with TestCancellationToken
- Replace all string concatenation (+) with string interpolation ($"")
- Add null guards, improve error handling for alias retrieval
- Fix constant condition warnings in LoggerExtensions and JsonDiffer
- Add convenience overloads for PatchDocument Add/Replace primitives
- Implement DoubleSystemTextJsonConverter.Read (was NotImplementedException)
- Add NotSupportedException for unsupported JSONPath in patch operations
- Validate patch array elements in PatchDocument.Load
- Remove dead code, unused imports, and commented-out routing call
- Suppress CS8002 for test-only GitHubActionsTestLogger dependency
- Simplify RuntimeFieldsQueryBuilder test to context-level assertions
Made-with: Cursor
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 123 out of 127 changed files in this pull request and generated 3 comments.
Files not reviewed (3)
- .idea/.idea.Foundatio.Repositories/.idea/indexLayout.xml: Language not supported
- .idea/.idea.Foundatio.Repositories/.idea/projectSettingsUpdater.xml: Language not supported
- .idea/.idea.Foundatio.Repositories/.idea/vcs.xml: Language not supported
Comments suppressed due to low confidence (1)
docs/guide/troubleshooting.md:63
- The troubleshooting guide shows
ElasticsearchClientSettingsbut still usessettings.BasicAuthentication(...), which is a NEST-era API. With Elastic.Transport, authentication is configured viasettings.Authentication(new BasicAuthentication(...))(or ApiKey/BearerToken equivalents). Update this snippet so readers can copy/paste working code.
**Solutions:**
```csharp
protected override void ConfigureSettings(ElasticsearchClientSettings settings)
{
// Basic authentication
settings.BasicAuthentication("username", "password");
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| _logger.LogInformation("Reindex Task Id: {TaskId}", result.Task.FullyQualifiedId); | ||
| if (result.Task == null) | ||
| { | ||
| _logger.LogError("Reindex failed to start - no task returned. Response valid: {IsValid}, Error: {Error}", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is {Error} the common name for this or is it Reason or Message, ensure we are consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Investigated: The codebase uses mixed naming -- {Error} for ES server error objects/strings, {Reason} for specific error reason fields, {Message} for exception messages. The usage here ({Error} for the error reason string) is consistent with the pattern in ElasticRepositoryBase.cs:880 and DailyIndex.cs:472. The template name matches what the value represents (the error details).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Investigated: The codebase convention is: {Error} for ES server error objects/strings (ElasticsearchServerError), {Reason} for specific error reason fields (Error.Reason), {Message} for exception messages (ex.Message). The usage at this line passes ElasticsearchServerError?.Error?.Reason which is extracting the reason string from the server error. Renamed the placeholder to {Reason} for consistency since it specifically references the Reason field. See commit 8869558.
- Rename tests to three-part naming convention (Method_State_Expected) and add
AAA (Arrange/Act/Assert) comments
- Extract timeout formatting to TimeSpan.ToElasticDuration() extension method
with 18 unit tests covering all time units and edge cases
- Add blank line before ctx.Search.Source() in FieldIncludesQueryBuilder
- Configure ES client source serializer with ConfigureFoundatioRepositoryDefaults() so IDictionary
- Replace manual retry loops in ElasticUtility with IResiliencePolicyProvider
- Use SerializerTestHelper in DoubleSystemTextJsonConverterTests for centralized config
- Fix ReindexTests ToJson to use ES client serializer for ES types (Properties)
- Remove redundant CreateElasticClient override in MyAppElasticConfiguration
- Remove .ToString() workarounds in CustomFieldTests now that source serializer is fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 142 out of 146 changed files in this pull request and generated 1 comment.
Files not reviewed (3)
- .idea/.idea.Foundatio.Repositories/.idea/indexLayout.xml: Language not supported
- .idea/.idea.Foundatio.Repositories/.idea/projectSettingsUpdater.xml: Language not supported
- .idea/.idea.Foundatio.Repositories/.idea/vcs.xml: Language not supported
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| byte b8 => FieldValue.Long(b8), | ||
| sbyte sb => FieldValue.Long(sb), | ||
| uint ui => FieldValue.Long(ui), | ||
| ulong ul => FieldValue.Long((long)ul), |
Copilot
AI
Mar 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Casting ulong to long will throw an OverflowException at runtime (in a checked context) or silently produce incorrect values (in an unchecked context) for values greater than long.MaxValue (9,223,372,036,854,775,807). Consider using FieldValue.Double((double)ul) as a fallback for large ulong values, or at minimum adding a bounds check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 142 out of 146 changed files in this pull request and generated no new comments.
Files not reviewed (3)
- .idea/.idea.Foundatio.Repositories/.idea/indexLayout.xml: Language not supported
- .idea/.idea.Foundatio.Repositories/.idea/projectSettingsUpdater.xml: Language not supported
- .idea/.idea.Foundatio.Repositories/.idea/vcs.xml: Language not supported
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Update `FieldValueHelper` to safely handle `ulong` values by falling back to `double` for values exceeding `long.MaxValue`
- Minor nullability fix in `IndexTests`
src/Foundatio.Repositories.Elasticsearch/Repositories/ElasticReindexer.cs
Fixed
Show fixed
Hide fixed
src/Foundatio.Repositories.Elasticsearch/Repositories/ElasticReindexer.cs
Fixed
Show fixed
Hide fixed
|
|
||
| if (!String.IsNullOrEmpty(timestampField)) | ||
| return descriptor.DateRange(dr => dr.Field(timestampField).GreaterThanOrEquals(startTime)); | ||
| return descriptor.Range(dr => dr.Date(drr => drr.Field(timestampField).Gte(startTime.Value))); |
| return descriptor.Range(dr => dr.Date(drr => drr.Field(timestampField).Gte(startTime.Value))); | ||
|
|
||
| return descriptor.TermRange(dr => dr.Field(ID_FIELD).GreaterThanOrEquals(ObjectId.GenerateNewId(startTime.Value).ToString())); | ||
| return descriptor.Range(dr => dr.Term(tr => tr.Field(ID_FIELD).Gte(ObjectId.GenerateNewId(startTime.Value).ToString()))); |
| // Assert | ||
| Assert.NotNull(lastEmployee); | ||
| Assert.NotNull(lastEmployee!.Id); | ||
| var retrieved = await repository.GetByIdAsync(lastEmployee.Id); |
# Conflicts:
# src/Foundatio.Repositories.Elasticsearch/Extensions/ElasticIndexExtensions.cs
# src/Foundatio.Repositories.Elasticsearch/Repositories/ElasticReadOnlyRepositoryBase.cs
Made-with: Cursor
Port of fix from main to feature/elastic-client. FieldConditionsQueryBuilder now resolves field names through the per-query QueryFieldResolver (set by OnCustomFieldsBeforeQuery) after ElasticMappingResolver, enabling custom field name resolution for all ComparisonOperator cases.
src/Foundatio.Repositories.Elasticsearch/Queries/Builders/FieldConditionsQueryBuilder.cs
Fixed
Show fixed
Hide fixed
src/Foundatio.Repositories.Elasticsearch/Queries/Builders/FieldConditionsQueryBuilder.cs
Fixed
Show fixed
Hide fixed
- FieldConditionsQueryBuilder consults QueryFieldResolver for custom fields
- ResolveFieldAsync ordering: resolve base -> custom resolver -> nonAnalyzed
- Null-value rewrites extended to Contains/NotContains
- Contains/NotContains use Operator.And for multi-term matching
- Null-safe dereferences and ternary expressions for Contains text
- Multi-document discrimination tests for all 6 operators
- Reversed token order tests for AND semantics
- Null-value Contains/NotContains rewrite tests
Preserved Elastic v8 client types (Query, FieldValue, TermsQueryField,
FieldValueHelper.ToFieldValue) throughout.
All 485 tests pass (374 ES + 111 core).
new Elasticsearch client branch:
- Resolve conflicts in ElasticRepositoryBase.cs and
ElasticReadOnlyRepositoryBase.cs
- Port all Newtonsoft JToken/JObject helpers to System.Text.Json.Nodes
(JsonNode/JsonObject/JsonValue) equivalents
- Port EmployeeWithDateMetaDataIndex from NEST to new client APIs
(CreateIndexRequestDescriptor, TypeMappingDescriptor, DynamicMapping)
- Remove duplicate Keyword(e => e.Id) mapping (already in SetupDefaults)
- Use ElasticsearchClientSettings.SourceSerializer (not ConnectionSettings)
- All 501 tests pass
- Replace magic strings "dateCreatedUtc"/"dateUpdatedUtc" in
EmployeeWithDateMetaDataIndex with nameof + JsonNamingPolicy.CamelCase
- Fix patch-operations.md reference to JToken (Newtonsoft) - JsonNode
9fca6da to
8cdff51
Compare