From e45929997c19ff6b676f8953712517fa3f88b846 Mon Sep 17 00:00:00 2001 From: dhruvxvaishnav Date: Mon, 14 Sep 2026 16:58:32 +0530 Subject: [PATCH 1/2] feat(database): add write operation capabilities --- .../capabilities/database.yaml | 14 +++++++++- .../mutate/bulk_rows_with_differing_fields.md | 28 +++++++++++++++++++ .../specs/database/mutate/count.md | 23 +++++++++++++++ .../specs/database/mutate/insert.md | 3 ++ .../specs/database/mutate/missing_defaults.md | 27 ++++++++++++++++++ .../specs/database/mutate/upsert.md | 3 ++ 6 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 packages/capability-matrix/specs/database/mutate/bulk_rows_with_differing_fields.md create mode 100644 packages/capability-matrix/specs/database/mutate/count.md create mode 100644 packages/capability-matrix/specs/database/mutate/missing_defaults.md diff --git a/packages/capability-matrix/capabilities/database.yaml b/packages/capability-matrix/capabilities/database.yaml index 52d8519..bc1149d 100644 --- a/packages/capability-matrix/capabilities/database.yaml +++ b/packages/capability-matrix/capabilities/database.yaml @@ -14,10 +14,22 @@ groups: - id: configuration title: Client Configuration features: + - id: database.mutate.bulk_rows_with_differing_fields + name: Bulk Write Rows with Differing Fields + description: Insert or upsert multiple rows with different field sets in one request, without requiring callers to fill every omitted field explicitly. + group: mutate + - id: database.mutate.count + name: Count Mutated Rows + description: Request the number of rows affected by an insert, update, upsert, or delete operation. + group: mutate - id: database.mutate.delete name: Delete Rows description: Delete rows from a table or view that match a filter. group: mutate + - id: database.mutate.missing_defaults + name: Use Defaults for Missing Fields + description: Use database column defaults instead of null for fields omitted from bulk insert or upsert rows. + group: mutate - id: database.mutate.insert name: Insert Rows description: Insert one or more rows into a table or view. @@ -241,4 +253,4 @@ features: - id: database.configuration.request_timeout name: Request Timeout description: Set a global request timeout in milliseconds at construction time; in-flight requests are cancelled once the deadline is reached. - group: configuration \ No newline at end of file + group: configuration diff --git a/packages/capability-matrix/specs/database/mutate/bulk_rows_with_differing_fields.md b/packages/capability-matrix/specs/database/mutate/bulk_rows_with_differing_fields.md new file mode 100644 index 0000000..d067c3d --- /dev/null +++ b/packages/capability-matrix/specs/database/mutate/bulk_rows_with_differing_fields.md @@ -0,0 +1,28 @@ +# Bulk Write Rows with Differing Fields + +Insert or upsert multiple rows with different field sets in one request. + +## API + +Spec: [PostgREST Documentation: Specifying Columns](https://docs.postgrest.org/en/latest/references/api/tables_views.html#specifying-columns) + +- `POST /{relation}?columns={union-of-fields}` + +## Behavior + +The SDK accepts a collection whose rows do not all contain the same fields and sends it as one bulk insert or upsert. It identifies the union of fields across the non-empty collection and supplies that set through PostgREST's `columns` query parameter. + +The SDK must not require callers to add placeholder values for omitted fields. Their values follow the missing-field behavior selected for the request. + +An empty collection writes nothing and must not produce an empty `columns` parameter. + +## Errors + +- `PGRST204` when a field named by `columns` does not exist +- Database constraint errors still apply to every row in the bulk operation + +## Related + +- [Insert Rows](insert.md) +- [Upsert Rows](upsert.md) +- [Use Defaults for Missing Fields](missing_defaults.md) diff --git a/packages/capability-matrix/specs/database/mutate/count.md b/packages/capability-matrix/specs/database/mutate/count.md new file mode 100644 index 0000000..26b89cf --- /dev/null +++ b/packages/capability-matrix/specs/database/mutate/count.md @@ -0,0 +1,23 @@ +# Count Mutated Rows + +Request the number of rows affected by an insert, update, upsert, or delete operation. + +## API + +Spec: [PostgREST Documentation: Counting](https://docs.postgrest.org/en/latest/references/api/pagination_count.html#counting) + +- `POST`, `PATCH`, or `DELETE` with `Prefer: count=exact|planned|estimated` + +## Behavior + +The caller chooses a supported count strategy when starting a mutation. The response exposes the resulting affected-row count separately from any returned row representation. + +Counting is optional. Omitting it avoids requesting a total, and selecting it must not implicitly request the mutated rows themselves. + +The count preference is independent of other `Prefer` entries, including `return`, `resolution`, and `missing`. An SDK must preserve those entries when adding the count preference. + +## Related + +- [Insert Rows](insert.md) +- [Upsert Rows](upsert.md) +- `database.mutate.select_after_mutation` diff --git a/packages/capability-matrix/specs/database/mutate/insert.md b/packages/capability-matrix/specs/database/mutate/insert.md index afe237b..67c99bc 100644 --- a/packages/capability-matrix/specs/database/mutate/insert.md +++ b/packages/capability-matrix/specs/database/mutate/insert.md @@ -48,3 +48,6 @@ whole header. ## Related - [Upsert Rows](upsert.md) — insert, but resolve a conflict instead of failing +- [Bulk Write Rows with Differing Fields](bulk_rows_with_differing_fields.md) +- [Use Defaults for Missing Fields](missing_defaults.md) +- [Count Mutated Rows](count.md) diff --git a/packages/capability-matrix/specs/database/mutate/missing_defaults.md b/packages/capability-matrix/specs/database/mutate/missing_defaults.md new file mode 100644 index 0000000..eb4ec28 --- /dev/null +++ b/packages/capability-matrix/specs/database/mutate/missing_defaults.md @@ -0,0 +1,27 @@ +# Use Defaults for Missing Fields + +Use database column defaults instead of null for fields omitted from bulk insert or upsert rows. + +## API + +Spec: [PostgREST Documentation: Missing](https://docs.postgrest.org/en/latest/references/api/preferences.html#missing) + +- `POST /{relation}?columns={union-of-fields}` with `Prefer: missing=default` + +## Behavior + +When rows in a bulk insert or upsert omit different fields, the caller can choose whether each omitted value becomes SQL `NULL` or uses the column's database `DEFAULT`. + +Using database defaults sends `missing=default`. The alternative omits that preference or sends `missing=null`. The choice only affects omitted fields. An explicitly supplied null remains null. + +The missing preference is independent of other `Prefer` entries, including `return`, `resolution`, and `count`. An SDK must preserve those entries when changing the missing-field behavior. + +## Prerequisites + +The request must supply a `columns` parameter containing the union of fields across the rows. Without it, each payload row supplies its own field set and an omitted field is left out of the statement rather than governed by this preference. + +## Related + +- [Bulk Write Rows with Differing Fields](bulk_rows_with_differing_fields.md) +- [Insert Rows](insert.md) +- [Upsert Rows](upsert.md) diff --git a/packages/capability-matrix/specs/database/mutate/upsert.md b/packages/capability-matrix/specs/database/mutate/upsert.md index 18e0d3c..2c072c6 100644 --- a/packages/capability-matrix/specs/database/mutate/upsert.md +++ b/packages/capability-matrix/specs/database/mutate/upsert.md @@ -45,3 +45,6 @@ the whole header drops `resolution=` and silently turns the upsert into an inser ## Related - [Insert Rows](insert.md) — the same write without conflict resolution +- [Bulk Write Rows with Differing Fields](bulk_rows_with_differing_fields.md) +- [Use Defaults for Missing Fields](missing_defaults.md) +- [Count Mutated Rows](count.md) From c05491305e79ce9df53717d7896e8d222228fef0 Mon Sep 17 00:00:00 2001 From: dhruvxvaishnav Date: Thu, 17 Sep 2026 17:29:32 +0530 Subject: [PATCH 2/2] fix(database): address write capability review feedback --- packages/capability-matrix/capabilities/database.yaml | 8 ++++---- .../specs/database/mutate/missing_defaults.md | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/capability-matrix/capabilities/database.yaml b/packages/capability-matrix/capabilities/database.yaml index bc1149d..b1484e8 100644 --- a/packages/capability-matrix/capabilities/database.yaml +++ b/packages/capability-matrix/capabilities/database.yaml @@ -26,14 +26,14 @@ features: name: Delete Rows description: Delete rows from a table or view that match a filter. group: mutate - - id: database.mutate.missing_defaults - name: Use Defaults for Missing Fields - description: Use database column defaults instead of null for fields omitted from bulk insert or upsert rows. - group: mutate - id: database.mutate.insert name: Insert Rows description: Insert one or more rows into a table or view. group: mutate + - id: database.mutate.missing_defaults + name: Use Defaults for Missing Fields + description: Use database column defaults instead of null for fields omitted from bulk insert or upsert rows. + group: mutate - id: database.mutate.select_after_mutation name: Select After Mutation description: Chain a column selection onto an insert, update, upsert, or delete to return the affected rows in the response. diff --git a/packages/capability-matrix/specs/database/mutate/missing_defaults.md b/packages/capability-matrix/specs/database/mutate/missing_defaults.md index eb4ec28..cb9b1fc 100644 --- a/packages/capability-matrix/specs/database/mutate/missing_defaults.md +++ b/packages/capability-matrix/specs/database/mutate/missing_defaults.md @@ -18,7 +18,7 @@ The missing preference is independent of other `Prefer` entries, including `retu ## Prerequisites -The request must supply a `columns` parameter containing the union of fields across the rows. Without it, each payload row supplies its own field set and an omitted field is left out of the statement rather than governed by this preference. +The request must supply a `columns` parameter containing the union of fields across the rows. Without it, a bulk payload must carry an identical key set on every row (see [Insert Rows](insert.md)), and a field omitted from every row is left out of the statement entirely, so the database applies its default regardless of this preference. ## Related