@@ -117,6 +117,12 @@ pub enum TableConstraint {
117117 ///
118118 /// [1]: https://www.postgresql.org/docs/current/sql-altertable.html
119119 UniqueUsingIndex ( ConstraintUsingIndex ) ,
120+ /// PostgreSQL `EXCLUDE` constraint.
121+ ///
122+ /// `[ CONSTRAINT <name> ] EXCLUDE [ USING <index_method> ] ( <element> WITH <operator> [, ...] ) [ INCLUDE (<cols>) ] [ WHERE (<predicate>) ]`
123+ ///
124+ /// See <https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-EXCLUDE>
125+ Exclusion ( ExclusionConstraint ) ,
120126}
121127
122128impl From < UniqueConstraint > for TableConstraint {
@@ -155,6 +161,12 @@ impl From<FullTextOrSpatialConstraint> for TableConstraint {
155161 }
156162}
157163
164+ impl From < ExclusionConstraint > for TableConstraint {
165+ fn from ( constraint : ExclusionConstraint ) -> Self {
166+ TableConstraint :: Exclusion ( constraint)
167+ }
168+ }
169+
158170impl fmt:: Display for TableConstraint {
159171 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
160172 match self {
@@ -166,6 +178,7 @@ impl fmt::Display for TableConstraint {
166178 TableConstraint :: FulltextOrSpatial ( constraint) => constraint. fmt ( f) ,
167179 TableConstraint :: PrimaryKeyUsingIndex ( c) => c. fmt_with_keyword ( f, "PRIMARY KEY" ) ,
168180 TableConstraint :: UniqueUsingIndex ( c) => c. fmt_with_keyword ( f, "UNIQUE" ) ,
181+ TableConstraint :: Exclusion ( constraint) => constraint. fmt ( f) ,
169182 }
170183 }
171184}
@@ -603,3 +616,86 @@ impl crate::ast::Spanned for ConstraintUsingIndex {
603616 start. union ( & end)
604617 }
605618}
619+
620+ /// One element in an `EXCLUDE` constraint's element list.
621+ ///
622+ /// `<expr> WITH <operator>`
623+ ///
624+ /// See <https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-EXCLUDE>
625+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
626+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
627+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
628+ pub struct ExclusionElement {
629+ /// The index expression or column name.
630+ pub expr : Expr ,
631+ /// The exclusion operator (e.g. `&&`, `<->`, `=`).
632+ pub operator : String ,
633+ }
634+
635+ impl fmt:: Display for ExclusionElement {
636+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
637+ write ! ( f, "{} WITH {}" , self . expr, self . operator)
638+ }
639+ }
640+
641+ /// A PostgreSQL `EXCLUDE` constraint.
642+ ///
643+ /// `[ CONSTRAINT <name> ] EXCLUDE [ USING <index_method> ] ( <element> WITH <operator> [, ...] ) [ INCLUDE (<cols>) ] [ WHERE (<predicate>) ]`
644+ ///
645+ /// See <https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-EXCLUDE>
646+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
647+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
648+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
649+ pub struct ExclusionConstraint {
650+ /// Optional constraint name.
651+ pub name : Option < Ident > ,
652+ /// Optional index method (e.g. `gist`, `spgist`).
653+ pub index_method : Option < Ident > ,
654+ /// The list of index expressions with their exclusion operators.
655+ pub elements : Vec < ExclusionElement > ,
656+ /// Optional list of additional columns to include in the index.
657+ pub include : Vec < Ident > ,
658+ /// Optional `WHERE` predicate to restrict the constraint to a subset of rows.
659+ pub where_clause : Option < Box < Expr > > ,
660+ /// Optional constraint characteristics like `DEFERRABLE`.
661+ pub characteristics : Option < ConstraintCharacteristics > ,
662+ }
663+
664+ impl fmt:: Display for ExclusionConstraint {
665+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
666+ use crate :: ast:: ddl:: display_constraint_name;
667+ write ! ( f, "{}EXCLUDE" , display_constraint_name( & self . name) ) ?;
668+ if let Some ( method) = & self . index_method {
669+ write ! ( f, " USING {method}" ) ?;
670+ }
671+ write ! ( f, " ({})" , display_comma_separated( & self . elements) ) ?;
672+ if !self . include . is_empty ( ) {
673+ write ! ( f, " INCLUDE ({})" , display_comma_separated( & self . include) ) ?;
674+ }
675+ if let Some ( predicate) = & self . where_clause {
676+ write ! ( f, " WHERE ({predicate})" ) ?;
677+ }
678+ if let Some ( characteristics) = & self . characteristics {
679+ write ! ( f, " {characteristics}" ) ?;
680+ }
681+ Ok ( ( ) )
682+ }
683+ }
684+
685+ impl crate :: ast:: Spanned for ExclusionConstraint {
686+ fn span ( & self ) -> Span {
687+ fn union_spans < I : Iterator < Item = Span > > ( iter : I ) -> Span {
688+ Span :: union_iter ( iter)
689+ }
690+
691+ union_spans (
692+ self . name
693+ . iter ( )
694+ . map ( |i| i. span )
695+ . chain ( self . index_method . iter ( ) . map ( |i| i. span ) )
696+ . chain ( self . include . iter ( ) . map ( |i| i. span ) )
697+ . chain ( self . where_clause . iter ( ) . map ( |e| e. span ( ) ) )
698+ . chain ( self . characteristics . iter ( ) . map ( |c| c. span ( ) ) ) ,
699+ )
700+ }
701+ }
0 commit comments