Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 20 additions & 15 deletions docs/limitations.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,19 @@ request is sent.

See [Supported Operators](querying/operators.md) for the full list of what does translate.

| Category | Operators | Why |
| --------------------------------------- | ---------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| Aggregation | `Count`, `LongCount`, `Sum`, `Average`, `Min`, `Max` | DynamoDB PartiQL has no aggregate functions |
| Grouping | `GroupBy` | `GROUP BY` is not supported in DynamoDB PartiQL |
| Joins | `Join`, `GroupJoin`, `LeftJoin`, `RightJoin`, `SelectMany`, `DefaultIfEmpty` | DynamoDB does not support cross-item joins |
| Set operations | `Union`, `Concat`, `Except`, `Intersect` | Not supported in DynamoDB PartiQL |
| Offset / paging | `Skip`, `Take`, `ElementAt`, `ElementAtOrDefault` | DynamoDB has no offset semantics — use `Limit(n)` for an evaluation budget |
| Element operators | `Any`, `All` | Not supported server-side |
| Reverse traversal | `Last`, `LastOrDefault`, `Reverse` | Requires reverse index traversal, not implemented |
| Deduplication | `Distinct` | `SELECT DISTINCT` is not supported in DynamoDB PartiQL |
| Type filtering | `OfType<T>`, `Cast<T>` | Not supported |
| Conditional skipping | `SkipWhile`, `TakeWhile` | Not supported |
| Queryable `Contains` over query sources | `Queryable.Contains(dbSet, item)` | Not supported; in-memory membership translates to `IN`, native collection membership to `contains` |
| Category | Operators | Why |
| --------------------------------------- | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Aggregation | `Count`, `LongCount`, `Sum`, `Average`, `Min`, `Max` | DynamoDB PartiQL has no aggregate functions |
| Grouping | `GroupBy` | `GROUP BY` is not supported in DynamoDB PartiQL |
| Joins | `Join`, `GroupJoin`, `LeftJoin`, `RightJoin`, `SelectMany`, `DefaultIfEmpty` | DynamoDB does not support cross-item joins |
| Set operations | `Union`, `Concat`, `Except`, `Intersect` | Not supported in DynamoDB PartiQL |
| Offset / paging | `Skip`, `Take`, `ElementAt`, `ElementAtOrDefault` | DynamoDB has no offset semantics — use `Limit(n)` for an evaluation budget |
| Element operators | `Any`, `All` | Not supported server-side |
| Reverse traversal | `Last`, `LastOrDefault`, `Reverse` | Requires reverse index traversal, not implemented |
| Deduplication | `Distinct` | `SELECT DISTINCT` is not supported in DynamoDB PartiQL |
| Type casting | `Cast<T>` | Not supported; TPH discriminator filtering via `OfType<TDerived>()` and `is` requires active discriminator metadata; `GetType()` checks require active discriminator metadata and are limited to exact concrete mapped entity types |
| Conditional skipping | `SkipWhile`, `TakeWhile` | Not supported |
| Queryable `Contains` over query sources | `Queryable.Contains(dbSet, item)` | Not supported; in-memory membership translates to `IN`, native collection membership to `contains` |

Value-converted enum numeric casts are also rejected when compared to parameters. For example, `(int)entity.Status == value` is not translated if `Status` uses `.HasConversion<string>()`, because DynamoDB stores the converted string value. Compare `entity.Status` to an enum value directly, or map the enum numerically.

Expand Down Expand Up @@ -396,8 +396,13 @@ provider cannot guarantee auto-increment semantics on DynamoDB item writes.

### Shared-Table Discriminator Constraints

When multiple entity types share the same DynamoDB table, a discriminator is required. The
following constraints are validated at startup:
When multiple entity types share the same DynamoDB table, discriminator metadata is required only
when the provider needs server-side type discrimination or type filtering. `HasNoDiscriminator()`
can disable discriminator metadata for a shared-table group when your key design already isolates
entity types. With discriminator metadata disabled, derived `OfType<T>()`, `is`, and `GetType()`
type filters cannot be translated.

