@@ -70,6 +70,12 @@ def test_named_param(self):
7070 assert p .name == "greeting"
7171 assert p .exact is False
7272
73+ def test_positional_creation (self ):
74+ p = Param (42 , "greeting" , True )
75+ assert p .value == 42
76+ assert p .name == "greeting"
77+ assert p .exact is True
78+
7379 def test_exact_param_requires_name (self ):
7480 with pytest .raises (ValueError , match = "exact=True must have a name" ):
7581 Param (value = 1 , exact = True )
@@ -94,8 +100,8 @@ def test_param_helper_function(self):
94100 def test_param_repr (self ):
95101 p = Param (value = 42 , name = "x" )
96102 r = repr (p )
97- assert "42" in r
98- assert "x" in r
103+ expected = "Param(value=42, name='x', exact=False)"
104+ assert r == expected
99105
100106 def test_param_equality (self ):
101107 """Frozen dataclasses support equality by default."""
@@ -108,6 +114,32 @@ def test_param_various_value_types(self):
108114 p = Param (value = val )
109115 assert p .value is val
110116
117+ def test_param_factory_function_defaults (self ):
118+ """param() should allow defaults for name and exact."""
119+ expected = Param (value = 42 , name = None , exact = False )
120+ assert param (42 ) == expected
121+ assert param (value = 42 ) == expected
122+
123+ def test_param_factory_function_named (self ):
124+ p = param (42 , name = "x" )
125+ assert p .value == 42
126+ assert p .name == "x"
127+ assert p .exact is False
128+
129+ def test_param_factory_function_exact (self ):
130+ p = param (42 , name = "x" , exact = True )
131+ assert p .value == 42
132+ assert p .name == "x"
133+ assert p .exact is True
134+
135+ def test_param_factory_function_exact_requires_name (self ):
136+ with pytest .raises (ValueError , match = "exact=True must have a name" ):
137+ param (42 , exact = True )
138+
139+ def test_param_factory_function_exact_with_name (self ):
140+ with pytest .raises (TypeError ):
141+ param (42 , "x" , True ) # ty:ignore[too-many-positional-arguments]
142+
111143
112144# ═══════════════════════════════════════════════════════════════════════════════
113145# ParamInterpolation
@@ -116,20 +148,20 @@ def test_param_various_value_types(self):
116148
117149class TestParamInterpolation :
118150 def test_wraps_param (self ):
119- p = Param ( value = 42 , name = "x" )
151+ p = param ( 42 , "x" )
120152 pi = ParamInterpolation (p )
121153 assert pi .value is p
122154 assert pi .expression == "x"
123155 assert pi .conversion is None
124156 assert pi .format_spec == ""
125157
126158 def test_unnamed_param_expression_is_none (self ):
127- p = Param ( value = 42 )
159+ p = param ( 42 )
128160 pi = ParamInterpolation (p )
129161 assert pi .expression is None
130162
131163 def test_satisfies_into_interpolation_protocol (self ):
132- pi = ParamInterpolation (Param ( value = 1 , name = "x" ))
164+ pi = ParamInterpolation (param ( 1 , "x" ))
133165 assert isinstance (pi , IntoInterpolation )
134166
135167
@@ -234,12 +266,11 @@ def test_with_interpolation(self):
234266 assert t .interpolations [0 ] is interp
235267
236268 def test_bare_param_errors (self ):
237- p = Param (value = 42 )
238269 with pytest .raises (TypeError , match = "Unexpected part type" ):
239- SqlTemplate ("SELECT " , p ) # ty:ignore[invalid-argument-type]
270+ SqlTemplate ("SELECT " , param ( 42 ) ) # ty:ignore[invalid-argument-type]
240271
241272 def test_wrapped_param (self ):
242- wrapped = ParamInterpolation (Param ( value = 42 , name = "x" ))
273+ wrapped = ParamInterpolation (param ( 42 , "x" ))
243274 t = SqlTemplate ("SELECT " , wrapped , " FROM t" )
244275 assert len (t .interpolations ) == 1
245276
@@ -299,8 +330,7 @@ def test_plain_string(self):
299330 assert expected == compiled
300331
301332 def test_param (self ):
302- p = Param (value = 42 , name = "answer" )
303- t = template (p )
333+ t = template (param (42 , "answer" ))
304334 compiled = t .compile ()
305335 expected = CompiledSql ("$p0_answer" , {"p0_answer" : 42 })
306336 assert expected == compiled
@@ -346,7 +376,7 @@ def test_iterable_of_strings(self):
346376 assert expected == compiled
347377
348378 def test_iterable_with_params (self ):
349- t = template ("SELECT * FROM t WHERE id = " , Param ( value = 5 , name = "id" ))
379+ t = template ("SELECT * FROM t WHERE id = " , param ( 5 , "id" ))
350380 compiled = t .compile ()
351381 expected = CompiledSql ("SELECT * FROM t WHERE id = $p0_id" , {"p0_id" : 5 })
352382 assert expected == compiled
@@ -547,12 +577,12 @@ def test_expression_name_preserved_for_simple_param(self):
547577
548578class TestResolvedSqlTemplate :
549579 def test_basic (self ):
550- r = ResolvedSqlTemplate (["SELECT " , Param ( value = 42 , name = "x" )])
580+ r = ResolvedSqlTemplate (["SELECT " , param ( 42 , "x" )])
551581 parts = list (r )
552582 assert len (parts ) == 2
553583
554584 def test_compile (self ):
555- r = ResolvedSqlTemplate (["SELECT " , Param ( value = 42 , name = "x" )])
585+ r = ResolvedSqlTemplate (["SELECT " , param ( 42 , "x" )])
556586 compiled = r .compile ()
557587 assert isinstance (compiled , CompiledSql )
558588 assert 42 in compiled .params .values ()
@@ -563,13 +593,13 @@ def test_str_raises(self):
563593 str (r )
564594
565595 def test_repr (self ):
566- r = ResolvedSqlTemplate (["SELECT " , Param ( value = 42 , name = "x" )])
596+ r = ResolvedSqlTemplate (["SELECT " , param ( 42 , "x" )])
567597 rep = repr (r )
568598 assert "ResolvedSqlTemplate" in rep
569599 assert "x=42" in rep
570600
571601 def test_iter (self ):
572- parts_in = ["a" , Param ( value = 1 , name = "x" ), "b" ]
602+ parts_in = ["a" , param ( 1 , "x" ), "b" ]
573603 r = ResolvedSqlTemplate (parts_in )
574604 assert list (r ) == parts_in
575605
@@ -585,43 +615,31 @@ def test_all_strings(self):
585615 assert result == CompiledSql ("SELECT 1" )
586616
587617 def test_single_unnamed_param (self ):
588- result = compile_parts (["SELECT " , Param ( value = 42 )])
618+ result = compile_parts (["SELECT " , param ( 42 )])
589619 expected = CompiledSql ("SELECT $p0" , params = {"p0" : 42 })
590620 assert result == expected
591621
592622 def test_single_named_param (self ):
593- result = compile_parts (["SELECT " , Param ( value = 42 , name = "x" )])
623+ result = compile_parts (["SELECT " , param ( 42 , "x" )])
594624 expected = CompiledSql ("SELECT $p0_x" , params = {"p0_x" : 42 })
595625 assert result == expected
596626
597627 def test_exact_param_uses_literal_name (self ):
598- result = compile_parts (["SELECT " , Param ( value = 42 , name = "my_param" , exact = True )])
628+ result = compile_parts (["SELECT " , param ( 42 , "my_param" , exact = True )])
599629 expected = CompiledSql ("SELECT $my_param" , params = {"my_param" : 42 })
600630 assert result == expected
601631
602632 def test_multiple_params_numbered_sequentially (self ):
603- result = compile_parts (["SELECT * WHERE a = " , Param ( value = 1 , name = "a" ), " AND b = " , Param ( value = 2 , name = "b" )])
633+ result = compile_parts (["SELECT * WHERE a = " , param ( 1 , "a" ), " AND b = " , param ( 2 , "b" )])
604634 expected = CompiledSql ("SELECT * WHERE a = $p0_a AND b = $p1_b" , params = {"p0_a" : 1 , "p1_b" : 2 })
605635 assert result == expected
606636
607637 def test_duplicate_param_names_raises (self ):
608638 with pytest .raises (ValueError , match = "Duplicate parameter names" ):
609- compile_parts (
610- [
611- Param (value = 1 , name = "x" , exact = True ),
612- Param (value = 2 , name = "x" , exact = True ),
613- ]
614- )
639+ compile_parts ([param (1 , "x" , exact = True ), param (2 , "x" , exact = True )])
615640
616641 def test_unnamed_params_get_sequential_names (self ):
617- result = compile_parts (
618- [
619- "a = " ,
620- Param (value = 1 ),
621- " AND b = " ,
622- Param (value = 2 ),
623- ]
624- )
642+ result = compile_parts (["a = " , param (1 ), " AND b = " , param (2 )])
625643 expected = CompiledSql ("a = $p0 AND b = $p1" , params = {"p0" : 1 , "p1" : 2 })
626644 assert result == expected
627645
@@ -630,11 +648,11 @@ def test_exact_param_causes_counter_gap(self):
630648 result = compile_parts (
631649 [
632650 "a = " ,
633- Param ( value = 1 , name = "x" ), # → p0_x
651+ param ( 1 , "x" ), # → p0_x
634652 " AND b = " ,
635- Param ( value = 2 , name = "b" , exact = True ), # → b (exact), but counter increments
653+ param ( 2 , "b" , exact = True ), # → b (exact), but counter increments
636654 " AND c = " ,
637- Param ( value = 3 , name = "y" ), # → p2_y (not p1_y!)
655+ param ( 3 , "y" ), # → p2_y (not p1_y!)
638656 ]
639657 )
640658 expected = CompiledSql ("a = $p0_x AND b = $b AND c = $p2_y" , params = {"p0_x" : 1 , "b" : 2 , "p2_y" : 3 })
@@ -651,7 +669,7 @@ def test_adjacent_strings(self):
651669 assert result == expected
652670
653671 def test_param_with_none_value (self ):
654- result = compile_parts (["SELECT " , Param ( value = None , name = "x" )])
672+ result = compile_parts (["SELECT " , param ( None , "x" )])
655673 expected = CompiledSql ("SELECT $p0_x" , params = {"p0_x" : None })
656674 assert result == expected
657675
@@ -733,7 +751,7 @@ def test_protocol_check_negative(self):
733751 assert not isinstance (42 , IntoInterpolation )
734752
735753 def test_param_interpolation_satisfies (self ):
736- pi = ParamInterpolation (Param ( value = 1 ))
754+ pi = ParamInterpolation (param ( 1 ))
737755 assert isinstance (pi , IntoInterpolation )
738756
739757
@@ -799,17 +817,12 @@ def test_strings_joined(self):
799817 assert result == CompiledSql ("SELECT * FROM users" , {})
800818
801819 def test_param_in_list (self ):
802- result = compile ("SELECT * FROM users WHERE id = " , Param ( value = 5 , name = "id" ))
820+ result = compile ("SELECT * FROM users WHERE id = " , param ( 5 , "id" ))
803821 expected = CompiledSql ("SELECT * FROM users WHERE id = $p0_id" , {"p0_id" : 5 })
804822 assert expected == result
805823
806824 def test_multiple_params_in_list (self ):
807- result = compile (
808- "SELECT * FROM users WHERE name = " ,
809- Param (value = "Alice" , name = "name" ),
810- " AND age > " ,
811- Param (value = 18 , name = "age" ),
812- )
825+ result = compile ("SELECT * FROM users WHERE name = " , param ("Alice" , "name" ), " AND age > " , param (18 , "age" ))
813826 expected = CompiledSql (
814827 "SELECT * FROM users WHERE name = $p0_name AND age > $p1_age" ,
815828 {"p0_name" : "Alice" , "p1_age" : 18 },
@@ -939,8 +952,7 @@ def test_none_param(self):
939952
940953 def test_param_object_in_interpolation_preserves_name (self ):
941954 """An explicit Param used in an interpolation should keep its name."""
942- p = Param (value = 42 , name = "custom_name" )
943- interp = FakeInterpolation (value = p , expression = "p" )
955+ interp = FakeInterpolation (value = param (42 , "custom_name" ), expression = "p" )
944956 result = template ("SELECT " , interp , "" ).compile ()
945957 expected = CompiledSql ("SELECT $custom_name" , params = {"custom_name" : 42 })
946958 assert result == expected
0 commit comments