selene-db-core 1.3.0

Foundation types for the selene-db ISO/IEC 39075:2024 GQL property graph engine.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
//! ISO/IEC 39075:2024 feature and implementation-defined registers.
//!
//! This file is the canonical source for selene-db's optional-feature language
//! claim. The markdown tables for Spec 01, Spec 07, and Spec 09 are rendered or
//! checked from these constants by `build/regen_feature_docs.sh`.

use std::fmt;

/// Stable ISO GQL feature identifier.
///
/// The private field makes the set closed to this module while preserving the
/// spec's string IDs as the stable ABI-facing representation.
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct FeatureId(&'static str);

impl FeatureId {
    /// Return the ISO feature ID string, such as `GP04`.
    pub const fn as_str(self) -> &'static str {
        self.0
    }
}

impl fmt::Display for FeatureId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.as_str())
    }
}

macro_rules! feature_ids {
    ($($name:ident = $id:literal => $display:literal;)*) => {
        impl FeatureId {
            $(
                #[doc = concat!("`", $display, "`")]
                pub const $name: FeatureId = FeatureId($id);
            )*
        }

        /// Every feature ID currently referenced by selene-db specs.
        pub const REFERENCED_FEATURES: &[(FeatureId, &str)] = &[
            $((FeatureId::$name, $display),)*
        ];
    };
}

