1use serde::{Deserialize, Serialize};
13
14mod acl_role_specification;
15mod assignment_target;
16mod constraints;
17mod cte;
18mod domains;
19mod events;
20mod expressions;
21mod from;
22mod function_binding;
23mod identity_sequence;
24mod indexes;
25mod interval;
26mod locking;
27mod namespaces;
28mod overriding;
29mod ranges;
30mod relation_hierarchy;
31mod relation_lifecycle;
32mod role_specification;
33mod routine_security;
34mod routines;
35mod sequence;
36mod sequence_declaration;
37mod types;
38
39pub use acl_role_specification::AclRoleSpecification;
40pub use assignment_target::{AssignmentStep, AssignmentTarget};
41pub use constraints::*;
42pub use cte::*;
43pub use domains::*;
44pub use events::*;
45pub use expressions::*;
46pub use from::*;
47pub use function_binding::*;
48pub use identity_sequence::{DeferredSQLError, IdentitySequenceDeclaration, IdentitySequenceName};
49pub use indexes::*;
50pub use interval::*;
51pub use locking::*;
52pub use namespaces::*;
53pub use overriding::OverridingKind;
54pub use ranges::*;
55pub use relation_hierarchy::*;
56pub use relation_lifecycle::*;
57pub use role_specification::RoleSpecification;
58pub use routine_security::*;
59pub use routines::*;
60pub use sequence::*;
61pub use sequence_declaration::{SequenceDeclaration, SequenceOptionValue};
62pub use types::*;
63
64const fn default_include_descendants() -> bool {
65 true
66}
67
68const fn default_true() -> bool {
69 true
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
73pub enum GeneratedColumnKind {
74 Virtual,
75 Stored,
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize)]
79pub struct GeneratedColumn {
80 pub kind: GeneratedColumnKind,
81 pub expression: Box<Expr>,
82 #[serde(default, skip_serializing_if = "Vec::is_empty")]
83 pub function_dependencies: Vec<GeneratedFunctionDependency>,
84}
85
86#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
87pub struct IndexColumnOrder {
88 pub descending: bool,
89 pub nulls_first: bool,
90}
91
92#[derive(Debug, Clone, Serialize, Deserialize)]
93pub struct CreateIndex {
94 #[serde(default)]
95 pub included_columns: Vec<String>,
96 #[serde(default)]
97 pub column_order: Vec<IndexColumnOrder>,
98 #[serde(default)]
99 pub predicate: Option<Box<Expr>>,
100 pub name: Option<String>,
101 pub table: String,
102 pub access_method: String,
104 pub columns: Vec<IndexKey>,
105 #[serde(default)]
106 pub unique: bool,
107 #[serde(default)]
108 pub nulls_not_distinct: bool,
109 pub if_not_exists: bool,
111 pub options: Vec<(String, String)>,
115 #[serde(default, skip_serializing_if = "Vec::is_empty")]
117 pub option_namespaces: Vec<String>,
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize)]
121pub struct DropStmt {
122 pub kind: DropKind,
123 pub names: Vec<String>,
124 pub if_exists: bool,
125 pub cascade: bool,
126}
127
128#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
129pub enum DropKind {
130 Table,
131 ForeignTable,
132 Index,
133 View,
134 MaterializedView,
135 Schema,
136 Sequence,
137 Domain,
138}
139
140#[derive(Debug, Clone, Serialize, Deserialize)]
141pub struct AlterTableStmt {
142 pub table: String,
143 pub qualifier: String,
145 pub if_exists: bool,
146 #[serde(default = "default_true")]
148 pub recurse: bool,
149 pub actions: Vec<AlterTableAction>,
150}
151
152#[derive(Debug, Clone, Serialize, Deserialize)]
153#[expect(
154 clippy::large_enum_variant,
155 reason = "preserves the stable AST serde shape"
156)]
157pub enum AlterTableAction {
158 AddInheritance {
159 parent: String,
160 },
161 DropInheritance {
162 parent: String,
163 },
164 AttachPartition {
165 partition: String,
166 bound: PartitionBound,
167 },
168 DetachPartition {
169 partition: String,
170 concurrently: bool,
171 finalize: bool,
172 },
173 AddColumn {
174 column: ColumnDef,
175 #[serde(default)]
176 checks: Vec<TableCheck>,
177 #[serde(default)]
178 key_constraints: Vec<TableKeyConstraint>,
179 if_not_exists: bool,
180 },
181 AddKeyConstraint {
182 constraint: TableKeyConstraint,
183 },
184 AddCheckConstraint {
185 constraint: TableCheck,
186 },
187 AddForeignKeyConstraint {
188 constraint: ForeignKey,
189 },
190 AddNotNullConstraint {
191 name: Option<String>,
192 column: String,
193 validated: bool,
194 no_inherit: bool,
195 },
196 ValidateConstraint {
197 name: String,
198 },
199 AlterConstraint {
200 name: String,
201 enforceability: Option<bool>,
202 deferrability: Option<(bool, bool)>,
203 no_inherit: Option<bool>,
204 },
205 DropConstraint {
206 name: String,
207 if_exists: bool,
208 cascade: bool,
209 },
210 DropColumn {
211 name: String,
212 if_exists: bool,
213 cascade: bool,
214 },
215 RenameColumn {
216 from: String,
217 to: String,
218 },
219 RenameTable {
220 to: String,
221 },
222 RenameTrigger {
223 from: String,
224 to: String,
225 },
226 RenameConstraint {
227 from: String,
228 to: String,
229 },
230 RenameRule {
231 from: String,
232 to: String,
233 },
234 SetPersistence {
235 persistence: RelationPersistence,
236 },
237 ChangeOwner {
238 owner: RoleSpecification,
239 },
240 SetSchema {
241 schema: String,
242 },
243 SetTriggerEnableMode {
244 name: Option<String>,
245 user_only: bool,
246 mode: EventEnableMode,
247 },
248 SetRuleEnableMode {
249 name: String,
250 mode: EventEnableMode,
251 },
252 SetDefault {
253 name: String,
254 default: Expr,
255 },
256 DropDefault {
257 name: String,
258 },
259 SetExpression {
260 name: String,
261 expression: Expr,
262 },
263 DropExpression {
264 name: String,
265 },
266 SetNotNull {
267 name: String,
268 },
269 DropNotNull {
270 name: String,
271 },
272 AlterColumnType {
273 name: String,
274 ty: ColumnType,
275 #[serde(default, skip_serializing_if = "Option::is_none")]
276 using: Option<Expr>,
277 },
278 AddIdentity {
280 name: String,
281 kind: AutoIncrementKind,
282 #[serde(default, skip_serializing_if = "Option::is_none")]
283 declaration: Option<Box<IdentitySequenceDeclaration>>,
284 },
285 SetIdentity {
287 name: String,
288 kind: Option<AutoIncrementKind>,
290 repeated_kind: bool,
292 #[serde(default)]
294 sequence: SequenceDeclaration,
295 #[serde(default, skip_serializing_if = "Option::is_none")]
297 error: Option<DeferredSQLError>,
298 },
299 DropIdentity {
301 name: String,
302 if_exists: bool,
303 },
304}
305
306#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
307pub struct InsertStmt {
308 pub table: String,
309 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
311 pub target_relation_bound: bool,
312 pub target_qualifier: String,
314 #[serde(default = "default_include_descendants")]
315 pub include_descendants: bool,
316 pub columns: Vec<AssignmentTarget>,
317 #[serde(default, skip_serializing_if = "Option::is_none")]
319 pub overriding: Option<OverridingKind>,
320 pub with: Vec<CTE>,
322 pub rows: Vec<Vec<ValueExpr>>,
324 pub select_source: Option<Box<SelectStmt>>,
328 pub on_conflict: Option<OnConflict>,
331 pub returning: Vec<Projection>,
333 pub returning_aliases: ReturningAliases,
336}
337
338#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
339pub struct ReturningAliases {
340 pub old: String,
341 pub new: String,
342 #[serde(default)]
343 pub old_explicit: bool,
344 #[serde(default)]
345 pub new_explicit: bool,
346}
347
348impl Default for ReturningAliases {
349 fn default() -> Self {
350 Self {
351 old: "old".into(),
352 new: "new".into(),
353 old_explicit: false,
354 new_explicit: false,
355 }
356 }
357}
358
359#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
360pub struct OnConflict {
361 #[serde(default)]
362 pub predicate: Option<Box<Expr>>,
363 #[serde(default)]
364 pub constraint: Option<String>,
365 pub conflict_columns: Vec<String>,
369 #[serde(default)]
370 pub expressions: Vec<Expr>,
371 pub action: OnConflictAction,
372}
373
374#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
375pub enum OnConflictAction {
376 Nothing,
378 Update {
382 assignments: Vec<(AssignmentTarget, Expr)>,
383 r#where: Option<Box<Expr>>,
384 },
385}
386
387#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
388pub struct SelectStmt {
389 pub projections: Vec<Projection>,
390 #[serde(default, skip_serializing_if = "Vec::is_empty")]
394 pub values: Vec<Vec<Expr>>,
395 pub from: Option<FromClause>,
396 pub r#where: Option<Expr>,
397 pub group_by: Vec<Expr>,
398 pub grouping_sets: Vec<Vec<Expr>>,
404 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
406 pub group_distinct: bool,
407 pub having: Option<Expr>,
411 pub order_by: Vec<OrderBy>,
412 pub limit: Option<Expr>,
416 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
418 pub with_ties: bool,
419 pub offset: Option<Expr>,
421 pub with: Vec<CTE>,
423 pub set_op: Option<Box<SetOp>>,
427 pub distinct: bool,
430 pub distinct_on: Vec<Expr>,
433 #[serde(default, skip_serializing_if = "Vec::is_empty")]
435 pub locking: Vec<LockingClause>,
436}
437
438#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
439pub struct SetOp {
440 pub kind: SetOpKind,
441 pub all: bool,
442 #[serde(default, skip_serializing_if = "Option::is_none")]
446 pub left: Option<Box<SelectStmt>>,
447 pub right: SelectStmt,
448 pub combined_order_by: Vec<OrderBy>,
451 pub combined_limit: Option<Expr>,
454 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
456 pub combined_with_ties: bool,
457 pub combined_offset: Option<Expr>,
459}
460
461#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
462pub enum SetOpKind {
463 Union,
464 Intersect,
465 Except,
466}
467
468#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
470pub enum DiscardTarget {
471 All,
472 Plans,
473 Sequences,
474 Temp,
475}
476
477#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
478pub struct UpdateStmt {
479 pub table: String,
480 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
482 pub target_relation_bound: bool,
483 pub target_qualifier: String,
484 #[serde(default = "default_include_descendants")]
485 pub include_descendants: bool,
486 pub assignments: Vec<(AssignmentTarget, Expr)>,
487 pub r#where: Option<Expr>,
488 pub with: Vec<CTE>,
490 pub from: Option<FromClause>,
493 pub returning: Vec<Projection>,
495 pub returning_aliases: ReturningAliases,
496}
497
498#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
499pub struct DeleteStmt {
500 pub table: String,
501 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
503 pub target_relation_bound: bool,
504 pub target_qualifier: String,
505 #[serde(default = "default_include_descendants")]
506 pub include_descendants: bool,
507 pub r#where: Option<Expr>,
508 pub with: Vec<CTE>,
510 pub using: Option<FromClause>,
514 pub returning: Vec<Projection>,
516 pub returning_aliases: ReturningAliases,
517}
518
519#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
520pub struct SetConstraintName {
521 pub catalog: Option<String>,
522 pub schema: Option<String>,
523 pub name: String,
524}
525
526#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
528pub struct VacuumOption {
529 pub name: String,
530 pub value: Option<VacuumOptionValue>,
531}
532
533#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
534pub enum VacuumOptionValue {
535 Boolean(bool),
536 Integer(i32),
537 String(String),
538}
539
540#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
542pub struct VacuumTarget {
543 pub catalog: Option<String>,
544 pub table: String,
545 #[serde(default = "default_include_descendants")]
546 pub include_descendants: bool,
547 #[serde(default, skip_serializing_if = "Vec::is_empty")]
548 pub columns: Vec<String>,
549}
550
551#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
552pub struct VacuumStmt {
553 #[serde(default, skip_serializing_if = "Vec::is_empty")]
554 pub options: Vec<VacuumOption>,
555 #[serde(default, skip_serializing_if = "Vec::is_empty")]
556 pub targets: Vec<VacuumTarget>,
557}
558
559#[derive(Debug, Clone, Serialize, Deserialize)]
560pub enum Statement {
561 CreateDomain(CreateDomain),
562 CreateTable(CreateTable),
563 CreateTableIfNotExists(DeferredCreateTable),
564 CreateIndex(CreateIndex),
565 RenameIndex(RenameIndexStmt),
566 Insert(InsertStmt),
567 Select(Box<SelectStmt>),
571 Update(UpdateStmt),
572 Delete(DeleteStmt),
573 Drop(DropStmt),
574 AlterTable(AlterTableStmt),
575 AlterForeignTable(AlterForeignTableStmt),
576 AlterView(AlterViewStmt),
577 CreateView {
579 name: String,
580 #[serde(default)]
581 column_names: Vec<String>,
582 body: Box<SelectStmt>,
583 or_replace: bool,
584 #[serde(default)]
585 persistence: RelationPersistence,
586 #[serde(default, skip_serializing_if = "Vec::is_empty")]
588 options: Vec<(String, String)>,
589 },
590 CreateMaterializedView {
592 name: String,
593 #[serde(default)]
594 column_names: Vec<String>,
595 #[serde(default)]
596 if_not_exists: bool,
597 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
598 with_no_data: bool,
599 #[serde(default, skip_serializing_if = "Vec::is_empty")]
600 options: Vec<(String, String)>,
601 body: Box<SelectStmt>,
602 },
603 RefreshMaterializedView {
605 name: String,
606 concurrently: bool,
607 with_no_data: bool,
608 },
609 CreateSchema {
611 name: Option<String>,
612 if_not_exists: bool,
613 #[serde(default, skip_serializing_if = "Option::is_none")]
614 authorization: Option<SchemaAuthorization>,
615 },
616 AlterSchemaOwner {
617 name: String,
618 new_owner: RoleSpecification,
619 },
620 Notify {
622 channel: String,
623 payload: String,
624 },
625 Listen {
627 channel: String,
628 },
629 Unlisten {
631 channel: Option<String>,
632 },
633 SetVariable {
637 name: String,
638 value: String,
639 #[serde(default)]
640 local: bool,
641 #[serde(default)]
642 is_default: bool,
643 },
644 ResetVariable {
646 name: String,
647 },
648 ResetAllVariables,
650 SetConstraints {
652 constraints: Vec<SetConstraintName>,
653 deferred: bool,
654 },
655 ShowVariable {
658 name: String,
659 },
660 Discard {
663 target: DiscardTarget,
664 },
665 Load {
670 library: String,
671 },
672 Explain {
675 analyze: bool,
676 verbose: bool,
677 format: Option<String>,
678 body: Box<Statement>,
679 },
680 Analyze {
683 table: Option<String>,
684 },
685 Vacuum(VacuumStmt),
687 LockTable(LockTableStmt),
689 Truncate {
692 tables: Vec<TruncateTarget>,
693 cascade: bool,
694 #[serde(default)]
695 restart_identity: bool,
696 },
697 Transaction(TransactionStmt),
699 DeclareCursor(DeclareCursorStmt),
701 FetchCursor(FetchCursorStmt),
703 CloseCursor {
705 name: Option<String>,
706 },
707 CreateSequence(CreateSequence),
709 AlterSequence(AlterSequence),
712 CreateTableAs {
714 name: String,
715 if_not_exists: bool,
716 #[serde(default, skip_serializing_if = "Vec::is_empty")]
717 column_names: Vec<String>,
718 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
719 with_no_data: bool,
720 #[serde(default)]
721 persistence: RelationPersistence,
722 #[serde(default)]
723 on_commit: OnCommitAction,
724 body: Box<SelectStmt>,
725 },
726 Prepare {
728 name: String,
729 #[serde(default)]
730 parameter_types: Vec<ColumnType>,
731 body: Box<Statement>,
732 },
733 Execute {
735 name: String,
736 params: Vec<Expr>,
737 },
738 Deallocate {
740 name: Option<String>,
741 },
742 Values {
745 rows: Vec<Vec<Expr>>,
746 },
747 CreateForeignServer(CreateForeignServer),
749 CreateForeignTable(CreateForeignTable),
751 CreateForeignTableIfNotExists(DeferredCreateForeignTable),
753 Merge(MergeStmt),
756 CreateFunction(Box<CreateFunction>),
759 DropFunction(DropFunctionStmt),
761 AlterRoutine(AlterRoutineStmt),
763 AlterRoutineOwner(AlterRoutineOwnerStmt),
764 RenameRoutine(RenameRoutineStmt),
765 GrantRoutine(GrantRoutineStmt),
766 GrantTable(GrantTableStmt),
767 GrantSequence(GrantSequenceStmt),
768 GrantDatabase(GrantDatabaseStmt),
769 GrantSchema(GrantSchemaStmt),
770 GrantRole(GrantRoleStmt),
771 CreateRole(CreateRoleStmt),
772 AlterRole(AlterRoleStmt),
773 RenameRole(RenameRoleStmt),
774 DropRole(DropRoleStmt),
775 CreateTrigger(CreateTrigger),
777 DropTrigger(DropTrigger),
779 CreateRule(CreateRule),
781 DropRule(DropRule),
783 DoBlock {
785 language: String,
786 body: String,
787 },
788 Call {
791 name: String,
792 args: Vec<Expr>,
793 },
794}
795
796#[derive(Debug, Clone, Serialize, Deserialize)]
797pub struct TruncateTarget {
798 pub table: String,
799 #[serde(default = "default_include_descendants")]
800 pub include_descendants: bool,
801}
802
803#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
804pub struct MergeTargetColumnBinding {
805 pub object_id: [u8; 16],
806 #[serde(default, skip_serializing_if = "std::collections::BTreeSet::is_empty")]
808 pub domain_dependencies: std::collections::BTreeSet<u32>,
809}
810
811#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
812pub struct MergeStmt {
813 #[serde(default)]
814 pub with: Vec<CTE>,
815 pub target: String,
816 pub target_qualifier: String,
817 pub target_alias: Option<String>,
818 #[serde(default, skip_serializing_if = "std::collections::BTreeMap::is_empty")]
820 pub target_column_bindings: std::collections::BTreeMap<String, MergeTargetColumnBinding>,
821 #[serde(default = "default_include_descendants")]
822 pub include_descendants: bool,
823 pub source: FromClause,
824 pub join_condition: Expr,
825 pub when_clauses: Vec<MergeWhen>,
826 pub returning: Vec<Projection>,
828 pub returning_aliases: ReturningAliases,
829}
830
831#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
832pub enum MergeWhen {
833 UpdateMatched {
835 condition: Option<Expr>,
836 assignments: Vec<(AssignmentTarget, Expr)>,
837 },
838 DeleteMatched { condition: Option<Expr> },
840 UpdateNotMatchedBySource {
842 condition: Option<Expr>,
843 assignments: Vec<(AssignmentTarget, Expr)>,
844 },
845 DeleteNotMatchedBySource { condition: Option<Expr> },
847 InsertNotMatched {
849 condition: Option<Expr>,
850 columns: Vec<AssignmentTarget>,
851 #[serde(default, skip_serializing_if = "Option::is_none")]
852 overriding: Option<OverridingKind>,
853 values: Vec<Expr>,
854 },
855 NothingMatched { condition: Option<Expr> },
857 NothingNotMatched { condition: Option<Expr> },
859 NothingNotMatchedBySource { condition: Option<Expr> },
861}
862
863#[derive(Debug, Clone, Serialize, Deserialize)]
864pub struct CreateForeignServer {
865 pub name: String,
866 pub fdw_type: String,
867 pub options: Vec<(String, String)>,
868 pub if_not_exists: bool,
869}
870
871#[derive(Debug, Clone, Serialize, Deserialize)]
872pub struct CreateForeignTable {
873 pub name: String,
874 pub server_name: String,
875 pub columns: Vec<ColumnDef>,
876 #[serde(default)]
877 pub checks: Vec<TableCheck>,
878 pub options: Vec<(String, String)>,
879 pub if_not_exists: bool,
880}
881
882#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
884pub struct DeferredCreateForeignTable {
885 pub name: String,
886 pub server_name: String,
887 pub definition_sql: String,
888}
889
890#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
891pub enum TransactionIsolationLevel {
892 ReadUncommitted,
893 ReadCommitted,
894 RepeatableRead,
895 Serializable,
896}
897
898impl TransactionIsolationLevel {
899 #[must_use]
900 pub const fn as_str(self) -> &'static str {
901 match self {
902 Self::ReadUncommitted => "read uncommitted",
903 Self::ReadCommitted => "read committed",
904 Self::RepeatableRead => "repeatable read",
905 Self::Serializable => "serializable",
906 }
907 }
908}
909
910#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
911pub struct TransactionCharacteristics {
912 pub isolation: Option<TransactionIsolationLevel>,
913 pub read_only: Option<bool>,
914 pub deferrable: Option<bool>,
915}
916
917#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
918pub enum TransactionStmt {
919 Begin,
920 BeginWithCharacteristics(TransactionCharacteristics),
921 Commit,
922 CommitAndChain,
923 Rollback,
924 RollbackAndChain,
925 SetCharacteristics(TransactionCharacteristics),
926 SetSessionCharacteristics(TransactionCharacteristics),
927 SetSnapshot(String),
928 Savepoint(String),
929 ReleaseSavepoint(String),
930 RollbackToSavepoint(String),
931}
932
933#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
934pub enum CursorDirection {
935 Forward,
936 Backward,
937 Absolute,
938 Relative,
939}
940
941#[derive(Debug, Clone, Serialize, Deserialize)]
942pub struct DeclareCursorStmt {
943 pub name: String,
944 pub binary: bool,
945 pub scroll: Option<bool>,
947 pub hold: bool,
948 pub query: Box<SelectStmt>,
949}
950
951#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
952pub struct FetchCursorStmt {
953 pub name: String,
954 pub direction: CursorDirection,
955 pub count: i64,
957 pub move_only: bool,
958}
959
960#[cfg(test)]
961mod tests;