tx_indexer/database/
plutus.rs

1#[cfg(feature = "diesel")]
2use diesel::sql_types::{Array, Bytea, Nullable};
3use num_bigint::BigInt;
4use pla::csl::pla_to_csl::TryToCSL;
5use plutus_ledger_api as pla;
6use thiserror::Error;
7use plutus_ledger_api::csl::{
8    lib as csl,
9    csl_to_pla::{TryFromCSLError, TryToPLA},
10    pla_to_csl::TryFromPLAError,
11};
12
13#[derive(Error, Debug)]
14pub enum DBTypeConversionError {
15    #[error("Couldn't parse DB type, because some invariants weren't valid: {0}")]
16    InvariantBroken(String),
17
18    #[error("Cannot represent BigInt as PostgreSQL BIGINT type: {0}")]
19    BigIntConversion(num_bigint::TryFromBigIntError<BigInt>),
20
21    #[error(transparent)]
22    PlutusDataEncodingError(#[from] PlutusDataEncodingError),
23}
24
25#[cfg(feature = "diesel")]
26pub mod sql_types {
27
28    #[derive(diesel::QueryId, diesel::SqlType)]
29    #[diesel(postgres_type(name = "address", schema = "plutus"))]
30    pub struct Address;
31
32    #[derive(diesel::QueryId, diesel::SqlType)]
33    #[diesel(postgres_type(name = "asset_quantity", schema = "plutus"))]
34    pub struct AssetQuantity;
35
36    #[derive(diesel::QueryId, diesel::SqlType)]
37    #[diesel(postgres_type(name = "chain_pointer", schema = "plutus"))]
38    pub struct ChainPointer;
39
40    #[derive(diesel::QueryId, diesel::SqlType)]
41    #[diesel(postgres_type(name = "credential", schema = "plutus"))]
42    pub struct Credential;
43
44    #[derive(diesel::QueryId, diesel::SqlType)]
45    #[diesel(postgres_type(name = "currency_symbol", schema = "plutus"))]
46    pub struct CurrencySymbol;
47
48    #[derive(diesel::QueryId, diesel::SqlType)]
49    #[diesel(postgres_type(name = "datum_hash", schema = "plutus"))]
50    pub struct DatumHash;
51
52    #[derive(diesel::QueryId, diesel::SqlType)]
53    #[diesel(postgres_type(name = "ed25519_pub_key_hash", schema = "plutus"))]
54    pub struct Ed25519PubKeyHash;
55
56    #[derive(diesel::QueryId, diesel::SqlType)]
57    #[diesel(postgres_type(name = "hash28", schema = "plutus"))]
58    pub struct Hash28;
59
60    #[derive(diesel::QueryId, diesel::SqlType)]
61    #[diesel(postgres_type(name = "hash32", schema = "plutus"))]
62    pub struct Hash32;
63
64    #[derive(diesel::QueryId, diesel::SqlType)]
65    #[diesel(postgres_type(name = "output_datum", schema = "plutus"))]
66    pub struct OutputDatum;
67
68    #[derive(diesel::QueryId, diesel::SqlType)]
69    #[diesel(postgres_type(name = "plutus_data", schema = "plutus"))]
70    pub struct PlutusData;
71
72    #[derive(diesel::QueryId, diesel::SqlType)]
73    #[diesel(postgres_type(name = "script_hash", schema = "plutus"))]
74    pub struct ScriptHash;
75
76    #[derive(diesel::QueryId, diesel::SqlType)]
77    #[diesel(postgres_type(name = "slot", schema = "plutus"))]
78    pub struct Slot;
79
80    #[derive(diesel::QueryId, diesel::SqlType)]
81    #[diesel(postgres_type(name = "staking_credential", schema = "plutus"))]
82    pub struct StakingCredential;
83
84    #[derive(diesel::QueryId, diesel::SqlType)]
85    #[diesel(postgres_type(name = "token_name", schema = "plutus"))]
86    pub struct TokenName;
87
88    #[derive(diesel::QueryId, diesel::SqlType)]
89    #[diesel(postgres_type(name = "transaction_hash", schema = "plutus"))]
90    pub struct TransactionHash;
91
92    #[derive(diesel::QueryId, diesel::SqlType)]
93    #[diesel(postgres_type(name = "transaction_input", schema = "plutus"))]
94    pub struct TransactionInput;
95
96    #[derive(diesel::QueryId, diesel::SqlType)]
97    #[diesel(postgres_type(name = "transaction_output", schema = "plutus"))]
98    pub struct TransactionOutput;
99
100    #[derive(diesel::QueryId, diesel::SqlType)]
101    #[diesel(postgres_type(name = "tx_in_info", schema = "plutus"))]
102    pub struct TxInInfo;
103
104    #[derive(diesel::QueryId, diesel::SqlType)]
105    #[diesel(postgres_type(name = "value", schema = "plutus"))]
106    pub struct Value;
107}
108
109//////////////////////
110/// Hash28
111//////////////////////
112
113#[derive(Clone, Debug, PartialEq, Eq)]
114#[cfg_attr(feature = "sqlx", derive(sqlx::Encode, sqlx::Decode))]
115#[cfg_attr(
116    feature = "diesel",
117    derive(diesel::AsExpression, diesel::FromSqlRow, diesel_derive_pg::PgCustomType),
118    diesel(sql_type = sql_types::Hash28), 
119    diesel_derive_pg(sql_type = sql_types::Hash28)
120)]
121pub struct Hash28(#[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = Bytea))] pub Vec<u8>);
122
123impl From<pla::v3::crypto::LedgerBytes> for Hash28 {
124    fn from(item: pla::v3::crypto::LedgerBytes) -> Self {
125        Hash28(item.0)
126    }
127}
128
129impl From<Hash28> for pla::v3::crypto::LedgerBytes {
130    fn from(item: Hash28) -> Self {
131        pla::v3::crypto::LedgerBytes(item.0)
132    }
133}
134
135#[cfg(feature = "sqlx")]
136impl ::sqlx::Type<::sqlx::postgres::Postgres> for Hash28 {
137    fn type_info() -> ::sqlx::postgres::PgTypeInfo {
138        ::sqlx::postgres::PgTypeInfo::with_name("plutus.hash28")
139    }
140    fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> ::std::primitive::bool {
141        Self::type_info() == *ty || <Vec<u8> as ::sqlx::Type<::sqlx::Postgres>>::compatible(ty)
142    }
143}
144
145//////////////////////
146/// Hash32
147//////////////////////
148
149#[derive(Clone, Debug, PartialEq, Eq)]
150#[cfg_attr(feature = "sqlx", derive(sqlx::Encode, sqlx::Decode))]
151#[cfg_attr(
152    feature = "diesel",
153    derive(diesel::AsExpression, diesel::FromSqlRow, diesel_derive_pg::PgCustomType),
154    diesel(sql_type = sql_types::Hash32),
155    diesel_derive_pg(sql_type = sql_types::Hash32)
156)]
157pub struct Hash32(#[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = Bytea))] pub Vec<u8>);
158
159impl From<pla::v3::crypto::LedgerBytes> for Hash32 {
160    fn from(item: pla::v3::crypto::LedgerBytes) -> Self {
161        Hash32(item.0)
162    }
163}
164
165impl From<Hash32> for pla::v3::crypto::LedgerBytes {
166    fn from(item: Hash32) -> Self {
167        pla::v3::crypto::LedgerBytes(item.0)
168    }
169}
170
171#[cfg(feature = "sqlx")]
172impl ::sqlx::Type<::sqlx::postgres::Postgres> for Hash32 {
173    fn type_info() -> ::sqlx::postgres::PgTypeInfo {
174        ::sqlx::postgres::PgTypeInfo::with_name("plutus.hash32")
175    }
176    fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> ::std::primitive::bool {
177        Self::type_info() == *ty || <Vec<u8> as ::sqlx::Type<::sqlx::Postgres>>::compatible(ty)
178    }
179}
180
181//////////////////////
182/// CurrencySymbol
183//////////////////////
184
185#[derive(Clone, Debug, PartialEq, Eq)]
186#[cfg_attr(feature = "sqlx", derive(sqlx::Encode, sqlx::Decode))]
187#[cfg_attr(
188    feature = "diesel",
189    derive(diesel::AsExpression, diesel::FromSqlRow, diesel_derive_pg::PgCustomType),
190    diesel(sql_type = sql_types::CurrencySymbol),
191    diesel_derive_pg(sql_type = sql_types::CurrencySymbol)
192)]
193pub struct CurrencySymbol(#[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = Bytea))] pub Vec<u8>);
194
195impl From<pla::v3::value::CurrencySymbol> for CurrencySymbol {
196    fn from(item: pla::v3::value::CurrencySymbol) -> Self {
197        match item {
198            pla::v3::value::CurrencySymbol::Ada => CurrencySymbol(Vec::with_capacity(0)),
199            pla::v3::value::CurrencySymbol::NativeToken(pla::v3::script::MintingPolicyHash(
200                pla::v3::script::ScriptHash(pla::v3::crypto::LedgerBytes(bytes)),
201            )) => CurrencySymbol(bytes),
202        }
203    }
204}
205
206impl From<CurrencySymbol> for pla::v3::value::CurrencySymbol {
207    fn from(item: CurrencySymbol) -> Self {
208        let CurrencySymbol(bytes) = item;
209        if bytes.is_empty() {
210            pla::v3::value::CurrencySymbol::Ada
211        } else {
212            pla::v3::value::CurrencySymbol::NativeToken(pla::v3::script::MintingPolicyHash(
213                pla::v3::script::ScriptHash(pla::v3::crypto::LedgerBytes(bytes)),
214            ))
215        }
216    }
217}
218
219#[cfg(feature = "sqlx")]
220impl ::sqlx::Type<::sqlx::postgres::Postgres> for CurrencySymbol {
221    fn type_info() -> ::sqlx::postgres::PgTypeInfo {
222        ::sqlx::postgres::PgTypeInfo::with_name("plutus.currency_symbol")
223    }
224    fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> ::std::primitive::bool {
225        Self::type_info() == *ty || <Vec<u8> as ::sqlx::Type<::sqlx::Postgres>>::compatible(ty)
226    }
227}
228
229//////////////////////
230/// TokenName
231//////////////////////
232
233#[derive(Clone, Debug, PartialEq, Eq)]
234#[cfg_attr(feature = "sqlx", derive(sqlx::Encode, sqlx::Decode))]
235#[cfg_attr(
236    feature = "diesel",
237    derive(diesel::AsExpression, diesel::FromSqlRow, diesel_derive_pg::PgCustomType),
238    diesel(sql_type = sql_types::TokenName),
239    diesel_derive_pg(sql_type = sql_types::TokenName)
240)]
241pub struct TokenName(#[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = Bytea))] pub Vec<u8>);
242
243impl From<pla::v3::value::TokenName> for TokenName {
244    fn from(item: pla::v3::value::TokenName) -> Self {
245        TokenName(item.0 .0)
246    }
247}
248
249impl From<TokenName> for pla::v3::value::TokenName {
250    fn from(item: TokenName) -> Self {
251        pla::v3::value::TokenName(pla::v3::crypto::LedgerBytes(item.0))
252    }
253}
254
255#[cfg(feature = "sqlx")]
256impl ::sqlx::Type<::sqlx::postgres::Postgres> for TokenName {
257    fn type_info() -> ::sqlx::postgres::PgTypeInfo {
258        ::sqlx::postgres::PgTypeInfo::with_name("plutus.token_name")
259    }
260    fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> ::std::primitive::bool {
261        Self::type_info() == *ty || <Vec<u8> as ::sqlx::Type<::sqlx::Postgres>>::compatible(ty)
262    }
263}
264
265//////////////////////
266/// TransactionHash
267//////////////////////
268
269#[derive(Clone, Debug, PartialEq, Eq)]
270#[cfg_attr(feature = "sqlx", derive(sqlx::Encode, sqlx::Decode))]
271#[cfg_attr(
272    feature = "diesel",
273    derive(diesel::AsExpression, diesel::FromSqlRow, diesel_derive_pg::PgCustomType),
274    diesel(sql_type = sql_types::TransactionHash),
275    diesel_derive_pg(sql_type = sql_types::TransactionHash)
276)]
277pub struct TransactionHash(#[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = sql_types::Hash32))] pub Hash32);
278
279impl From<pla::v3::transaction::TransactionHash> for TransactionHash {
280    fn from(item: pla::v3::transaction::TransactionHash) -> Self {
281        TransactionHash(item.0.into())
282    }
283}
284
285impl From<TransactionHash> for pla::v3::transaction::TransactionHash {
286    fn from(item: TransactionHash) -> Self {
287        pla::v3::transaction::TransactionHash(item.0.into())
288    }
289}
290
291#[cfg(feature = "sqlx")]
292impl ::sqlx::Type<::sqlx::postgres::Postgres> for TransactionHash {
293    fn type_info() -> ::sqlx::postgres::PgTypeInfo {
294        ::sqlx::postgres::PgTypeInfo::with_name("plutus.transaction_hash")
295    }
296    fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> ::std::primitive::bool {
297        Self::type_info() == *ty || <Hash32 as ::sqlx::Type<::sqlx::Postgres>>::compatible(ty)
298    }
299}
300
301//////////////////////
302/// Ed25519PubKeyHash
303//////////////////////
304
305#[derive(Clone, Debug, PartialEq, Eq)]
306#[cfg_attr(feature = "sqlx", derive(sqlx::Encode, sqlx::Decode))]
307#[cfg_attr(
308    feature = "diesel",
309    derive(diesel::AsExpression, diesel::FromSqlRow, diesel_derive_pg::PgCustomType),
310    diesel(sql_type = sql_types::Ed25519PubKeyHash),
311    diesel_derive_pg(sql_type = sql_types::Ed25519PubKeyHash)
312)]
313pub struct Ed25519PubKeyHash(#[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = sql_types::Hash28))] pub Hash28);
314
315impl From<pla::v3::crypto::Ed25519PubKeyHash> for Ed25519PubKeyHash {
316    fn from(item: pla::v3::crypto::Ed25519PubKeyHash) -> Self {
317        Ed25519PubKeyHash(item.0.into())
318    }
319}
320
321impl From<Ed25519PubKeyHash> for pla::v3::crypto::Ed25519PubKeyHash {
322    fn from(item: Ed25519PubKeyHash) -> Self {
323        pla::v3::crypto::Ed25519PubKeyHash(item.0.into())
324    }
325}
326
327#[cfg(feature = "sqlx")]
328impl ::sqlx::Type<::sqlx::postgres::Postgres> for Ed25519PubKeyHash {
329    fn type_info() -> ::sqlx::postgres::PgTypeInfo {
330        ::sqlx::postgres::PgTypeInfo::with_name("plutus.ed25519_pub_key_hash")
331    }
332    fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> ::std::primitive::bool {
333        Self::type_info() == *ty || <Hash28 as ::sqlx::Type<::sqlx::Postgres>>::compatible(ty)
334    }
335}
336
337//////////////////////
338/// ScriptHash
339//////////////////////
340
341#[derive(Clone, Debug, PartialEq, Eq)]
342#[cfg_attr(feature = "sqlx", derive(sqlx::Encode, sqlx::Decode))]
343#[cfg_attr(
344    feature = "diesel",
345    derive(diesel::AsExpression, diesel::FromSqlRow, diesel_derive_pg::PgCustomType),
346    diesel(sql_type = sql_types::ScriptHash),
347    diesel_derive_pg(sql_type = sql_types::ScriptHash)
348)]
349pub struct ScriptHash(#[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = sql_types::Hash28))] pub Hash28);
350
351impl From<pla::v3::script::ScriptHash> for ScriptHash {
352    fn from(item: pla::v3::script::ScriptHash) -> Self {
353        ScriptHash(item.0.into())
354    }
355}
356
357impl From<ScriptHash> for pla::v3::script::ScriptHash {
358    fn from(item: ScriptHash) -> Self {
359        pla::v3::script::ScriptHash(item.0.into())
360    }
361}
362
363#[cfg(feature = "sqlx")]
364impl ::sqlx::Type<::sqlx::postgres::Postgres> for ScriptHash {
365    fn type_info() -> ::sqlx::postgres::PgTypeInfo {
366        ::sqlx::postgres::PgTypeInfo::with_name("plutus.script_hash")
367    }
368    fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> ::std::primitive::bool {
369        Self::type_info() == *ty || <Hash28 as ::sqlx::Type<::sqlx::Postgres>>::compatible(ty)
370    }
371}
372
373//////////////////////
374/// DatumHash
375//////////////////////
376
377#[derive(Clone, Debug, PartialEq, Eq)]
378#[cfg_attr(feature = "sqlx", derive(sqlx::Encode, sqlx::Decode))]
379#[cfg_attr(
380    feature = "diesel",
381    derive(diesel::AsExpression, diesel::FromSqlRow, diesel_derive_pg::PgCustomType),
382    diesel(sql_type = sql_types::DatumHash),
383    diesel_derive_pg(sql_type = sql_types::DatumHash)
384    )]
385pub struct DatumHash(#[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = sql_types::Hash32))] pub Hash32);
386
387impl From<pla::v3::datum::DatumHash> for DatumHash {
388    fn from(item: pla::v3::datum::DatumHash) -> Self {
389        DatumHash(item.0.into())
390    }
391}
392
393impl From<DatumHash> for pla::v3::datum::DatumHash {
394    fn from(item: DatumHash) -> Self {
395        pla::v3::datum::DatumHash(item.0.into())
396    }
397}
398
399#[cfg(feature = "sqlx")]
400impl ::sqlx::Type<::sqlx::postgres::Postgres> for DatumHash {
401    fn type_info() -> ::sqlx::postgres::PgTypeInfo {
402        ::sqlx::postgres::PgTypeInfo::with_name("plutus.datum_hash")
403    }
404    fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> ::std::primitive::bool {
405        Self::type_info() == *ty || <Hash32 as ::sqlx::Type<::sqlx::Postgres>>::compatible(ty)
406    }
407}
408
409//////////////////////
410/// Slot
411//////////////////////
412
413#[derive(Clone, Debug, PartialEq, Eq)]
414#[cfg_attr(feature = "sqlx", derive(sqlx::Encode, sqlx::Decode))]
415#[cfg_attr(
416    feature = "diesel",
417    derive(diesel::AsExpression, diesel::FromSqlRow, diesel_derive_pg::PgCustomType),
418    diesel(sql_type = sql_types::Slot),
419    diesel_derive_pg(sql_type = sql_types::Slot)
420)]
421pub struct Slot(#[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = diesel::sql_types::BigInt))] pub i64);
422
423impl From<u64> for Slot {
424    fn from(item: u64) -> Self {
425        Slot(item as i64)
426    }
427}
428
429impl From<&Slot> for u64 {
430    fn from(item: &Slot) -> Self {
431        item.0 as u64
432    }
433}
434
435#[cfg(feature = "sqlx")]
436impl ::sqlx::Type<::sqlx::postgres::Postgres> for Slot {
437    fn type_info() -> ::sqlx::postgres::PgTypeInfo {
438        ::sqlx::postgres::PgTypeInfo::with_name("plutus.slot")
439    }
440    fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> ::std::primitive::bool {
441        Self::type_info() == *ty || <i64 as ::sqlx::Type<::sqlx::Postgres>>::compatible(ty)
442    }
443}
444
445
446//////////////////////
447/// PlutusData
448//////////////////////
449
450#[derive(Error, Debug)]
451pub enum PlutusDataEncodingError {
452    #[error(transparent)]
453    CSLConversionError(#[from] csl::JsError),
454
455    #[error(transparent)]
456    TryFromPLAError(#[from] TryFromPLAError),
457
458    #[error(transparent)]
459    TryFromCSLError(#[from] TryFromCSLError),
460}
461
462#[derive(Clone, Debug, PartialEq, Eq)]
463#[cfg_attr(feature = "sqlx", derive(sqlx::Encode, sqlx::Decode))]
464#[cfg_attr(
465    feature = "diesel",
466    derive(diesel::AsExpression, diesel::FromSqlRow, diesel_derive_pg::PgCustomType),
467    diesel(sql_type = sql_types::PlutusData),
468    diesel_derive_pg(sql_type = sql_types::PlutusData)
469)]
470pub struct PlutusData(#[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = diesel::sql_types::Jsonb))] pub serde_json::Value);
471
472impl TryFrom<pla::plutus_data::PlutusData> for PlutusData {
473    type Error = DBTypeConversionError;
474
475    fn try_from(item: pla::plutus_data::PlutusData) -> Result<Self, Self::Error> {
476        Ok(PlutusData(
477            csl::decode_plutus_datum_to_json_value(
478                &item
479                    .try_to_csl()
480                    .map_err(PlutusDataEncodingError::TryFromPLAError)?,
481                csl::PlutusDatumSchema::DetailedSchema,
482            )
483            .map_err(PlutusDataEncodingError::CSLConversionError)?,
484        ))
485    }
486}
487
488impl TryFrom<PlutusData> for pla::plutus_data::PlutusData {
489    type Error = DBTypeConversionError;
490
491    fn try_from(item: PlutusData) -> Result<Self, Self::Error> {
492        Ok(
493            csl::encode_json_value_to_plutus_datum(item.0, csl::PlutusDatumSchema::DetailedSchema)
494                .map_err(PlutusDataEncodingError::CSLConversionError)?
495                .try_to_pla()
496                .map_err(PlutusDataEncodingError::TryFromCSLError)?,
497        )
498    }
499}
500
501#[cfg(feature = "sqlx")]
502impl ::sqlx::Type<::sqlx::postgres::Postgres> for PlutusData {
503    fn type_info() -> ::sqlx::postgres::PgTypeInfo {
504        ::sqlx::postgres::PgTypeInfo::with_name("plutus.plutus_data")
505    }
506    fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> ::std::primitive::bool {
507        Self::type_info() == *ty
508            || <serde_json::Value as ::sqlx::Type<::sqlx::Postgres>>::compatible(ty)
509    }
510}
511
512//////////////////////
513/// Credential
514//////////////////////
515
516#[derive(Clone, Debug, PartialEq, Eq)]
517#[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
518#[cfg_attr(feature = "sqlx", sqlx(type_name = "plutus.credential"))]
519#[cfg_attr(
520    feature = "diesel",
521    derive(diesel::AsExpression, diesel::FromSqlRow, diesel_derive_pg::PgCustomType),
522    diesel(sql_type = sql_types::Credential),
523    diesel_derive_pg(sql_type = sql_types::Credential)
524)]
525pub struct Credential {
526    #[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = Nullable<sql_types::Ed25519PubKeyHash>))]
527    pub_key_hash: Option<Ed25519PubKeyHash>,
528
529    #[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = Nullable<sql_types::ScriptHash>))]
530    script_hash: Option<ScriptHash>,
531}
532
533impl From<pla::v3::address::Credential> for Credential {
534    fn from(item: pla::v3::address::Credential) -> Self {
535        match item {
536            pla::v3::address::Credential::PubKey(pkh) => Credential {
537                pub_key_hash: Some(pkh.into()),
538                script_hash: None,
539            },
540            pla::v3::address::Credential::Script(pla::v3::script::ValidatorHash(sh)) => {
541                Credential {
542                    pub_key_hash: None,
543                    script_hash: Some(sh.into()),
544                }
545            }
546        }
547    }
548}
549
550impl TryFrom<Credential> for pla::v3::address::Credential {
551    type Error = DBTypeConversionError;
552
553    fn try_from(item: Credential) -> Result<Self, Self::Error> {
554        Ok(match item {
555            Credential {
556                pub_key_hash: Some(pkh_db),
557                script_hash: None,
558            } => pla::v3::address::Credential::PubKey(pkh_db.into()),
559            Credential {
560                pub_key_hash: None,
561                script_hash: Some(sh_db),
562            } => pla::v3::address::Credential::Script(pla::v3::script::ValidatorHash(sh_db.into())),
563            _ => Err(DBTypeConversionError::InvariantBroken(
564                "DB Credential must have either 'pub_key_hash' or 'script_hash'".to_string(),
565            ))?,
566        })
567    }
568}
569
570//////////////////////
571/// ChainPointer
572//////////////////////
573
574#[derive(Clone, Debug, PartialEq, Eq)]
575#[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
576#[cfg_attr(feature = "sqlx", sqlx(type_name = "plutus.chain_pointer"))]
577#[cfg_attr(
578    feature = "diesel",
579    derive(diesel::AsExpression, diesel::FromSqlRow, diesel_derive_pg::PgCustomType),
580    diesel(sql_type = sql_types::ChainPointer),
581    diesel_derive_pg(sql_type = sql_types::ChainPointer)
582)]
583pub struct ChainPointer {
584    #[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = diesel::sql_types::BigInt))]
585    slot_num: i64,
586
587    #[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = diesel::sql_types::BigInt))]
588    tx_idx: i64,
589
590    #[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = diesel::sql_types::BigInt))]
591    cert_idx: i64,
592}
593
594impl TryFrom<pla::v3::address::ChainPointer> for ChainPointer {
595    type Error = DBTypeConversionError;
596
597    fn try_from(item: pla::v3::address::ChainPointer) -> Result<Self, Self::Error> {
598        Ok(ChainPointer {
599            slot_num: item
600                .slot_number
601                .0
602                .try_into()
603                .map_err(DBTypeConversionError::BigIntConversion)?,
604            tx_idx: item
605                .transaction_index
606                .0
607                .try_into()
608                .map_err(DBTypeConversionError::BigIntConversion)?,
609            cert_idx: item
610                .certificate_index
611                .0
612                .try_into()
613                .map_err(DBTypeConversionError::BigIntConversion)?,
614        })
615    }
616}
617
618impl From<ChainPointer> for pla::v3::address::ChainPointer {
619    fn from(item: ChainPointer) -> Self {
620        pla::v3::address::ChainPointer {
621            slot_number: pla::v3::address::Slot(BigInt::from(item.slot_num)),
622            transaction_index: pla::v3::address::TransactionIndex(BigInt::from(item.tx_idx)),
623            certificate_index: pla::v3::address::CertificateIndex(BigInt::from(item.cert_idx)),
624        }
625    }
626}
627
628//////////////////////
629/// StakingCredential
630//////////////////////
631
632#[derive(Clone, Debug, PartialEq, Eq)]
633#[cfg_attr(feature = "sqlx", derive(sqlx::Type), sqlx(type_name = "plutus.staking_credential"))]
634#[cfg_attr(
635    feature = "diesel",
636    derive(diesel::AsExpression, diesel::FromSqlRow, diesel_derive_pg::PgCustomType),
637    diesel(sql_type = sql_types::StakingCredential),
638    diesel_derive_pg(sql_type = sql_types::StakingCredential)
639)]
640pub struct StakingCredential {
641    #[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = Nullable<sql_types::Credential>))]
642    staking_hash: Option<Credential>,
643
644    #[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = Nullable<sql_types::ChainPointer>))]
645    staking_ptr: Option<ChainPointer>,
646}
647
648impl TryFrom<pla::v3::address::StakingCredential> for StakingCredential {
649    type Error = DBTypeConversionError;
650
651    fn try_from(item: pla::v3::address::StakingCredential) -> Result<Self, Self::Error> {
652        Ok(match item {
653            pla::v3::address::StakingCredential::Hash(cred) => StakingCredential {
654                staking_hash: Some(cred.into()),
655                staking_ptr: None,
656            },
657            pla::v3::address::StakingCredential::Pointer(ptr) => StakingCredential {
658                staking_hash: None,
659                staking_ptr: Some(ptr.try_into()?),
660            },
661        })
662    }
663}
664
665impl TryFrom<StakingCredential> for pla::v3::address::StakingCredential {
666    type Error = DBTypeConversionError;
667
668    fn try_from(item: StakingCredential) -> Result<Self, Self::Error> {
669        Ok(match item {
670            StakingCredential {
671                staking_hash: Some(cred),
672                staking_ptr: None,
673            } => pla::v3::address::StakingCredential::Hash(cred.try_into()?),
674            StakingCredential {
675                staking_hash: None,
676                staking_ptr: Some(ptr),
677            } => pla::v3::address::StakingCredential::Pointer(ptr.into()),
678
679            _ => Err(DBTypeConversionError::InvariantBroken(
680                "DB StakingCredential must have either 'staking_hash' or 'staking_ptr'".to_string(),
681            ))?,
682        })
683    }
684}
685
686//////////////////////
687/// Address
688//////////////////////
689
690#[derive(Clone, Debug, PartialEq, Eq)]
691#[cfg_attr(
692    feature = "sqlx", 
693    derive(sqlx::Type),
694    sqlx(type_name = "plutus.address")
695)]
696#[cfg_attr(
697    feature = "diesel",
698    derive(diesel::AsExpression, diesel::FromSqlRow, diesel_derive_pg::PgCustomType),
699    diesel(sql_type = sql_types::Address),
700    diesel_derive_pg(sql_type = sql_types::Address)
701)]
702pub struct Address {
703    #[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = sql_types::Credential))]
704    credential: Credential,
705
706    #[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = Nullable<sql_types::StakingCredential>))]
707    staking_credential: Option<StakingCredential>,
708}
709
710impl TryFrom<pla::v3::address::Address> for Address {
711    type Error = DBTypeConversionError;
712
713    fn try_from(item: pla::v3::address::Address) -> Result<Self, Self::Error> {
714        Ok(Address {
715            credential: item.credential.into(),
716            staking_credential: item
717                .staking_credential
718                .map(StakingCredential::try_from)
719                .transpose()?,
720        })
721    }
722}
723
724impl TryFrom<Address> for pla::v3::address::Address {
725    type Error = DBTypeConversionError;
726
727    fn try_from(item: Address) -> Result<Self, Self::Error> {
728        Ok(pla::v3::address::Address {
729            credential: item.credential.try_into()?,
730            staking_credential: item
731                .staking_credential
732                .map(pla::v3::address::StakingCredential::try_from)
733                .transpose()?,
734        })
735    }
736}
737
738//////////////////////
739/// AssetQuantity
740//////////////////////
741
742#[derive(Clone, Debug, PartialEq, Eq)]
743#[cfg_attr(
744    feature = "sqlx", derive(sqlx::Type),
745    sqlx(type_name = "plutus.asset_quantity")
746)]
747#[cfg_attr(
748    feature = "diesel",
749    derive(diesel::AsExpression, diesel::FromSqlRow, diesel_derive_pg::PgCustomType),
750    diesel(sql_type = sql_types::AssetQuantity),
751    diesel_derive_pg(sql_type = sql_types::AssetQuantity)
752)]
753pub struct AssetQuantity {
754    #[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = sql_types::CurrencySymbol))]
755    currency_symbol: CurrencySymbol,
756
757    #[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = sql_types::TokenName))]
758    token_name: TokenName,
759
760    #[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = diesel::sql_types::BigInt))]
761    amount: i64,
762}
763
764impl
765    TryFrom<(
766        pla::v3::value::CurrencySymbol,
767        pla::v3::value::TokenName,
768        BigInt,
769    )> for AssetQuantity
770{
771    type Error = DBTypeConversionError;
772
773    fn try_from(
774        item: (
775            pla::v3::value::CurrencySymbol,
776            pla::v3::value::TokenName,
777            BigInt,
778        ),
779    ) -> Result<Self, Self::Error> {
780        Ok(AssetQuantity {
781            currency_symbol: item.0.into(),
782            token_name: item.1.into(),
783            amount: item
784                .2
785                .try_into()
786                .map_err(DBTypeConversionError::BigIntConversion)?,
787        })
788    }
789}
790
791impl From<AssetQuantity>
792    for (
793        pla::v3::value::CurrencySymbol,
794        pla::v3::value::TokenName,
795        BigInt,
796    )
797{
798    fn from(item: AssetQuantity) -> Self {
799        (
800            item.currency_symbol.into(),
801            item.token_name.into(),
802            item.amount.into(),
803        )
804    }
805}
806
807//////////////////////
808/// Value
809//////////////////////
810
811#[derive(Clone, Debug, PartialEq, Eq)]
812#[cfg_attr(
813    feature = "sqlx",
814    derive(sqlx::Type),
815    sqlx(type_name = "plutus.asset_quantity[]")
816)]
817#[cfg_attr(
818    feature = "diesel",
819    derive(diesel::AsExpression, diesel::FromSqlRow, diesel_derive_pg::PgCustomType),
820    diesel(sql_type = sql_types::Value),
821    diesel_derive_pg(sql_type = sql_types::Value)
822)]
823pub struct Value(#[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = Array<sql_types::AssetQuantity>))] pub Vec<AssetQuantity>);
824
825impl TryFrom<pla::v3::value::Value> for Value {
826    type Error = DBTypeConversionError;
827
828    fn try_from(item: pla::v3::value::Value) -> Result<Self, Self::Error> {
829        let assets = item
830            .0
831            .iter()
832            .flat_map(|(cs, assets)| {
833                assets
834                    .iter()
835                    .map(|(tn, amount)| {
836                        AssetQuantity::try_from((cs.to_owned(), tn.to_owned(), amount.to_owned()))
837                    })
838                    .collect::<Vec<_>>()
839            })
840            .collect::<Result<Vec<AssetQuantity>, DBTypeConversionError>>()?;
841
842        Ok(Value(assets))
843    }
844}
845
846impl From<Value> for pla::v3::value::Value {
847    fn from(item: Value) -> Self {
848        item.0.into_iter().fold(
849            pla::v3::value::Value::new(),
850            |value,
851             AssetQuantity {
852                 currency_symbol,
853                 token_name,
854                 amount,
855             }| {
856                value.insert_token(&currency_symbol.into(), &token_name.into(), &amount.into())
857            },
858        )
859    }
860}
861
862//////////////////////
863/// TransactionInput
864//////////////////////
865
866#[derive(Clone, Debug, PartialEq, Eq)]
867#[cfg_attr(
868    feature = "sqlx",
869    derive(sqlx::Type),
870    sqlx(type_name = "plutus.transaction_input")
871)]
872#[cfg_attr(
873    feature = "diesel",
874    derive(diesel::AsExpression, diesel::FromSqlRow, diesel_derive_pg::PgCustomType),
875    diesel(sql_type = sql_types::TransactionInput),
876    diesel_derive_pg(sql_type = sql_types::TransactionInput)
877)]
878pub struct TransactionInput {
879    #[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = sql_types::TransactionHash))]
880    tx_id: TransactionHash,
881
882    #[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = diesel::sql_types::BigInt))]
883    tx_idx: i64,
884}
885
886impl TryFrom<pla::v3::transaction::TransactionInput> for TransactionInput {
887    type Error = DBTypeConversionError;
888
889    fn try_from(item: pla::v3::transaction::TransactionInput) -> Result<Self, Self::Error> {
890        Ok(TransactionInput {
891            tx_id: item.transaction_id.into(),
892            tx_idx: item
893                .index
894                .try_into()
895                .map_err(DBTypeConversionError::BigIntConversion)?,
896        })
897    }
898}
899
900impl From<TransactionInput> for pla::v3::transaction::TransactionInput {
901    fn from(item: TransactionInput) -> Self {
902        pla::v3::transaction::TransactionInput {
903            transaction_id: item.tx_id.into(),
904            index: item.tx_idx.into(),
905        }
906    }
907}
908
909//////////////////////
910/// OutputDatum
911//////////////////////
912
913#[derive(Clone, Debug, PartialEq, Eq)]
914#[cfg_attr(
915    feature = "sqlx",
916    derive(sqlx::Type),
917    sqlx(type_name = "plutus.output_datum")
918)]
919#[cfg_attr(
920    feature = "diesel",
921    derive(diesel::AsExpression, diesel::FromSqlRow, diesel_derive_pg::PgCustomType),
922    diesel(sql_type = sql_types::OutputDatum),
923    diesel_derive_pg(sql_type = sql_types::OutputDatum)
924)]
925pub struct OutputDatum {
926    #[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = Nullable<sql_types::DatumHash>))]
927    datum_hash: Option<DatumHash>,
928
929    #[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = Nullable<sql_types::PlutusData>))]
930    inline_datum: Option<PlutusData>,
931}
932
933impl TryFrom<pla::v3::datum::OutputDatum> for OutputDatum {
934    type Error = DBTypeConversionError;
935
936    fn try_from(item: pla::v3::datum::OutputDatum) -> Result<Self, Self::Error> {
937        Ok(match item {
938            pla::v3::datum::OutputDatum::DatumHash(dh) => OutputDatum {
939                datum_hash: Some(dh.into()),
940                inline_datum: None,
941            },
942            pla::v3::datum::OutputDatum::InlineDatum(pla::v3::datum::Datum(datum)) => OutputDatum {
943                datum_hash: None,
944                inline_datum: Some(datum.try_into()?),
945            },
946            pla::v3::datum::OutputDatum::None => OutputDatum {
947                datum_hash: None,
948                inline_datum: None,
949            },
950        })
951    }
952}
953
954impl TryFrom<OutputDatum> for pla::v3::datum::OutputDatum {
955    type Error = DBTypeConversionError;
956
957    fn try_from(item: OutputDatum) -> Result<Self, Self::Error> {
958        Ok(match item {
959            OutputDatum {
960                datum_hash: Some(dh_db),
961                ..
962            } => pla::v3::datum::OutputDatum::DatumHash(dh_db.into()),
963            OutputDatum {
964                inline_datum: Some(datum_db),
965                ..
966            } => pla::v3::datum::OutputDatum::InlineDatum(pla::v3::datum::Datum(
967                datum_db.try_into()?,
968            )),
969            _ => pla::v3::datum::OutputDatum::None,
970        })
971    }
972}
973
974//////////////////////
975/// TransactionOutput
976//////////////////////
977
978#[derive(Clone, Debug, PartialEq, Eq)]
979#[cfg_attr(
980    feature = "sqlx",
981    derive(sqlx::Type),
982    sqlx(type_name = "plutus.transaction_output")
983)]
984#[cfg_attr(
985    feature = "diesel",
986    derive(diesel::AsExpression, diesel::FromSqlRow, diesel_derive_pg::PgCustomType),
987    diesel(sql_type = sql_types::TransactionOutput),
988    diesel_derive_pg(sql_type = sql_types::TransactionOutput)
989)]
990pub struct TransactionOutput {
991    #[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = sql_types::Address))]
992    address: Address,
993
994    #[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = sql_types::Value))]
995    assets: Value,
996
997    #[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = sql_types::OutputDatum))]
998    datum: OutputDatum,
999
1000    #[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = Nullable<sql_types::ScriptHash>))]
1001    reference_script: Option<ScriptHash>,
1002}
1003
1004impl TryFrom<pla::v3::transaction::TransactionOutput> for TransactionOutput {
1005    type Error = DBTypeConversionError;
1006
1007    fn try_from(item: pla::v3::transaction::TransactionOutput) -> Result<Self, Self::Error> {
1008        Ok(TransactionOutput {
1009            address: item.address.try_into()?,
1010            assets: item.value.try_into()?,
1011            datum: item.datum.try_into()?,
1012            reference_script: item.reference_script.map(ScriptHash::from),
1013        })
1014    }
1015}
1016
1017impl TryFrom<TransactionOutput> for pla::v3::transaction::TransactionOutput {
1018    type Error = DBTypeConversionError;
1019
1020    fn try_from(item: TransactionOutput) -> Result<Self, Self::Error> {
1021        Ok(pla::v3::transaction::TransactionOutput {
1022            address: item.address.try_into()?,
1023            value: item.assets.into(),
1024            datum: item.datum.try_into()?,
1025            reference_script: item.reference_script.map(pla::v3::script::ScriptHash::from),
1026        })
1027    }
1028}
1029
1030//////////////////////
1031/// TxInInfo
1032//////////////////////
1033
1034#[derive(Clone, Debug, PartialEq, Eq)]
1035#[cfg_attr(
1036    feature = "sqlx",
1037    derive(sqlx::Type),
1038    sqlx(type_name = "plutus.tx_in_info")
1039)]
1040#[cfg_attr(
1041    feature = "diesel",
1042    derive(diesel::AsExpression, diesel::FromSqlRow, diesel_derive_pg::PgCustomType),
1043    diesel(sql_type = sql_types::TxInInfo),
1044    diesel_derive_pg(sql_type = sql_types::TxInInfo)
1045)]
1046pub struct TxInInfo {
1047    #[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = sql_types::TransactionInput))]
1048    reference: TransactionInput,
1049
1050    #[cfg_attr(feature = "diesel", diesel_derive_pg(sql_type = sql_types::TransactionOutput))]
1051    output: TransactionOutput,
1052}
1053
1054impl TryFrom<pla::v3::transaction::TxInInfo> for TxInInfo {
1055    type Error = DBTypeConversionError;
1056
1057    fn try_from(item: pla::v3::transaction::TxInInfo) -> Result<Self, Self::Error> {
1058        Ok(TxInInfo {
1059            reference: item.reference.try_into()?,
1060            output: item.output.try_into()?,
1061        })
1062    }
1063}
1064
1065impl TryFrom<TxInInfo> for pla::v3::transaction::TxInInfo {
1066    type Error = DBTypeConversionError;
1067
1068    fn try_from(item: TxInInfo) -> Result<Self, Self::Error> {
1069        Ok(pla::v3::transaction::TxInInfo {
1070            reference: item.reference.into(),
1071            output: item.output.try_into()?,
1072        })
1073    }
1074}
1075