feature_ids! {
    G002 = "G002" => "Different-edges match mode";
    G003 = "G003" => "Explicit REPEATABLE ELEMENTS keyword";
    G010 = "G010" => "Explicit WALK keyword";
    G011 = "G011" => "Advanced path modes: TRAIL";
    G012 = "G012" => "Advanced path modes: SIMPLE";
    G013 = "G013" => "Advanced path modes: ACYCLIC";
    G014 = "G014" => "Explicit PATH/PATHS keywords";
    G015 = "G015" => "All path search: explicit ALL keyword";
    G016 = "G016" => "Any path search";
    G017 = "G017" => "All shortest path search";
    G018 = "G018" => "Any shortest path search";
    G019 = "G019" => "Counted shortest path search";
    G020 = "G020" => "Counted shortest group search";
    G036 = "G036" => "Quantified edges";
    G037 = "G037" => "Questioned paths";
    G060 = "G060" => "Bounded graph pattern quantifiers";
    G061 = "G061" => "Unbounded graph pattern quantifiers";
    G100 = "G100" => "ELEMENT_ID function";
    G110 = "G110" => "IS DIRECTED predicate";
    G111 = "G111" => "IS LABELED predicate";
    G112 = "G112" => "IS SOURCE and IS DESTINATION predicate";
    G113 = "G113" => "ALL_DIFFERENT predicate";
    G114 = "G114" => "SAME predicate";
    G115 = "G115" => "PROPERTY_EXISTS predicate";
    GA01 = "GA01" => "IEEE 754 floating point operations";
    GA07 = "GA07" => "Ordering by discarded binding variables";
    GC02 = "GC02" => "Graph schema management: IF [ NOT ] EXISTS";
    GC03 = "GC03" => "Graph type: IF [ NOT ] EXISTS";
    GC04 = "GC04" => "Graph management";
    GC05 = "GC05" => "Graph management: IF [ NOT ] EXISTS";
    GD01 = "GD01" => "Updatable graphs";
    GE04 = "GE04" => "Graph parameters";
    GE05 = "GE05" => "Binding table parameters";
    GE06 = "GE06" => "Path value construction";
    GE07 = "GE07" => "Boolean XOR";
    // ISO/IEC 39075:2024 Annex D Table D.1 row 77 / subclause 17.7: GE08 is
    // "Reference parameters", NOT a CAST feature. selene-db does not implement
    // reference parameters, so GE08 is referenced-but-not-supported (see
    // NOT_SUPPORTED_RATIONALE). CAST is `<cast specification>` (§20.8 /
    // Table D.1 row 53 = GA05, "Cast specification"). Per ISO Annex A item 52
    // (Feature GA05), without GA05 "conforming GQL language shall not contain a
    // <cast specification>" — CAST is gated behind GA05, NOT baseline. selene-db
    // implements the cast construct, so it claims GA05 in SUPPORTED_FEATURES and
    // stamps it on every `ValueExpr::Cast`. GA06 is the sibling construct-level
    // feature for `IS [NOT] TYPED <value type>` (§19.6); selene-db implements that
    // value type predicate and stamps it on every typed `IsCheckKind`.
    GE08 = "GE08" => "Reference parameters";
    GA05 = "GA05" => "Cast specification";
    GA06 = "GA06" => "Value type predicate";
    GF01 = "GF01" => "Enhanced numeric functions";
    GF02 = "GF02" => "Trigonometric functions";
    GF03 = "GF03" => "Logarithmic functions";
    GF04 = "GF04" => "Enhanced path functions";
    GF05 = "GF05" => "Multi-character TRIM function";
    GF06 = "GF06" => "Explicit TRIM function";
    GF07 = "GF07" => "Byte string TRIM function";
    GF10 = "GF10" => "Advanced aggregate functions: general set functions";
    GF11 = "GF11" => "Advanced aggregate functions: binary set functions";
    GF12 = "GF12" => "CARDINALITY function";
    GF13 = "GF13" => "SIZE function";
    GF20 = "GF20" => "Aggregate functions in sort keys";
    GL01 = "GL01" => "Hexadecimal literals";
    GL02 = "GL02" => "Octal literals";
    GL03 = "GL03" => "Binary literals";
    GL04 = "GL04" => "Exact number in common notation without suffix";
    GL05 = "GL05" => "Exact number in common notation or as decimal integer with suffix";
    GL06 = "GL06" => "Exact number in scientific notation with suffix";
    GL07 = "GL07" => "Approximate number in common notation or as decimal integer with suffix";
    GL08 = "GL08" => "Approximate number in scientific notation with suffix";
    GL09 = "GL09" => "Optional float number suffix";
    GL10 = "GL10" => "Optional double number suffix";
    GL11 = "GL11" => "Opt-out character escaping";
    IM_UUID = "IM_UUID" => "selene-db UUID extension";
    IM_JSON = "IM_JSON" => "selene-db JSON extension";
    IM_VECTOR = "IM_VECTOR" => "selene-db VECTOR extension";
    IM_EXTENDS = "IM_EXTENDS" => "selene-db EXTENDS type composition extension";
    IM_INDEX_DDL = "IM_INDEX_DDL" => "selene-db named index DDL extension";
    IM_TYPED_PARAMS = "IM_TYPED_PARAMS" => "selene-db inline typed parameter declaration extension";
    IM_TRUNCATE = "IM_TRUNCATE" => "selene-db bulk truncate extension";
    IM_DROP_CASCADE = "IM_DROP_CASCADE" => "selene-db cascading DROP TYPE extension";
    IM_DROP_GRAPH = "IM_DROP_GRAPH" => "selene-db DROP GRAPH factory-reset extension";
    GH02 = "GH02" => "Undirected edge patterns";
    GG01 = "GG01" => "Graph with an open graph type";
    GG02 = "GG02" => "Graph with a closed graph type";
    GG20 = "GG20" => "Explicit element type names";
    GG21 = "GG21" => "Explicit element type key label sets";
    GP01 = "GP01" => "Inline procedure";
    GP02 = "GP02" => "Inline procedure with implicit nested variable scope";
    GP03 = "GP03" => "Inline procedure with explicit nested variable scope";
    GP04 = "GP04" => "Named procedure calls";
    GP05 = "GP05" => "Procedure-local value variable definitions";
    GP06 = "GP06" => "Procedure-local value variable definitions: value variables based on simple expressions";
    GP07 = "GP07" => "Procedure-local value variable definitions: value variable based on subqueries";
    GP08 = "GP08" => "Procedure-local binding table variable definitions";
    GP09 = "GP09" => "Procedure-local binding table variable definitions: binding table variables based on simple expressions or references";
    GP10 = "GP10" => "Procedure-local binding table variable definitions: binding table variables based on subqueries";
    GP11 = "GP11" => "Procedure-local graph variable definitions";
    GP12 = "GP12" => "Procedure-local graph variable definitions: graph variables based on simple expressions or references";
    GP13 = "GP13" => "Procedure-local graph variable definitions: graph variables based on subqueries";
    GP14 = "GP14" => "Binding tables as procedure arguments";
    GP15 = "GP15" => "Graphs as procedure arguments";
    GP18 = "GP18" => "Catalog and data statement mixing";
    GQ02 = "GQ02" => "Composite query: OTHERWISE";
    GQ03 = "GQ03" => "Composite query: UNION";
    GQ04 = "GQ04" => "Composite query: EXCEPT DISTINCT";
    GQ05 = "GQ05" => "Composite query: EXCEPT ALL";
    GQ06 = "GQ06" => "Composite query: INTERSECT DISTINCT";
    GQ07 = "GQ07" => "Composite query: INTERSECT ALL";
    GQ08 = "GQ08" => "FILTER statement";
    GQ09 = "GQ09" => "LET statement";
    GQ10 = "GQ10" => "FOR statement: list value support";
    GQ11 = "GQ11" => "FOR statement: WITH ORDINALITY";
    GQ12 = "GQ12" => "ORDER BY and page statement: OFFSET clause";
    GQ13 = "GQ13" => "ORDER BY and page statement: LIMIT clause";
    GQ14 = "GQ14" => "Complex expressions in sort keys";
    GQ15 = "GQ15" => "GROUP BY clause";
    GQ16 = "GQ16" => "Pre-projection aliases in sort keys";
    GQ18 = "GQ18" => "Scalar subqueries";
    GQ20 = "GQ20" => "Advanced linear composition with NEXT";
    GQ24 = "GQ24" => "FOR statement: WITH OFFSET";
    GS01 = "GS01" => "SESSION SET command: session-local graph parameters";
    GS02 = "GS02" => "SESSION SET command: session-local binding table parameters";
    GS03 = "GS03" => "SESSION SET command: session-local value parameters";
    GS04 = "GS04" => "SESSION RESET command: reset all characteristics";
    GS05 = "GS05" => "SESSION RESET command: reset session schema";
    GS06 = "GS06" => "SESSION RESET command: reset session graph";
    GS07 = "GS07" => "SESSION RESET command: reset time zone displacement";
    GS08 = "GS08" => "SESSION RESET command: reset all session parameters";
    GS10 = "GS10" => "SESSION SET command: session-local binding table parameters based on subqueries";
    GS11 = "GS11" => "SESSION SET command: session-local value parameters based on subqueries";
    GS12 = "GS12" => "SESSION SET command: session-local graph parameters based on simple expressions or references";
    GS13 = "GS13" => "SESSION SET command: session-local binding table parameters based on simple expressions or references";
    GS14 = "GS14" => "SESSION SET command: session-local value parameters based on simple expressions";
    GS15 = "GS15" => "SESSION SET command: set time zone displacement";
    GS16 = "GS16" => "SESSION RESET command: reset individual session parameters";
    GT01 = "GT01" => "Explicit transaction commands";
    GT03 = "GT03" => "Use of multiple graphs in a transaction";
    GV01 = "GV01" => "8 bit unsigned integer numbers";
    GV02 = "GV02" => "8 bit signed integer numbers";
    GV03 = "GV03" => "16 bit unsigned integer numbers";
    GV04 = "GV04" => "16 bit signed integer numbers";
    GV05 = "GV05" => "Small unsigned integer numbers";
    GV06 = "GV06" => "32 bit unsigned integer numbers";
    GV07 = "GV07" => "32 bit signed integer numbers";
    GV08 = "GV08" => "Regular unsigned integer numbers";
    GV09 = "GV09" => "Specified integer number precision";
    GV10 = "GV10" => "Big unsigned integer numbers";
    GV11 = "GV11" => "64 bit unsigned integer numbers";
    GV12 = "GV12" => "64 bit signed integer numbers";
    GV13 = "GV13" => "128 bit unsigned integer numbers";
    GV14 = "GV14" => "128 bit signed integer numbers";
    GV15 = "GV15" => "256 bit unsigned integer numbers";
    GV16 = "GV16" => "256 bit signed integer numbers";
    GV17 = "GV17" => "Decimal numbers";
    GV18 = "GV18" => "Small signed integer numbers";
    GV19 = "GV19" => "Big signed integer numbers";
    GV20 = "GV20" => "16 bit floating point numbers";
    GV21 = "GV21" => "32 bit floating point numbers";
    GV22 = "GV22" => "Specified floating point number precision";
    GV23 = "GV23" => "Floating point type name synonyms";
    GV24 = "GV24" => "64 bit floating point numbers";
    GV25 = "GV25" => "128 bit floating point numbers";
    GV26 = "GV26" => "256 bit floating point numbers";
    GV30 = "GV30" => "Specified character string minimum length";
    GV31 = "GV31" => "Specified character string maximum length";
    GV32 = "GV32" => "Specified character string fixed length";
    GV35 = "GV35" => "Byte string types";
    GV36 = "GV36" => "Specified byte string minimum length";
    GV37 = "GV37" => "Specified byte string maximum length";
    GV38 = "GV38" => "Specified byte string fixed length";
    GV39 = "GV39" => "Temporal types: date, local datetime and local time support";
    GV40 = "GV40" => "Temporal types: zoned datetime and zoned time support";
    GV41 = "GV41" => "Temporal types: duration support";
    GV45 = "GV45" => "Record types";
    GV46 = "GV46" => "Closed record types";
    GV47 = "GV47" => "Open record types";
    GV48 = "GV48" => "Nested record types";
    GV50 = "GV50" => "List value types";
    GV55 = "GV55" => "Path value types";
    GV60 = "GV60" => "Graph reference value types";
    GV61 = "GV61" => "Binding table reference value types";
    GV66 = "GV66" => "Open dynamic union types";
    GV67 = "GV67" => "Closed dynamic union types";
    GV68 = "GV68" => "Dynamic property value types";
    GV90 = "GV90" => "Explicit value type nullability";
}

