feat: Add generated and generated_always attributes

This commit introduces support for PostgreSQL generated columns by
adding two new field attributes to the `Georm` derive macro:
`#[georm(generated)]` and `#[georm(generated_always)]`.

The `#[georm(generated_always)]` attribute is for fields that are
always generated by the database, such as `GENERATED ALWAYS AS
IDENTITY` columns or columns with a `GENERATED ALWAYS AS (expression)
STORED` clause. These fields are now excluded from `INSERT` and
`UPDATE` statements, preventing accidental writes and ensuring data
integrity at compile time.

The `#[georm(generated)]` attribute is for fields that have a default
value generated by the database but can also be manually overridden,
such as `GENERATED BY DEFAULT AS IDENTITY` columns. These fields
behave similarly to `#[georm(defaultable)]` fields, allowing them to
be omitted from `INSERT` statements to use the database-generated
value.

For now, the behaviour is the same between `#[georm(generated)]` and
`#[georm(defaultable)]`, but the addition of the former now will be
useful for future features.

Key changes:
- Added `generated` and `generated_always` attributes to
  `GeormFieldAttributes`.
- Introduced `GeneratedType` enum in the IR to represent the different
  generation strategies.
- Modified the `create` and `update` query generation to exclude
  fields marked with `#[georm(generated_always)]`.
- Integrated `#[georm(generated)]` fields with the existing
  defaultable struct logic.
- Added validation to prevent conflicting attribute usage, namely
  `#[georm(generated)]` and `#[georm(generated_always)]` on the same
  field.

Implements #3
This commit is contained in:
2025-08-07 20:27:45 +02:00
parent 545dfa066d
commit 3307aa679d
17 changed files with 434 additions and 103 deletions

8
tests/fixtures/generated.sql vendored Normal file
View File

@@ -0,0 +1,8 @@
INSERT INTO products (name, price, discount_percent)
VALUES ('Laptop', 999.99, 10);
INSERT INTO products (sku_number, name, price, discount_percent)
VALUES (5000, 'Mouse', 29.99, 5);
INSERT INTO products (name, price)
VALUES ('Keyboard', 79.99);