Skip to content

Commit 8332449

Browse files
committed
Add replace_ignore ColumnInfo
1 parent 6555931 commit 8332449

1 file changed

Lines changed: 27 additions & 4 deletions

File tree

sql_athame/dataclasses.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class ColumnInfo:
4646
serialize: Function to transform Python values before database storage
4747
deserialize: Function to transform database values back to Python objects
4848
insert_only: Whether this field should only be set on INSERT, not UPDATE in upsert operations
49+
replace_ignore: Whether this field should be ignored for `replace_multiple`
4950
5051
Example:
5152
>>> from dataclasses import dataclass
@@ -72,6 +73,7 @@ class ColumnInfo:
7273
serialize: Optional[Callable[[Any], Any]] = None
7374
deserialize: Optional[Callable[[Any], Any]] = None
7475
insert_only: Optional[bool] = None
76+
replace_ignore: Optional[bool] = None
7577

7678
def __post_init__(self, constraints: Union[str, Iterable[str], None]) -> None:
7779
if constraints is not None:
@@ -98,6 +100,9 @@ def merge(a: "ColumnInfo", b: "ColumnInfo") -> "ColumnInfo":
98100
serialize=b.serialize if b.serialize is not None else a.serialize,
99101
deserialize=b.deserialize if b.deserialize is not None else a.deserialize,
100102
insert_only=b.insert_only if b.insert_only is not None else a.insert_only,
103+
replace_ignore=(
104+
b.replace_ignore if b.replace_ignore is not None else a.replace_ignore
105+
),
101106
)
102107

103108

@@ -118,6 +123,7 @@ class ConcreteColumnInfo:
118123
serialize: Optional serialization function
119124
deserialize: Optional deserialization function
120125
insert_only: Whether this field should only be set on INSERT, not UPDATE
126+
replace_ignore: Whether this field should be ignored for `replace_multiple`
121127
"""
122128

123129
field: Field
@@ -126,9 +132,10 @@ class ConcreteColumnInfo:
126132
create_type: str
127133
nullable: bool
128134
constraints: tuple[str, ...]
129-
serialize: Optional[Callable[[Any], Any]] = None
130-
deserialize: Optional[Callable[[Any], Any]] = None
131-
insert_only: bool = False
135+
serialize: Optional[Callable[[Any], Any]]
136+
deserialize: Optional[Callable[[Any], Any]]
137+
insert_only: bool
138+
replace_ignore: bool
132139

133140
@staticmethod
134141
def from_column_info(
@@ -163,6 +170,7 @@ def from_column_info(
163170
serialize=info.serialize,
164171
deserialize=info.deserialize,
165172
insert_only=bool(info.insert_only),
173+
replace_ignore=bool(info.replace_ignore),
166174
)
167175

168176
def create_table_string(self) -> str:
@@ -386,6 +394,20 @@ def insert_only_field_names(cls) -> set[str]:
386394
},
387395
)
388396

397+
@classmethod
398+
def replace_ignore_field_names(cls) -> set[str]:
399+
"""Get set of field names marked as replace_ignore in ColumnInfo.
400+
401+
Returns:
402+
Set of field names that should be ignored for `replace_multiple`
403+
"""
404+
return cls._cached(
405+
("replace_ignore_field_names",),
406+
lambda: {
407+
ci.field.name for ci in cls.column_info().values() if ci.replace_ignore
408+
},
409+
)
410+
389411
@classmethod
390412
def field_names_sql(
391413
cls,
@@ -1366,7 +1388,8 @@ async def plan_replace_multiple(
13661388
"""
13671389
# For comparison purposes, combine auto-detected insert_only fields with manual ones
13681390
all_insert_only = cls.insert_only_field_names() | set(insert_only)
1369-
ignore = sorted(set(ignore) | all_insert_only)
1391+
default_ignore = cls.replace_ignore_field_names() - set(force_update)
1392+
ignore = sorted(set(ignore) | default_ignore | all_insert_only)
13701393
equal_ignoring = cls._cached(
13711394
("equal_ignoring", tuple(ignore)),
13721395
lambda: cls._get_equal_ignoring_fn(ignore),

0 commit comments

Comments
 (0)