/// Supported optional feature set.
///
/// ISO sources: Annex A numbered pp. 522-554; Annex D Table D.1 numbered
/// pp. 577-586. Implication closure is handled by the flagger/planner.
pub const SUPPORTED_FEATURES: &[FeatureId] = &[
    FeatureId::G002,
    FeatureId::G003,
    FeatureId::G010,
    FeatureId::G011,
    FeatureId::G012,
    FeatureId::G013,
    // G014 "Explicit PATH/PATHS keywords" (ISO §16.6 <path or paths>, Annex A
    // §16.6 CR5). The match-prefix grammar parses the optional PATH/PATHS sugar
    // and the flagger stamps G014 iff it is present. Pure surface sugar per
    // §1.2.4 — inert at runtime. G014 has NO ISO §24.7 implied-feature
    // relationship (it appears in neither column of Table 10).
    FeatureId::G014,
    FeatureId::G015,
    FeatureId::G016,
    FeatureId::G017,
    FeatureId::G018,
    FeatureId::G019,
    FeatureId::G020,
    FeatureId::G036,
    FeatureId::G037,
    FeatureId::G060,
    FeatureId::G061,
    FeatureId::G100,
    FeatureId::G110,
    FeatureId::G111,
    FeatureId::G112,
    FeatureId::G113,
    FeatureId::G114,
    FeatureId::G115,
    FeatureId::GA01,
    FeatureId::GA05,
    FeatureId::GA06,
    FeatureId::GA07,
    FeatureId::GC03,
    FeatureId::GD01,
    FeatureId::GE04,
    FeatureId::GE05,
    FeatureId::GE06,
    FeatureId::GE07,
    FeatureId::GF01,
    FeatureId::GF02,
    FeatureId::GF03,
    FeatureId::GF04,
    FeatureId::GF05,
    FeatureId::GF06,
    FeatureId::GF07,
    FeatureId::GF10,
    FeatureId::GF11,
    FeatureId::GF12,
    FeatureId::GF13,
    FeatureId::GF20,
    FeatureId::GL01,
    FeatureId::GL02,
    FeatureId::GL03,
    FeatureId::GL04,
    FeatureId::GL05,
    FeatureId::GL06,
    FeatureId::GL07,
    FeatureId::GL08,
    FeatureId::GL09,
    FeatureId::GL10,
    FeatureId::GL11,
    FeatureId::IM_UUID,
    FeatureId::IM_JSON,
    FeatureId::IM_VECTOR,
    FeatureId::IM_EXTENDS,
    FeatureId::IM_INDEX_DDL,
    FeatureId::IM_TYPED_PARAMS,
    FeatureId::IM_TRUNCATE,
    FeatureId::IM_DROP_CASCADE,
    FeatureId::IM_DROP_GRAPH,
    FeatureId::GH02,
    FeatureId::GG01,
    FeatureId::GG02,
    FeatureId::GG20,
    // GG21 "Explicit element type key label sets" — the type-DDL grammar now
    // parses the explicit `<...type key label set>` (`[ <label set phrase> ]
    // <implies>`, the `=>` marker, ISO §18.2/18.3) and the flagger stamps it.
    // Per the §24.7 implied-feature-relationships table GG21 implies GG02
    // ("Graph with a closed graph type"), which is already claimed above, so
    // the claim is implication-consistent. selene-db sets the IL003 key-label-
    // set cardinality cap to 1 (singleton), rejecting cardinality 0 (42012/
    // 42014) and > 1 (42013/42015) per §18.2 SR10/SR11 + §18.3 SR11/SR12 — a
    // conforming impl-defined cap, not a missing feature.
    FeatureId::GG21,
    FeatureId::GP01,
    FeatureId::GP02,
    FeatureId::GP03,
    FeatureId::GP04,
    FeatureId::GQ02,
    FeatureId::GQ03,
    FeatureId::GQ04,
    FeatureId::GQ05,
    FeatureId::GQ06,
    FeatureId::GQ07,
    FeatureId::GQ08,
    FeatureId::GQ09,
    FeatureId::GQ10,
    FeatureId::GQ11,
    FeatureId::GQ12,
    FeatureId::GQ13,
    FeatureId::GQ14,
    FeatureId::GQ15,
    FeatureId::GQ16,
    FeatureId::GQ18,
    FeatureId::GQ20,
    FeatureId::GQ24,
    FeatureId::GS03,
    FeatureId::GS04,
    FeatureId::GS07,
    FeatureId::GS08,
    FeatureId::GS15,
    FeatureId::GS16,
    FeatureId::GT01,
    FeatureId::GV01,
    FeatureId::GV02,
    FeatureId::GV03,
    FeatureId::GV04,
    FeatureId::GV05,
    FeatureId::GV06,
    FeatureId::GV07,
    FeatureId::GV08,
    FeatureId::GV09,
    FeatureId::GV10,
    FeatureId::GV11,
    FeatureId::GV12,
    FeatureId::GV13,
    FeatureId::GV14,
    FeatureId::GV17,
    FeatureId::GV18,
    FeatureId::GV19,
    FeatureId::GV21,
    FeatureId::GV22,
    FeatureId::GV23,
    FeatureId::GV24,
    FeatureId::GV30,
    FeatureId::GV31,
    FeatureId::GV32,
    FeatureId::GV35,
    FeatureId::GV36,
    FeatureId::GV37,
    FeatureId::GV38,
    FeatureId::GV39,
    FeatureId::GV40,
    FeatureId::GV41,
    FeatureId::GV45,
    FeatureId::GV46,
    FeatureId::GV47,
    FeatureId::GV48,
    FeatureId::GV50,
    FeatureId::GV55,
    FeatureId::GV66,
    FeatureId::GV67,
    FeatureId::GV68,
    FeatureId::GV90,
];

