Skip to content

Commit 9480180

Browse files
committed
simple insert_dict() builder
1 parent 8841520 commit 9480180

File tree

3 files changed

+45
-2
lines changed

3 files changed

+45
-2
lines changed

pypika/queries.py

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from copy import copy
22
from functools import reduce
3-
from typing import Any, List, Optional, Sequence, Tuple as TypedTuple, Type, Union
3+
from typing import Any, List, Optional, Sequence, Tuple as TypedTuple, Type, Union, Set, Dict
44

55
from pypika.enums import Dialects, JoinType, ReferenceOption, SetOperation
66
from pypika.terms import (
@@ -750,7 +750,7 @@ def __init__(
750750
self._select_star_tables = set()
751751
self._mysql_rollup = False
752752
self._select_into = False
753-
753+
self._using_insert_dict = False
754754
self._subquery_count = 0
755755
self._foreign_table = False
756756

@@ -890,6 +890,9 @@ def columns(self, *terms: Any) -> "QueryBuilder":
890890
if self._insert_table is None:
891891
raise AttributeError("'Query' object has no attribute '%s'" % "insert")
892892

893+
if self._using_insert_dict:
894+
raise QueryException("Cannot mix use of columns() and insert_dict()")
895+
893896
if terms and isinstance(terms[0], (list, tuple)):
894897
terms = terms[0]
895898

@@ -903,6 +906,15 @@ def insert(self, *terms: Any) -> "QueryBuilder":
903906
self._apply_terms(*terms)
904907
self._replace = False
905908

909+
def insert_dict(self, data: Dict[str, Any]) -> "QueryBuilder":
910+
cols = data.keys()
911+
if self._columns and self._columns != cols:
912+
raise QueryException("Current columns differs from columns in keys")
913+
914+
builder = self.columns(*cols).insert(*data.values())
915+
builder._using_insert_dict = True
916+
return builder
917+
906918
@builder
907919
def replace(self, *terms: Any) -> "QueryBuilder":
908920
self._apply_terms(*terms)

pypika/tests/test_inserts.py

+23
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
)
1818
from pypika.terms import Values
1919
from pypika.utils import QueryException
20+
from datetime import datetime
2021

2122
__author__ = "Timothy Heys"
2223
__email__ = "[email protected]"
@@ -168,6 +169,28 @@ def test_insert_with_statement(self):
168169
'WITH sub_qs AS (SELECT "id" FROM "abc") INSERT INTO "abc" SELECT "sub_qs"."id" FROM sub_qs', str(q)
169170
)
170171

172+
class InsertIntoWithDict(unittest.TestCase):
173+
table_abc = Table("abc")
174+
175+
def test_inserting_simple_dictionary(self):
176+
q = Query().into(self.table_abc).insert_dict({"c1": "value", "c2": 1})
177+
self.assertEqual("INSERT INTO \"abc\" (\"c1\",\"c2\") VALUES ('value',1)", str(q))
178+
179+
def test_inserting_dictionary_goes_through_value_quoting_logic(self):
180+
q = Query().into(self.table_abc).insert_dict({"num": 1, "timestamp": datetime(2023, 4, 18)})
181+
self.assertEqual("INSERT INTO \"abc\" (\"num\",\"timestamp\") VALUES (1,'2023-04-18T00:00:00')", str(q))
182+
183+
def test_inserting_dictionary_produces_builder(self):
184+
q = Query().into(self.table_abc).insert_dict({"num": 1, "timestamp": datetime(2023, 4, 18)})
185+
q = q.insert(2, datetime(2023, 4, 19))
186+
self.assertEqual("INSERT INTO \"abc\" (\"num\",\"timestamp\") VALUES (1,'2023-04-18T00:00:00'),(2,'2023-04-19T00:00:00')", str(q))
187+
188+
def test_columns_is_not_allowed_with_insert_dict(self):
189+
with self.assertRaises(QueryException):
190+
Query().into(self.table_abc).columns("a", "b").insert_dict({"num": 1})
191+
192+
with self.assertRaises(QueryException):
193+
Query().into(self.table_abc).insert_dict({"num": 1}).columns("a", "b")
171194

172195
class PostgresInsertIntoOnConflictTests(unittest.TestCase):
173196
table_abc = Table("abc")

pypika/utils.py

+8
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,18 @@ class FunctionException(Exception):
3636
pass
3737

3838

39+
<<<<<<< HEAD
3940
C = TypeVar("C")
4041

4142

4243
def builder(func: C) -> C:
44+
=======
45+
class MixedInsertStyleError(QueryException):
46+
pass
47+
48+
49+
def builder(func: Callable) -> Callable:
50+
>>>>>>> 25aabb6 (simple insert_dict() builder)
4351
"""
4452
Decorator for wrapper "builder" functions. These are functions on the Query class or other classes used for
4553
building queries which mutate the query and return self. To make the build functions immutable, this decorator is

0 commit comments

Comments
 (0)