1use rusqlite::named_params;
2use strum_macros::FromRepr;
3
4use super::{db::SqliteStorage, error::PersistResult};
5
6#[derive(FromRepr)]
7#[repr(i32)]
8pub(crate) enum SendPayStatus {
9 Pending = 0,
10 Failed = 1,
11 Complete = 2,
12}
13
14pub(crate) struct SendPay {
15 pub created_index: u64,
16 pub updated_index: Option<u64>,
17
18 pub groupid: String,
23
24 pub partid: Option<u64>,
25 pub payment_hash: Vec<u8>,
26 pub status: SendPayStatus,
27 pub amount_msat: Option<u64>,
28 pub destination: Option<Vec<u8>>,
29 pub created_at: u64,
30 pub amount_sent_msat: Option<u64>,
31 pub label: Option<String>,
32 pub bolt11: Option<String>,
33 pub description: Option<String>,
34 pub bolt12: Option<String>,
35 pub payment_preimage: Option<Vec<u8>>,
36 pub erroronion: Option<Vec<u8>>,
37}
38
39impl SqliteStorage {
40 pub(crate) fn insert_send_pays(&self, send_pays: &[SendPay]) -> PersistResult<()> {
41 let conn = self.get_connection()?;
42 let mut stmt = conn.prepare(
43 r#"INSERT OR REPLACE INTO send_pays (created_index, updated_index,
44 groupid, partid, payment_hash, status, amount_msat,
45 destination, created_at, amount_sent_msat, label, bolt11,
46 description, bolt12, payment_preimage, erroronion)
47 VALUES (:created_index, :updated_index,
48 :groupid, :partid, :payment_hash, :status, :amount_msat,
49 :destination, :created_at, :amount_sent_msat, :label, :bolt11,
50 :description, :bolt12, :payment_preimage, :erroronion)"#,
51 )?;
52 for send_pay in send_pays {
53 let status: i32 = match send_pay.status {
54 SendPayStatus::Pending => 0,
55 SendPayStatus::Failed => 1,
56 SendPayStatus::Complete => 2,
57 };
58 stmt.execute(named_params! {
59 ":created_index": send_pay.created_index,
60 ":updated_index": send_pay.updated_index,
61 ":groupid": send_pay.groupid,
62 ":partid": send_pay.partid,
63 ":payment_hash": send_pay.payment_hash,
64 ":status": status,
65 ":amount_msat": send_pay.amount_msat,
66 ":destination": send_pay.destination,
67 ":created_at": send_pay.created_at,
68 ":amount_sent_msat": send_pay.amount_sent_msat,
69 ":label": send_pay.label,
70 ":bolt11": send_pay.bolt11,
71 ":description": send_pay.description,
72 ":bolt12": send_pay.bolt12,
73 ":payment_preimage": send_pay.payment_preimage,
74 ":erroronion": send_pay.erroronion,
75 })?;
76 }
77
78 Ok(())
79 }
80
81 pub(crate) fn list_send_pays(
82 &self,
83 hash_groups: &[(Vec<u8>, String)],
84 ) -> PersistResult<Vec<SendPay>> {
85 let conn = self.get_connection()?;
86 let mut stmt = conn.prepare(
87 r#"SELECT created_index, updated_index, groupid, partid,
88 payment_hash, status, amount_msat, destination, created_at,
89 amount_sent_msat, label, bolt11, description, bolt12,
90 payment_preimage, erroronion
91 FROM send_pays
92 WHERE payment_hash = :payment_hash AND groupid = :groupid
93 ORDER BY created_index"#,
94 )?;
95 let mut send_pays = Vec::new();
96 for hash_group in hash_groups {
97 let rows: Vec<_> = stmt
98 .query_map(
99 named_params! {
100 ":payment_hash": hash_group.0,
101 ":groupid": hash_group.1,
102 },
103 |row| {
104 let status: i32 = row.get("status")?;
105 Ok(SendPay {
106 amount_msat: row.get("amount_msat")?,
107 amount_sent_msat: row.get("amount_sent_msat")?,
108 created_index: row.get("created_index")?,
109 updated_index: row.get("updated_index")?,
110 groupid: row.get("groupid")?,
111 partid: row.get("partid")?,
112 payment_hash: row.get("payment_hash")?,
113 status: SendPayStatus::from_repr(status)
114 .ok_or(rusqlite::Error::IntegralValueOutOfRange(5, 2))?,
115 destination: row.get("destination")?,
116 created_at: row.get("created_at")?,
117 label: row.get("label")?,
118 bolt11: row.get("bolt11")?,
119 description: row.get("description")?,
120 bolt12: row.get("bolt12")?,
121 payment_preimage: row.get("payment_preimage")?,
122 erroronion: row.get("erroronion")?,
123 })
124 },
125 )?
126 .collect::<Result<Vec<SendPay>, _>>()?;
127 for row in rows {
128 send_pays.push(row);
129 }
130 }
131 Ok(send_pays)
132 }
133}