@@ -358,9 +358,49 @@ def join(self, parts: Iterable["Fragment"]) -> "Fragment":
358358
359359
360360class SQLFormatter :
361+ """Main SQL formatting class providing the sql() function and utility methods.
362+
363+ This class is instantiated as the global 'sql' object that provides the primary
364+ interface for building SQL fragments. It supports format string syntax with
365+ placeholders and provides utility methods for common SQL operations.
366+ """
361367 def __call__ (
362368 self , fmt : str , * args : Any , preserve_formatting : bool = False , ** kwargs : Any
363369 ) -> Fragment :
370+ """Create a SQL Fragment from a format string with placeholders.
371+
372+ The format string contains literal SQL and may contain positional references
373+ marked by {} and named references marked by {name}. Positional references
374+ must have matching arguments in *args. Named references may have matching
375+ arguments in **kwargs; if not provided, they remain as named slots to be
376+ filled later.
377+
378+ If a referenced argument is a Fragment, it is substituted into the SQL
379+ along with its embedded placeholders. Otherwise, it becomes a placeholder value.
380+
381+ Args:
382+ fmt: SQL format string with {} placeholders
383+ *args: Positional arguments for {} placeholders
384+ preserve_formatting: If True, preserve whitespace; if False, normalize whitespace
385+ **kwargs: Named arguments for {name} placeholders
386+
387+ Returns:
388+ Fragment containing the SQL with placeholders
389+
390+ Raises:
391+ ValueError: If there are unfilled positional arguments
392+
393+ Example:
394+ >>> sql("SELECT * FROM users WHERE id = {}", 42)
395+ Fragment(['SELECT * FROM users WHERE id = ', Placeholder('0', 42)])
396+
397+ >>> sql("SELECT * FROM users WHERE id = {id} AND name = {name}", id=42, name="Alice")
398+ Fragment(['SELECT * FROM users WHERE id = ', Placeholder('id', 42), ' AND name = ', Placeholder('name', 'Alice')])
399+
400+ >>> # Fragments can be embedded
401+ >>> where_clause = sql("active = {}", True)
402+ >>> sql("SELECT * FROM users WHERE {}", where_clause)
403+ """
364404 if not preserve_formatting :
365405 fmt = newline_whitespace_re .sub (" " , fmt )
366406 fmtr = string .Formatter ()
@@ -389,23 +429,110 @@ def __call__(
389429
390430 @staticmethod
391431 def value (value : Any ) -> Fragment :
432+ """Create a Fragment with a single placeholder value.
433+
434+ Equivalent to sql("{}", value) but more explicit.
435+
436+ Args:
437+ value: The value to create a placeholder for
438+
439+ Returns:
440+ Fragment containing a single placeholder
441+
442+ Example:
443+ >>> sql.value(42)
444+ Fragment([Placeholder('value', 42)])
445+ """
392446 placeholder = Placeholder ("value" , value )
393447 return Fragment ([placeholder ])
394448
395449 @staticmethod
396450 def escape (value : Any ) -> Fragment :
451+ """Create a Fragment with a value escaped and embedded into the SQL.
452+
453+ Unlike placeholders, escaped values are embedded directly into the SQL text.
454+ Types currently supported are strings, floats, ints, UUIDs, None, and
455+ sequences of the above. Use with caution and only for trusted values.
456+
457+ Args:
458+ value: The value to escape and embed
459+
460+ Returns:
461+ Fragment with the escaped value as literal SQL
462+
463+ Example:
464+ >>> list(sql("SELECT * FROM tbl WHERE qty = ANY({})", sql.escape([1, 3, 5])))
465+ ['SELECT * FROM tbl WHERE qty = ANY(ARRAY[1, 3, 5])']
466+
467+ >>> # Compare to placeholder version:
468+ >>> list(sql("SELECT * FROM tbl WHERE qty = ANY({})", [1, 3, 5]))
469+ ['SELECT * FROM tbl WHERE qty = ANY($1)', [1, 3, 5]]
470+
471+ Note:
472+ Burning invariant values into the query can potentially help the query optimizer.
473+ """
397474 return lit (escape (value ))
398475
399476 @staticmethod
400477 def slot (name : str ) -> Fragment :
478+ """Create a Fragment with a single empty slot.
479+
480+ Equivalent to sql("{name}") but more explicit.
481+
482+ Args:
483+ name: The name of the slot
484+
485+ Returns:
486+ Fragment containing a single slot
487+
488+ Example:
489+ >>> template = sql("SELECT * FROM users WHERE {}", sql.slot("condition"))
490+ >>> query = template.fill(condition=sql("active = {}", True))
491+ """
401492 return Fragment ([Slot (name )])
402493
403494 @staticmethod
404495 def literal (text : str ) -> Fragment :
496+ """Create a Fragment with literal SQL text.
497+
498+ No substitution of any kind is performed. Be very careful of SQL injection
499+ when using this method.
500+
501+ Args:
502+ text: Raw SQL text to include
503+
504+ Returns:
505+ Fragment containing the literal SQL
506+
507+ Warning:
508+ Only use with trusted SQL text to avoid SQL injection vulnerabilities.
509+
510+ Example:
511+ >>> sql.literal("ORDER BY created_at DESC")
512+ Fragment(['ORDER BY created_at DESC'])
513+ """
405514 return Fragment ([text ])
406515
407516 @staticmethod
408517 def identifier (name : str , prefix : Optional [str ] = None ) -> Fragment :
518+ """Create a Fragment with a quoted SQL identifier.
519+
520+ Creates a properly quoted identifier name, optionally with a dotted prefix
521+ for schema or table qualification.
522+
523+ Args:
524+ name: The identifier name to quote
525+ prefix: Optional prefix (schema, table, etc.)
526+
527+ Returns:
528+ Fragment containing the quoted identifier
529+
530+ Example:
531+ >>> list(sql("SELECT {col} FROM {table}",
532+ ... col=sql.identifier("user_name"),
533+ ... table=sql.identifier("users", prefix="public")))
534+ ['SELECT "user_name" FROM "public"."users"']
535+ """
409536 if prefix :
410537 return lit (f"{ quote_identifier (prefix )} .{ quote_identifier (name )} " )
411538 else :
@@ -418,6 +545,24 @@ def all(self, parts: Iterable[Fragment]) -> Fragment: ... # pragma: no cover
418545 def all (self , * parts : Fragment ) -> Fragment : ... # pragma: no cover
419546
420547 def all (self , * parts ) -> Fragment : # type: ignore
548+ """Join fragments with AND, returning TRUE if no parts provided.
549+
550+ Creates a SQL Fragment joining the fragments in parts together with AND.
551+ If parts is empty, returns TRUE. Each fragment is wrapped in parentheses.
552+
553+ Args:
554+ *parts: Fragment objects to join, or single iterable of fragments
555+
556+ Returns:
557+ Fragment containing the AND-joined conditions
558+
559+ Example:
560+ >>> where = [sql("a = {}", 42), sql("x <> {}", "foo")]
561+ >>> list(sql("SELECT * FROM tbl WHERE {}", sql.all(where)))
562+ ['SELECT * FROM tbl WHERE (a = $1) AND (x <> $2)', 42, 'foo']
563+ >>> list(sql("SELECT * FROM tbl WHERE {}", sql.all([])))
564+ ['SELECT * FROM tbl WHERE TRUE']
565+ """
421566 if parts and not isinstance (parts [0 ], Fragment ):
422567 parts = parts [0 ]
423568 return any_all (list (parts ), "AND" , "TRUE" )
@@ -429,6 +574,24 @@ def any(self, parts: Iterable[Fragment]) -> Fragment: ... # pragma: no cover
429574 def any (self , * parts : Fragment ) -> Fragment : ... # pragma: no cover
430575
431576 def any (self , * parts ) -> Fragment : # type: ignore
577+ """Join fragments with OR, returning FALSE if no parts provided.
578+
579+ Creates a SQL Fragment joining the fragments in parts together with OR.
580+ If parts is empty, returns FALSE. Each fragment is wrapped in parentheses.
581+
582+ Args:
583+ *parts: Fragment objects to join, or single iterable of fragments
584+
585+ Returns:
586+ Fragment containing the OR-joined conditions
587+
588+ Example:
589+ >>> where = [sql("a = {}", 42), sql("x <> {}", "foo")]
590+ >>> list(sql("SELECT * FROM tbl WHERE {}", sql.any(where)))
591+ ['SELECT * FROM tbl WHERE (a = $1) OR (x <> $2)', 42, 'foo']
592+ >>> list(sql("SELECT * FROM tbl WHERE {}", sql.any([])))
593+ ['SELECT * FROM tbl WHERE FALSE']
594+ """
432595 if parts and not isinstance (parts [0 ], Fragment ):
433596 parts = parts [0 ]
434597 return any_all (list (parts ), "OR" , "FALSE" )
@@ -440,18 +603,66 @@ def list(self, parts: Iterable[Fragment]) -> Fragment: ... # pragma: no cover
440603 def list (self , * parts : Fragment ) -> Fragment : ... # pragma: no cover
441604
442605 def list (self , * parts ) -> Fragment : # type: ignore
606+ """Join fragments with commas.
607+
608+ Creates a SQL Fragment joining the fragments in parts together with commas.
609+ Commonly used for column lists, value lists, etc.
610+
611+ Args:
612+ *parts: Fragment objects to join, or single iterable of fragments
613+
614+ Returns:
615+ Fragment containing the comma-separated fragments
616+
617+ Example:
618+ >>> cols = [sql.identifier("id"), sql.identifier("name"), sql.identifier("email")]
619+ >>> list(sql("SELECT {} FROM users", sql.list(cols)))
620+ ['SELECT "id", "name", "email" FROM users']
621+ """
443622 if parts and not isinstance (parts [0 ], Fragment ):
444623 parts = parts [0 ]
445624 return Fragment (list (join_parts (parts , infix = ", " )))
446625
447626 def unnest (self , data : Iterable [Sequence [Any ]], types : Iterable [str ]) -> Fragment :
627+ """Create a Fragment containing an UNNEST expression with associated data.
628+
629+ The data is specified as tuples (in the "database columns" sense) in data,
630+ and the PostgreSQL types must be specified in types. The data is transposed
631+ into the correct form for UNNEST and embedded as placeholders.
632+
633+ Args:
634+ data: Iterable of sequences, where each sequence represents a row
635+ types: Iterable of PostgreSQL type names for each column
636+
637+ Returns:
638+ Fragment containing UNNEST expression with typed array placeholders
639+
640+ Example:
641+ >>> list(sql("SELECT * FROM {}", sql.unnest([("a", 1), ("b", 2), ("c", 3)], ["text", "integer"])))
642+ ['SELECT * FROM UNNEST($1::text[], $2::integer[])', ('a', 'b', 'c'), (1, 2, 3)]
643+
644+ >>> # Useful for bulk operations
645+ >>> users_data = [("Alice", 25), ("Bob", 30), ("Charlie", 35)]
646+ >>> insert_query = sql("INSERT INTO users (name, age) SELECT * FROM {}",
647+ ... sql.unnest(users_data, ["text", "integer"]))
648+ """
448649 nested = [nest_for_type (x , t ) for x , t in zip (zip (* data ), types )]
449650 if not nested :
450651 nested = [nest_for_type ([], t ) for t in types ]
451652 return Fragment (["UNNEST(" , self .list (nested ), ")" ])
452653
453654
454655sql = SQLFormatter ()
656+ """Global SQLFormatter instance providing the main sql() function and utilities.
657+
658+ This is the primary interface for creating SQL fragments. Use it to:
659+ - Create fragments: sql("SELECT * FROM users WHERE id = {}", user_id)
660+ - Join fragments: sql.all([condition1, condition2])
661+ - Create identifiers: sql.identifier("table_name")
662+ - And much more
663+
664+ See SQLFormatter class documentation for all available methods.
665+ """
455666
456667
457668json_types = ("JSON" , "JSONB" )
0 commit comments