The ARX specification
10 Conformance
The specification is checked in two ways. The test vectors (chapters 04, 06, 07 and 09) need no database: every implementation runs them. The conformance suite runs the rest against real databases: one set of tests that every .NET provider passes, on every change, against its own database in CI. Where a provider behaves differently from another, the suite either finds a declared capability that explains it or fails.
How it tests capabilities
Each capability is tested both ways. A provider that declares it must do it correctly; a provider that doesn't must refuse it with ARX8001 NotSupported, never ignore it or answer differently. Adding a capability to a provider changes which half of a test runs, never whether it runs.
| Capability | PostgreSQL | SQL Server | MySQL | MongoDB | DynamoDB |
|---|---|---|---|---|---|
| Joins | yes | yes | yes | yes | no |
| Aggregates | yes | yes | yes | yes | no (a Count alone is answered) |
| OffsetPaging | yes | yes | yes | yes | no |
| TokenPaging | no | no | no | yes | yes |
| TotalCount | yes | yes | yes | yes | no |
| Transactions | yes | yes | yes | yes (replica set) | yes |
| BulkWrite | yes | yes | yes | yes | yes |
| StoredProcedures | yes | yes | yes | no | no |
| FullTextSearch | yes | yes | yes | yes | no |
| LikeOperators | yes | yes | yes | yes | no (BeginsWith and Contains, case-sensitive, by opt-in) |
| OrFilters | yes | yes | yes | yes | yes |
| SecondaryIndexQuery | no | no | no | no | yes |
| OptimisticConcurrency | yes | yes | yes | yes | yes |
| SchemaResolution | yes | yes | yes | no | no |
| WriteByFilter | yes | yes | yes | yes | yes (the filter gives a partition key; at most 100 items) |
What it checks
| Area | Tests |
|---|---|
| Create, Retrieve | Every value read back (text, integer, decimal to 4 places, boolean, a UTC instant, null); a duplicate id is ARX3001 and leaves the first; an unknown id reads null; default(DateTime) is ARX1013 before the database; CreateMultiple returns ids in list order and is all or nothing |
| Update | Only the attributes set are written; null reads back null; a missing record is ARX2002 and creates nothing; UpdateMultiple is all or nothing |
| Delete | By id true, then false; DeleteMultiple counts what existed |
| RetrieveMultiple | Equal, with order both ways; greater than, Between, In, a boolean; Null, NotNull, and NotEqual never matching a null; the columns asked for and no others; an Or filter, BeginsWith, a Sum and a link, each by capability |
| Paging | By page number, by cookie (every row once, HasNextPage exact), the total, each by capability; a provider without cookies returns none and refuses one |
| Transactions | A batch scope committed keeps both writes; one disposed without a commit keeps neither |
| Execute | Refused (ARX8001) where StoredProcedures isn't declared |
| Writes by a filter | Only the matching records change, counted; Or and In; null clears; a version column goes up by one on each changed record; an id, a version value, an empty filter or a link condition is ARX1001; a batch scope rolled back undoes it; CreateMultiple without ids returns no id for each and stores every record |
| Optimistic concurrency | A stale version is ARX2004 and changes nothing where OptimisticConcurrency is declared; a declared version column is ARX8001 where it isn't |
| Security | Names carrying SQL (;, quotes, comments, UNION) are ARX1017 in Create, Update and RetrieveMultiple; values carrying SQL, MongoDB operators or DynamoDB expression syntax are stored and matched as values |
Values are compared as values, not as .NET types, where providers read them back differently by design: a DynamoDB
number comes back as decimal, a DynamoDB date as its ISO 8601 text, and a SQL Server or MySQL date with an unspecified
kind (UTC wall time).