1use anyhow::Context;
5use diesel::{
6 FromSqlRow, backend::Backend, deserialize, expression::AsExpression, prelude::*, serialize,
7 sql_types::SmallInt,
8};
9
10use sui_field_count::FieldCount;
11use sui_types::object::{Object, Owner};
12
13use crate::schema::{
14 coin_balance_buckets, coin_balance_buckets_deletion_reference, kv_objects, obj_info,
15 obj_info_deletion_reference, obj_versions,
16};
17
18#[derive(Insertable, Debug, Clone, FieldCount, Queryable)]
19#[diesel(table_name = kv_objects, primary_key(object_id, object_version))]
20#[diesel(treat_none_as_default_value = false)]
21pub struct StoredObject {
22 pub object_id: Vec<u8>,
23 pub object_version: i64,
24 pub serialized_object: Option<Vec<u8>>,
25}
26
27#[derive(
28 Insertable, Selectable, Debug, Clone, PartialEq, Eq, FieldCount, Queryable, QueryableByName,
29)]
30#[diesel(table_name = obj_versions, primary_key(object_id, object_version))]
31pub struct StoredObjVersion {
32 pub object_id: Vec<u8>,
33 pub object_version: i64,
34 pub object_digest: Option<Vec<u8>>,
35 pub cp_sequence_number: i64,
36}
37
38#[derive(AsExpression, FromSqlRow, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
39#[diesel(sql_type = SmallInt)]
40#[repr(i16)]
41pub enum StoredOwnerKind {
42 Immutable = 0,
43 Address = 1,
44 Object = 2,
45 Shared = 3,
46}
47
48#[derive(AsExpression, FromSqlRow, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
49#[diesel(sql_type = SmallInt)]
50#[repr(i16)]
51pub enum StoredCoinOwnerKind {
52 Fastpath = 0,
53 Consensus = 1,
54}
55
56#[derive(Insertable, Debug, Clone, FieldCount, Queryable)]
57#[diesel(table_name = obj_info, primary_key(object_id, cp_sequence_number))]
58#[diesel(treat_none_as_default_value = false)]
59pub struct StoredObjInfo {
60 pub object_id: Vec<u8>,
61 pub cp_sequence_number: i64,
62 pub owner_kind: Option<StoredOwnerKind>,
63 pub owner_id: Option<Vec<u8>>,
64 pub package: Option<Vec<u8>>,
65 pub module: Option<String>,
66 pub name: Option<String>,
67 pub instantiation: Option<Vec<u8>>,
68}
69
70#[derive(Insertable, Debug, Clone, FieldCount, Queryable)]
71#[diesel(table_name = obj_info_deletion_reference, primary_key(cp_sequence_number, object_id))]
72pub struct StoredObjInfoDeletionReference {
73 pub object_id: Vec<u8>,
74 pub cp_sequence_number: i64,
75}
76
77#[derive(Insertable, Queryable, Debug, Clone, FieldCount, Eq, PartialEq)]
78#[diesel(table_name = coin_balance_buckets, primary_key(object_id, cp_sequence_number))]
79#[diesel(treat_none_as_default_value = false)]
80pub struct StoredCoinBalanceBucket {
81 pub object_id: Vec<u8>,
82 pub cp_sequence_number: i64,
83 pub owner_kind: Option<StoredCoinOwnerKind>,
84 pub owner_id: Option<Vec<u8>>,
85 pub coin_type: Option<Vec<u8>>,
86 pub coin_balance_bucket: Option<i16>,
87}
88
89#[derive(Insertable, Queryable, Debug, Clone, FieldCount, Eq, PartialEq)]
90#[diesel(table_name = coin_balance_buckets_deletion_reference, primary_key(cp_sequence_number, object_id))]
91pub struct StoredCoinBalanceBucketDeletionReference {
92 pub object_id: Vec<u8>,
93 pub cp_sequence_number: i64,
94}
95
96impl StoredObjInfo {
97 pub fn from_object(object: &Object, cp_sequence_number: i64) -> anyhow::Result<Self> {
98 let type_ = object.type_();
99 Ok(Self {
100 object_id: object.id().to_vec(),
101 cp_sequence_number,
102 owner_kind: Some(match object.owner() {
103 Owner::AddressOwner(_) => StoredOwnerKind::Address,
104 Owner::ObjectOwner(_) => StoredOwnerKind::Object,
105 Owner::Shared { .. } => StoredOwnerKind::Shared,
106 Owner::Immutable => StoredOwnerKind::Immutable,
107 Owner::ConsensusAddressOwner { .. } => StoredOwnerKind::Address,
110 }),
111
112 owner_id: match object.owner() {
113 Owner::AddressOwner(a) => Some(a.to_vec()),
114 Owner::ObjectOwner(o) => Some(o.to_vec()),
115 Owner::Shared { .. } | Owner::Immutable => None,
116 Owner::ConsensusAddressOwner { owner, .. } => Some(owner.to_vec()),
117 },
118
119 package: type_.map(|t| t.address().to_vec()),
120 module: type_.map(|t| t.module().to_string()),
121 name: type_.map(|t| t.name().to_string()),
122 instantiation: type_
123 .map(|t| bcs::to_bytes(&t.type_params()))
124 .transpose()
125 .with_context(|| {
126 format!(
127 "Failed to serialize type parameters for {}",
128 object.id().to_canonical_display(true),
129 )
130 })?,
131 })
132 }
133}
134
135impl<DB: Backend> serialize::ToSql<SmallInt, DB> for StoredOwnerKind
136where
137 i16: serialize::ToSql<SmallInt, DB>,
138{
139 fn to_sql<'b>(&'b self, out: &mut serialize::Output<'b, '_, DB>) -> serialize::Result {
140 match self {
141 StoredOwnerKind::Immutable => 0.to_sql(out),
142 StoredOwnerKind::Address => 1.to_sql(out),
143 StoredOwnerKind::Object => 2.to_sql(out),
144 StoredOwnerKind::Shared => 3.to_sql(out),
145 }
146 }
147}
148
149impl<DB: Backend> deserialize::FromSql<SmallInt, DB> for StoredOwnerKind
150where
151 i16: deserialize::FromSql<SmallInt, DB>,
152{
153 fn from_sql(raw: DB::RawValue<'_>) -> deserialize::Result<Self> {
154 Ok(match i16::from_sql(raw)? {
155 0 => StoredOwnerKind::Immutable,
156 1 => StoredOwnerKind::Address,
157 2 => StoredOwnerKind::Object,
158 3 => StoredOwnerKind::Shared,
159 o => return Err(format!("Unexpected StoredOwnerKind: {o}").into()),
160 })
161 }
162}
163
164impl<DB: Backend> serialize::ToSql<SmallInt, DB> for StoredCoinOwnerKind
165where
166 i16: serialize::ToSql<SmallInt, DB>,
167{
168 fn to_sql<'b>(&'b self, out: &mut serialize::Output<'b, '_, DB>) -> serialize::Result {
169 match self {
170 StoredCoinOwnerKind::Fastpath => 0.to_sql(out),
171 StoredCoinOwnerKind::Consensus => 1.to_sql(out),
172 }
173 }
174}
175
176impl<DB: Backend> deserialize::FromSql<SmallInt, DB> for StoredCoinOwnerKind
177where
178 i16: deserialize::FromSql<SmallInt, DB>,
179{
180 fn from_sql(raw: DB::RawValue<'_>) -> deserialize::Result<Self> {
181 Ok(match i16::from_sql(raw)? {
182 0 => StoredCoinOwnerKind::Fastpath,
183 1 => StoredCoinOwnerKind::Consensus,
184 o => return Err(format!("Unexpected StoredCoinOwnerKind: {o}").into()),
185 })
186 }
187}