1616from sqlspec .builder ._select import ReturningClauseMixin
1717from sqlspec .core import SQLResult
1818from sqlspec .exceptions import SQLBuilderError
19+ from sqlspec .utils .deprecation import warn_deprecation
20+ from sqlspec .utils .serializers import schema_dump , serialize_collection
1921from sqlspec .utils .type_guards import has_expression_and_sql
2022
2123if TYPE_CHECKING :
@@ -104,21 +106,8 @@ def get_insert_expression(self) -> exp.Insert:
104106 """Get the insert expression (public API)."""
105107 return self ._get_insert_expression ()
106108
107- def values_from_dict (self , data : "Mapping[str, Any]" ) -> "Self" :
108- """Adds a row of values from a dictionary.
109-
110- This is a convenience method that automatically sets columns based on
111- the dictionary keys and values based on the dictionary values.
112-
113- Args:
114- data: A mapping of column names to values.
115-
116- Returns:
117- The current builder instance for method chaining.
118-
119- Raises:
120- SQLBuilderError: If `into()` has not been called to set the table.
121- """
109+ def _bind_values_from_dict (self , data : "Mapping[str, Any]" ) -> "Self" :
110+ """Bind a single dict row without deprecation warnings (internal)."""
122111 insert_expr = self ._get_insert_expression ()
123112 if insert_expr .args .get ("this" ) is None :
124113 raise SQLBuilderError (ERR_MSG_TABLE_NOT_SET )
@@ -132,21 +121,8 @@ def values_from_dict(self, data: "Mapping[str, Any]") -> "Self":
132121
133122 return self .values (* [data [col ] for col in self ._columns ])
134123
135- def values_from_dicts (self , data : "Sequence[Mapping[str, Any]]" ) -> "Self" :
136- """Adds multiple rows of values from a sequence of dictionaries.
137-
138- This is a convenience method for bulk inserts from structured data.
139-
140- Args:
141- data: A sequence of mappings, each representing a row of data.
142-
143- Returns:
144- The current builder instance for method chaining.
145-
146- Raises:
147- SQLBuilderError: If `into()` has not been called to set the table,
148- or if dictionaries have inconsistent keys.
149- """
124+ def _bind_values_from_dicts (self , data : "Sequence[Mapping[str, Any]]" ) -> "Self" :
125+ """Bind many dict rows without deprecation warnings (internal)."""
150126 if not data :
151127 return self
152128
@@ -168,6 +144,107 @@ def values_from_dicts(self, data: "Sequence[Mapping[str, Any]]") -> "Self":
168144
169145 return self
170146
147+ def values_from_dict (self , data : "Mapping[str, Any]" ) -> "Self" :
148+ """Adds a row of values from a dictionary.
149+
150+ .. deprecated:: 0.46.2
151+ Use :meth:`values_from` instead — it accepts dicts, msgspec Structs,
152+ Pydantic models, dataclasses, and attrs classes.
153+
154+ Args:
155+ data: A mapping of column names to values.
156+
157+ Returns:
158+ The current builder instance for method chaining.
159+
160+ Raises:
161+ SQLBuilderError: If `into()` has not been called to set the table.
162+ """
163+ warn_deprecation (
164+ version = "0.46.2" ,
165+ deprecated_name = "Insert.values_from_dict" ,
166+ kind = "method" ,
167+ alternative = "Insert.values_from() — accepts dicts, msgspec Structs, Pydantic models, dataclasses, and attrs classes" ,
168+ removal_in = "0.48.0" ,
169+ )
170+ return self ._bind_values_from_dict (data )
171+
172+ def values_from_dicts (self , data : "Sequence[Mapping[str, Any]]" ) -> "Self" :
173+ """Adds multiple rows of values from a sequence of dictionaries.
174+
175+ .. deprecated:: 0.46.2
176+ Use :meth:`values_from_many` instead — it accepts dicts, msgspec Structs,
177+ Pydantic models, dataclasses, and attrs classes.
178+
179+ Args:
180+ data: A sequence of mappings, each representing a row of data.
181+
182+ Returns:
183+ The current builder instance for method chaining.
184+
185+ Raises:
186+ SQLBuilderError: If `into()` has not been called to set the table,
187+ or if dictionaries have inconsistent keys.
188+ """
189+ warn_deprecation (
190+ version = "0.46.2" ,
191+ deprecated_name = "Insert.values_from_dicts" ,
192+ kind = "method" ,
193+ alternative = "Insert.values_from_many() — accepts dicts, msgspec Structs, Pydantic models, dataclasses, and attrs classes" ,
194+ removal_in = "0.48.0" ,
195+ )
196+ return self ._bind_values_from_dicts (data )
197+
198+ def values_from (self , data : Any , * , exclude_unset : bool = True ) -> "Self" :
199+ """Add a row of values from a dict, dataclass, msgspec.Struct, Pydantic model, or attrs class.
200+
201+ Schema instances are normalised via :func:`sqlspec.utils.serializers.schema_dump`
202+ with ``wire_format=False`` then bound as a single row. The dict shape uses Python
203+ attribute names regardless of msgspec ``rename=`` or Pydantic ``Field(alias=...)``;
204+ wire-aligned names never make sense for SQL column binding.
205+
206+ Args:
207+ data: A dict, dataclass instance, ``msgspec.Struct``, ``pydantic.BaseModel``,
208+ or ``attrs``-decorated class instance.
209+ exclude_unset: If True, exclude fields that were never set. Honoured by
210+ msgspec (UNSET fields), Pydantic (``model_fields_set``), and dataclass
211+ (via empty default-field semantics). No-op for attrs.
212+
213+ Returns:
214+ The current builder instance for method chaining.
215+
216+ Raises:
217+ SQLBuilderError: If ``into()`` has not been called or the dict shape is
218+ incompatible with previously set columns.
219+ """
220+ payload = schema_dump (data , exclude_unset = exclude_unset , wire_format = False )
221+ return self ._bind_values_from_dict (payload )
222+
223+ def values_from_many (self , items : "Sequence[Any]" , * , exclude_unset : bool = True ) -> "Self" :
224+ """Add multiple rows from a sequence of dicts, dataclasses, msgspec Structs, Pydantic models, or attrs classes.
225+
226+ Each item is normalised via :func:`sqlspec.utils.serializers.schema_dump` with
227+ ``wire_format=False`` then bound as a multi-row INSERT. Mixed schema kinds in the
228+ same sequence are supported (each item normalises independently); however, the
229+ resulting dict shapes must agree on key sets.
230+
231+ Args:
232+ items: A sequence of schema instances or dicts.
233+ exclude_unset: See :meth:`values_from` for per-library semantics.
234+
235+ Returns:
236+ The current builder instance for method chaining. Empty input returns the
237+ builder unchanged.
238+
239+ Raises:
240+ SQLBuilderError: If ``into()`` has not been called or item dict shapes
241+ disagree on key sets.
242+ """
243+ if not items :
244+ return self
245+ payload = serialize_collection (items , exclude_unset = exclude_unset , wire_format = False )
246+ return self ._bind_values_from_dicts (payload )
247+
171248 def on_conflict (self , * columns : str ) -> "ConflictBuilder" :
172249 """Adds an ON CONFLICT clause with specified columns.
173250
0 commit comments