/// Rationale for referenced optional features not currently claimed.
///
/// This list is reserved for features that are *parser-reachable but rejected*:
/// each entry is backed by a negative conformance-corpus case proving the
/// `UnsupportedFeature` rejection (see `corpus_covers_feature_register`).
/// Features that have no syntactic surface at all — and so can be neither
/// claimed nor rejected — are NOT listed here; they remain in
/// `REFERENCED_FEATURES` only and surface as the `"referenced"` status in
/// `selene.feature_status()`. GE08 ("Reference parameters", §17.7 —
/// unimplemented) is deliberately in that referenced-only bucket
/// (CONFORMANCE-00). GA05 ("Cast specification", §20.8) and GA06 ("Value type
/// predicate", §19.6) are CLAIMED in `SUPPORTED_FEATURES`: CAST is gated behind
/// GA05, and `IS [NOT] TYPED` is gated behind GA06. GG21 ("Explicit element type
/// key label sets", §18.2/18.3) is now CLAIMED as well: the type-DDL grammar
/// parses the explicit `<...type key label set>` (`=>` marker) and bounds its
/// cardinality to the IL003 singleton cap.
pub const NOT_SUPPORTED_RATIONALE: &[(FeatureId, &str)] = &[
    (
        FeatureId::GP05,
        "procedure-local definitions require the procedure body parser; not yet supported",
    ),
    (
        FeatureId::GP06,
        "procedure-local definitions require the procedure body parser; not yet supported",
    ),
    (
        FeatureId::GP07,
        "procedure-local definitions require the procedure body parser; not yet supported",
    ),
    (
        FeatureId::GP08,
        "procedure-local definitions require the procedure body parser; not yet supported",
    ),
    (
        FeatureId::GP09,
        "procedure-local definitions require the procedure body parser; not yet supported",
    ),
    (
        FeatureId::GP10,
        "procedure-local definitions require the procedure body parser; not yet supported",
    ),
    (
        FeatureId::GP11,
        "procedure-local definitions require the procedure body parser; not yet supported",
    ),
    (
        FeatureId::GP12,
        "procedure-local definitions require the procedure body parser; not yet supported",
    ),
    (
        FeatureId::GP13,
        "procedure-local definitions require the procedure body parser; not yet supported",
    ),
    (
        FeatureId::GP14,
        "procedure-local definitions require the procedure body parser; not yet supported",
    ),
    (
        FeatureId::GP15,
        "procedure-local definitions require the procedure body parser; not yet supported",
    ),
    (
        FeatureId::GP18,
        "mixed catalog/data transaction behavior remains forbidden",
    ),
    (
        FeatureId::GC02,
        "CREATE/DROP SCHEMA is outside the current catalog claim (graph-schema vs graph-type vs graph)",
    ),
    (
        FeatureId::GC04,
        "CREATE GRAPH stays outside the current catalog claim (D1 single-graph embeddable cannot create a second graph); DROP GRAPH is the IM_DROP_GRAPH factory-reset extension, not GC04",
    ),
    (
        FeatureId::GC05,
        "CREATE GRAPH IF NOT EXISTS modifier remains outside the current catalog claim",
    ),
    (
        FeatureId::GS01,
        "SESSION SET <name> GRAPH binds a session-local graph parameter; D1 single-graph embeddable has one graph and no graph-parameter catalog/value slot to bind",
    ),
    (
        FeatureId::GS02,
        "SESSION SET <name> BINDING TABLE binds a typed binding-table reference value (GV61); the reference-type surface is deferred, so D1 has no spelling to bind",
    ),
    (
        FeatureId::GS05,
        "SESSION RESET SCHEMA resets the session schema; D1 single-graph embeddable has no schema layer (section 4.2.5.1) to reset",
    ),
    (
        FeatureId::GS06,
        "SESSION RESET GRAPH resets the session graph; D1 single-graph embeddable has exactly one graph and no working-graph switch to reset",
    ),
    (
        FeatureId::GS10,
        "session-local binding table parameters from subqueries depend on GS02 (binding-table parameters) and a procedure body; both deferred under D1",
    ),
    (
        FeatureId::GS11,
        "session-local value parameters from subqueries depend on procedure-body support; SESSION SET VALUE restricts the RHS to a value expression with no row context",
    ),
    (
        FeatureId::GS12,
        "session-local graph parameters from simple graph expressions/references depend on GS01 (graph parameters); D1-blocked",
    ),
    (
        FeatureId::GS13,
        "session-local binding table parameters from simple expressions/references depend on GS02 (binding-table parameters); deferred",
    ),
    (
        FeatureId::GS14,
        "selene-db evaluates SESSION SET VALUE against an empty binding so the RHS is restricted to a <value specification> (literal/parameter); the full <value expression> form (GS14) is not claimed",
    ),
    (
        FeatureId::GT03,
        "multi-graph transactions are out of scope under the D1 single-graph embeddable model",
    ),
    (
        FeatureId::GV15,
        "256-bit unsigned integers are not represented in Value v1",
    ),
    (
        FeatureId::GV16,
        "256-bit signed integers are not represented in Value v1",
    ),
    (FeatureId::GV20, "FLOAT16 remains deferred"),
    (FeatureId::GV25, "FLOAT128 is deferred"),
    (FeatureId::GV26, "FLOAT256 is deferred"),
    (
        FeatureId::GV60,
        "GRAPH reference type spellings parse to the Flagger, but graph reference value semantics and closed graph constraints remain deferred",
    ),
    (
        FeatureId::GV61,
        "binding table reference types require TABLE field-type descriptors and binding-table value semantics before claiming",
    ),
];

mod annex_b;

pub use annex_b::{ANNEX_B_REGISTER, AnnexBId, ImplDefinedChoice};

/// True when `id` is in the supported feature set.
pub fn is_supported(id: FeatureId) -> bool {
    SUPPORTED_FEATURES.contains(&id)
}

/// Return the ISO display name for a referenced feature ID.
pub fn name_of(id: FeatureId) -> Option<&'static str> {
    REFERENCED_FEATURES
        .iter()
        .find_map(|(feature, name)| (*feature == id).then_some(*name))
}

/// Return a referenced feature ID from its stable string representation.
pub fn feature_id_from_str(id: &str) -> Option<FeatureId> {
    REFERENCED_FEATURES
        .iter()
        .find_map(|(feature, _)| (feature.as_str() == id).then_some(*feature))
}

/// Return the non-support rationale for a referenced feature ID.
pub fn non_supported_rationale(id: FeatureId) -> Option<&'static str> {
    NOT_SUPPORTED_RATIONALE
        .iter()
        .find_map(|(feature, rationale)| (*feature == id).then_some(*rationale))
}

#[cfg(test)]
mod tests;