When discriminator metadata is enabled, the following constraints are validated at startup:

- Discriminator values must be unique within the table group.
- All entity types in the group must use the same discriminator attribute name.
Expand Down
30 changes: 27 additions & 3 deletions docs/modeling/single-table-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,10 +248,34 @@ For key-shape examples, continue with [Practical single-table pattern](#practica
Base queries materialize polymorphically (`DbSet<Person>` can return `Employee` and `Manager`).
When discrimination is active, the discriminator attribute is included in projection.

### `OfType<TDerived>()` limitation
### Type filtering

`Queryable.OfType<TDerived>()` is not currently translated by the provider.
Query derived sets directly (for example `context.Employees`) instead.
`Queryable.OfType<TDerived>()` translates to a discriminator predicate for TPH hierarchies:

```csharp
context.People
.OfType<Employee>()
.Where(x => x.Pk == "TENANT#1")
.ToListAsync();
```

Type tests in predicates also translate when they can be expressed as discriminator checks:

```csharp
context.People.Where(x => x is Manager);
context.People.Where(x => x.GetType() == typeof(Employee));
```

`GetType()` comparisons are exact-type checks. Use them for concrete mapped leaf types, such
as `Employee` in the example above. For base or intermediate type matching, use `is` or
`OfType<T>()`.

When `HasNoDiscriminator()` disables discrimination for a shared-table group, derived
`OfType<T>()`, `is`, and `GetType()` type filters cannot be translated to server-side type
predicates. Use key predicates or query the concrete `DbSet` directly when your PK/SK pattern
already isolates types.

`Cast<T>()` is not translated.

!!! tip "Index selection with inheritance/shared-table queries"

Expand Down
3 changes: 2 additions & 1 deletion docs/querying/operators.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ _This page is the authoritative reference for which LINQ operators translate to
| `string.Length` | `size(attr)` | DynamoDB `size` semantics; for strings, use with care when non-ASCII text matters |
| `string.IsNullOrEmpty(s)` | `attr IS NULL OR attr IS MISSING OR attr = ''` | Matches DynamoDB `NULL`, missing attributes, or empty string |
| `collection.Contains(prop)` | `prop IN [?, ...]` | In-memory collection membership; max 50 PK values, 100 non-key values |
| `OfType<TDerived>()` | discriminator predicate | TPH inheritance only; filters by concrete discriminator values for the requested derived type. `x is TDerived` translates when the target type can be expressed as discriminator values. `x.GetType() == typeof(TConcrete)` translates only for exact concrete mapped entity types. |

## Projection Operators

Expand Down Expand Up @@ -105,7 +106,7 @@ The following operators are not supported and throw `InvalidOperationException`
| Joins | `Join`, `GroupJoin`, `SelectMany`, `LeftJoin`, `RightJoin`, `DefaultIfEmpty` | DynamoDB does not support cross-item joins |
| Set operations | `Union`, `Concat`, `Except`, `Intersect` | Not supported |
| Conditional filtering | `SkipWhile`, `TakeWhile` | Not supported |
| Type filtering | `OfType<T>`, `Cast<T>` | Not supported |
| Type casting | `Cast<T>` | Not supported; use TPH inheritance queries with `OfType<TDerived>()` for type filtering |

## Scalar Type Support

Expand Down
22 changes: 11 additions & 11 deletions docs/spec-test-coverage.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,16 +166,16 @@ These tests use non-Northwind models and fixtures.

### Implemented

| Test Class | Methods | Cosmos | MongoDB | Notes |
| -------------------------- | ------: | :----: | :-----: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ComplexTypeQueryTestBase` | 74 | ✓ | ✗ | All inherited methods are registered/overridden with explicit outcomes; supported projection/filter, nested struct projection, and complex equality subsets execute, while navigation, set-operation, GroupBy, subquery/Contains, and pushdown cases are explicitly skipped |
| Test Class | Methods | Cosmos | MongoDB | Notes |
| -------------------------- | ------: | :----: | :-----: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ComplexTypeQueryTestBase` | 74 | ✓ | ✗ | All inherited methods are registered/overridden with explicit outcomes; supported projection/filter, nested struct projection, and complex equality subsets execute, while navigation, set-operation, GroupBy, subquery/Contains, and pushdown cases are explicitly skipped |
| `InheritanceQueryTestBase` | 52 | ✓ | ✗ | Single-table inheritance with discriminator predicates is covered, including `OfType`, `is`, `GetType()` leaf checks, derived-property filters, and discriminator projections. Skips remain for keyless views, navigations/includes, transactions, set operations, non-key ordered result assumptions, scan-like `Single`, and a few unsupported projection/query shapes. |

### Future

| Test Class | Methods | Cosmos | MongoDB | Feasibility | Rationale |
| -------------------------------------------- | ------: | :----: | :-----: | ----------: | ----------------------------------------------------------------------------------------------------------------------- |
| `AdHocComplexTypeQueryTestBase` | 13 | ✓ | ✗ | ~65% | Ad-hoc complex type query scenarios; same fixture dependency |
| `InheritanceQueryTestBase` | 52 | ✓ | ✗ | ~60% | Single-table inheritance with discriminator; DynamoDB has discriminator support |
| `FiltersInheritanceQueryTestBase` | 11 | ✗ | ✗ | ~55% | Query filters on inherited types |
| `FunkyDataQueryTestBase` | 19 | ✗ | ✗ | ~60% | Edge-case strings (null chars, Unicode, SQL injection chars); WHERE translation should handle these |
| `PrimitiveCollectionsQueryTestBase` | 156 | ✓ | ✗ | ~50% | DynamoDB LIST/SET attribute querying; PartiQL supports `CONTAINS` on lists; complex collection operations not supported |
Expand Down Expand Up @@ -316,7 +316,7 @@ ______________________________________________________________________
| Non-Query (top-level) | 18 classes / 356 methods | — | 4 classes / 410 methods | 21 classes / 1,058 methods |
| BulkUpdates | — | — | 5 classes / 135+ methods | 1 class / 33 methods |
| Northwind Query | 8 classes / 458 methods | — | 1 class / 469 methods | 13 classes / 929+ methods |
| Other Query | 1 class / 74 methods | — | 10 classes / 381 methods | 18 classes / 1,691 methods |
| Other Query | 2 classes / 126 methods | — | 9 classes / 329 methods | 18 classes / 1,691 methods |
| Associations | 3 classes / 42 methods | — | 2 classes / 4 methods | 13+ classes / 123+ methods |
| Translations | 5 classes / 134 methods | — | 8 classes / 162 methods | 3 classes / 25 methods |

Expand Down Expand Up @@ -351,6 +351,7 @@ This list records recently completed additions; authoritative implemented/not-im
21. `StringTranslationsDynamoTest` — 100 methods
22. `ComplexPropertiesStructuralEqualityDynamoTest` — 16 methods
23. `ComplexPropertiesProjectionDynamoTest` — 20 methods
24. `InheritanceQueryDynamoTest` — 52 methods

### Near-term (small, high confidence)

Expand All @@ -362,16 +363,15 @@ No medium-term specification test classes are currently queued here.

### Long-term (after core coverage is stable)

1. `InheritanceQueryDynamoTest` — blocked on `OfType`, `is`/`GetType()` discriminator translation, and fixture work
2. `PrimitiveCollectionsQueryDynamoTest`
3. `BulkUpdates` family — blocked on `ExecuteUpdate`/`ExecuteDelete`
4. Remaining translation tests (Math, ByteArray)
1. `PrimitiveCollectionsQueryDynamoTest`
2. `BulkUpdates` family — blocked on `ExecuteUpdate`/`ExecuteDelete`
3. Remaining translation tests (Math, ByteArray)

### Current totals

| Status | Classes | Methods |
| -------------- | ------: | ------: |
| Implemented | 35 | 1,064 |
| Implemented | 36 | 1,116 |
| Implement Next | 0 | 0 |
| Future | 30 | 1,561+ |
| Future | 29 | 1,509+ |
| Skip | 69+ | 3,859+ |
Loading
Loading