@@ -7,6 +7,7 @@ pub struct Span {
77}
88
99impl Span {
10+ #[ must_use]
1011 pub const fn new ( start : usize , end : usize ) -> Self {
1112 Self { start, end }
1213 }
@@ -29,6 +30,215 @@ pub enum SchemaCommand {
2930 CreateIndex ( CreateIndex ) ,
3031 DropIndex ( DropIndex ) ,
3132 ShowIndexes ( ShowIndexes ) ,
33+ CreateConstraint ( CreateConstraint ) ,
34+ DropConstraint ( DropConstraint ) ,
35+ ShowConstraints ( ShowConstraints ) ,
36+ }
37+
38+ #[ derive( Debug , Clone ) ]
39+ pub struct CreateConstraint {
40+ pub name : ConstraintNameSpec ,
41+ pub if_not_exists : bool ,
42+ pub entity : IndexEntityKind ,
43+ /// Pattern variable in the `FOR` clause (`n`, `r`).
44+ pub variable : String ,
45+ /// Label / rel-type. Always present — constraints don't accept the
46+ /// wildcard form that LOOKUP indexes do.
47+ pub label : String ,
48+ pub properties : Vec < String > ,
49+ pub kind : ConstraintKind ,
50+ pub span : Span ,
51+ }
52+
53+ #[ derive( Debug , Clone ) ]
54+ pub struct DropConstraint {
55+ pub name : ConstraintNameSpec ,
56+ pub if_exists : bool ,
57+ pub span : Span ,
58+ }
59+
60+ #[ derive( Debug , Clone ) ]
61+ pub struct ShowConstraints {
62+ pub pipeline : Option < ShowPipeline > ,
63+ pub span : Span ,
64+ }
65+
66+ /// `SHOW INDEXES YIELD … [WHERE …] [RETURN …]` tail. Modelled after the
67+ /// Neo4j syntax: YIELD is the anchor, optional WHERE filters the
68+ /// yielded rows, optional RETURN reprojects them. ORDER BY / SKIP /
69+ /// LIMIT can appear on either YIELD or RETURN — semantically applied
70+ /// to the rows at that stage.
71+ #[ derive( Debug , Clone ) ]
72+ pub struct ShowPipeline {
73+ pub yield_part : ShowYield ,
74+ pub where_ : Option < Expr > ,
75+ pub return_part : Option < ShowReturn > ,
76+ pub span : Span ,
77+ }
78+
79+ #[ derive( Debug , Clone ) ]
80+ pub struct ShowYield {
81+ /// `YIELD *` — pass every catalog column through unchanged.
82+ pub star : bool ,
83+ /// `YIELD a, b AS x` items (empty when `star` is true).
84+ pub items : Vec < YieldItem > ,
85+ pub order : Vec < SortItem > ,
86+ pub skip : Option < Expr > ,
87+ pub limit : Option < Expr > ,
88+ pub span : Span ,
89+ }
90+
91+ #[ derive( Debug , Clone ) ]
92+ pub struct ShowReturn {
93+ pub items : Vec < ProjectionItem > ,
94+ pub order : Vec < SortItem > ,
95+ pub skip : Option < Expr > ,
96+ pub limit : Option < Expr > ,
97+ pub span : Span ,
98+ }
99+
100+ /// Type filter for `SHOW [TYPE] INDEXES`. `All` is the explicit
101+ /// unfiltered form; `Fulltext` and `Vector` parse but yield no rows
102+ /// because those index types aren't backed by anything in the catalog
103+ /// yet.
104+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
105+ pub enum IndexKindFilter {
106+ All ,
107+ Range ,
108+ Text ,
109+ Point ,
110+ Lookup ,
111+ Fulltext ,
112+ Vector ,
113+ }
114+
115+ #[ derive( Debug , Clone ) ]
116+ pub enum ConstraintNameSpec {
117+ Literal ( String ) ,
118+ Parameter ( String ) ,
119+ }
120+
121+ #[ derive( Debug , Clone , PartialEq ) ]
122+ pub enum ConstraintKind {
123+ /// `IS UNIQUE` — single or composite.
124+ Unique ,
125+ /// `IS NOT NULL` — single property only.
126+ Existence ,
127+ /// `IS NODE KEY` — single or composite, node only.
128+ NodeKey ,
129+ /// `IS RELATIONSHIP KEY` — single or composite, relationship only.
130+ RelationshipKey ,
131+ /// `IS :: Type` — single property only.
132+ PropertyType ( PropertyTypeExpr ) ,
133+ }
134+
135+ impl ConstraintKind {
136+ /// Human-readable tag for SHOW CONSTRAINTS and diagnostics.
137+ #[ must_use]
138+ pub fn type_tag ( & self , entity : IndexEntityKind ) -> & ' static str {
139+ match ( self , entity) {
140+ ( ConstraintKind :: Unique , IndexEntityKind :: Node ) => "NODE_PROPERTY_UNIQUENESS" ,
141+ ( ConstraintKind :: Unique , IndexEntityKind :: Relationship ) => {
142+ "RELATIONSHIP_PROPERTY_UNIQUENESS"
143+ }
144+ ( ConstraintKind :: Existence , IndexEntityKind :: Node ) => "NODE_PROPERTY_EXISTENCE" ,
145+ ( ConstraintKind :: Existence , IndexEntityKind :: Relationship ) => {
146+ "RELATIONSHIP_PROPERTY_EXISTENCE"
147+ }
148+ ( ConstraintKind :: NodeKey , _) => "NODE_KEY" ,
149+ ( ConstraintKind :: RelationshipKey , _) => "RELATIONSHIP_KEY" ,
150+ ( ConstraintKind :: PropertyType ( _) , IndexEntityKind :: Node ) => "NODE_PROPERTY_TYPE" ,
151+ ( ConstraintKind :: PropertyType ( _) , IndexEntityKind :: Relationship ) => {
152+ "RELATIONSHIP_PROPERTY_TYPE"
153+ }
154+ }
155+ }
156+ }
157+
158+ /// A closed dynamic union of property types: `T1 | T2 | ...`. A single
159+ /// type is represented as a one-element union.
160+ #[ derive( Debug , Clone , PartialEq ) ]
161+ pub struct PropertyTypeExpr {
162+ pub alternatives : Vec < PropertyTypeTerm > ,
163+ }
164+
165+ #[ derive( Debug , Clone , PartialEq ) ]
166+ pub enum PropertyTypeTerm {
167+ Scalar ( ScalarType ) ,
168+ List {
169+ inner : Box < PropertyTypeTerm > ,
170+ /// `LIST<X NOT NULL>` is the only fully-supported list shape in
171+ /// Neo4j compatibility mode; we keep the flag for grammar fidelity
172+ /// even though we reject `LIST<X>` (nullable elements) at the
173+ /// catalog layer.
174+ not_null : bool ,
175+ } ,
176+ Vector {
177+ coord : VectorCoordType ,
178+ dimension : u32 ,
179+ } ,
180+ }
181+
182+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
183+ pub enum ScalarType {
184+ Boolean ,
185+ String ,
186+ Integer ,
187+ Float ,
188+ Date ,
189+ LocalTime ,
190+ ZonedTime ,
191+ LocalDateTime ,
192+ ZonedDateTime ,
193+ Duration ,
194+ Point ,
195+ Map ,
196+ Any ,
197+ }
198+
199+ impl ScalarType {
200+ #[ must_use]
201+ pub const fn as_str ( self ) -> & ' static str {
202+ match self {
203+ ScalarType :: Boolean => "BOOLEAN" ,
204+ ScalarType :: String => "STRING" ,
205+ ScalarType :: Integer => "INTEGER" ,
206+ ScalarType :: Float => "FLOAT" ,
207+ ScalarType :: Date => "DATE" ,
208+ ScalarType :: LocalTime => "LOCAL TIME" ,
209+ ScalarType :: ZonedTime => "ZONED TIME" ,
210+ ScalarType :: LocalDateTime => "LOCAL DATETIME" ,
211+ ScalarType :: ZonedDateTime => "ZONED DATETIME" ,
212+ ScalarType :: Duration => "DURATION" ,
213+ ScalarType :: Point => "POINT" ,
214+ ScalarType :: Map => "MAP" ,
215+ ScalarType :: Any => "ANY" ,
216+ }
217+ }
218+ }
219+
220+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
221+ pub enum VectorCoordType {
222+ Int8 ,
223+ Int16 ,
224+ Int32 ,
225+ Int64 ,
226+ Float32 ,
227+ Float64 ,
228+ }
229+
230+ impl VectorCoordType {
231+ #[ must_use]
232+ pub const fn as_str ( self ) -> & ' static str {
233+ match self {
234+ VectorCoordType :: Int8 => "INT8" ,
235+ VectorCoordType :: Int16 => "INT16" ,
236+ VectorCoordType :: Int32 => "INT32" ,
237+ VectorCoordType :: Int64 => "INT64" ,
238+ VectorCoordType :: Float32 => "FLOAT32" ,
239+ VectorCoordType :: Float64 => "FLOAT64" ,
240+ }
241+ }
32242}
33243
34244#[ derive( Debug , Clone ) ]
@@ -48,7 +258,12 @@ pub struct CreateIndex {
48258 pub variable : String ,
49259 /// `Some(label_or_type)` for property indexes; `None` for `LOOKUP` token indexes
50260 /// where the label/type is the wildcard captured by `labels(n)` / `type(r)`.
261+ /// For `FULLTEXT` (which accepts `:A|B|C`) this carries the first label; the
262+ /// rest live in `additional_labels`.
51263 pub label : Option < String > ,
264+ /// Extra labels beyond `label`. Only populated for `FULLTEXT` indexes
265+ /// declared with the `(n:A|B|C)` pattern.
266+ pub additional_labels : Vec < String > ,
52267 /// Property keys covered by the index. Empty for `LOOKUP` token indexes.
53268 pub properties : Vec < String > ,
54269 pub options : Option < IndexOptions > ,
@@ -61,15 +276,20 @@ pub enum IndexKind {
61276 Text ,
62277 Point ,
63278 Lookup ,
279+ Vector ,
280+ Fulltext ,
64281}
65282
66283impl IndexKind {
284+ #[ must_use]
67285 pub const fn as_str ( self ) -> & ' static str {
68286 match self {
69287 IndexKind :: Range => "RANGE" ,
70288 IndexKind :: Text => "TEXT" ,
71289 IndexKind :: Point => "POINT" ,
72290 IndexKind :: Lookup => "LOOKUP" ,
291+ IndexKind :: Vector => "VECTOR" ,
292+ IndexKind :: Fulltext => "FULLTEXT" ,
73293 }
74294 }
75295}
@@ -81,6 +301,7 @@ pub enum IndexEntityKind {
81301}
82302
83303impl IndexEntityKind {
304+ #[ must_use]
84305 pub const fn as_str ( self ) -> & ' static str {
85306 match self {
86307 IndexEntityKind :: Node => "NODE" ,
@@ -103,6 +324,11 @@ pub struct IndexOptions {
103324
104325#[ derive( Debug , Clone ) ]
105326pub struct ShowIndexes {
327+ /// Optional index-type filter (e.g. `SHOW RANGE INDEXES`). `None`
328+ /// means no filter clause was written; `Some(IndexKindFilter::All)`
329+ /// is the explicit `SHOW ALL INDEXES` form (semantically the same).
330+ pub filter : Option < IndexKindFilter > ,
331+ pub pipeline : Option < ShowPipeline > ,
106332 pub span : Span ,
107333}
108334
@@ -543,6 +769,7 @@ pub enum ListPredicateKind {
543769}
544770
545771impl Expr {
772+ #[ must_use]
546773 pub fn span ( & self ) -> Span {
547774 match self {
548775 Expr :: Variable ( v) => v. span ,
0 commit comments