|
@@ -62,14 +62,15 @@ impl SQLite {
|
|
|
);
|
|
|
CREATE INDEX IF NOT EXISTS "spent_by" ON "payments" ("to", "spent_by");
|
|
|
CREATE TABLE IF NOT EXISTS "transaction_accounts" (
|
|
|
+ "id" INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
|
"account_id" VARCHAR(64) NOT NULL,
|
|
|
"transaction_id" VARCHAR(66) NOT NULL,
|
|
|
- "type" INTEGE
|
|
|
- R NOT NULL,
|
|
|
+ "type" INTEGER NOT NULL,
|
|
|
"created_at" DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
|
- "updated_at" DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
|
- PRIMARY KEY("account_id", "transaction_id")
|
|
|
+ "updated_at" DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
|
);
|
|
|
+ CREATE UNIQUE INDEX IF NOT EXISTS "unique_account_transaction" ON "transaction_accounts" ("account_id", "transaction_id");
|
|
|
+ CREATE INDEX IF NOT EXISTS "sorted_account_transaction" ON "transaction_accounts" ("account_id", "id" desc);
|
|
|
"#,
|
|
|
)
|
|
|
.await
|
|
@@ -277,52 +278,64 @@ impl Storage for SQLite {
|
|
|
.map_err(|e| Error::Storage(e.to_string()))?;
|
|
|
|
|
|
let sql = if types.is_empty() {
|
|
|
- r#"SELECT "transaction_id" FROM "transaction_accounts" WHERE "account_id" = ? ORDER BY "created_at" DESC"#.to_owned()
|
|
|
+ r#"SELECT
|
|
|
+ "b"."id",
|
|
|
+ "b"."blob"
|
|
|
+ FROM
|
|
|
+ "transaction_accounts" as "ta",
|
|
|
+ "transactions" as "t",
|
|
|
+ "blobs" as "b"
|
|
|
+ WHERE
|
|
|
+ "ta"."account_id" = ?
|
|
|
+ AND "t"."transaction_id" = "ta"."transaction_id"
|
|
|
+ AND "t"."blob_id" = "b"."id"
|
|
|
+ ORDER BY "ta"."id" DESC"#
|
|
|
+ .to_owned()
|
|
|
} else {
|
|
|
- let params = format!(
|
|
|
- "?{}",
|
|
|
- ", ?".repeat(types.len().checked_add(1).ok_or(Error::Underflow)?)
|
|
|
- );
|
|
|
+ let types = types
|
|
|
+ .into_iter()
|
|
|
+ .map(|t| u32::from(t).to_string())
|
|
|
+ .collect::<Vec<_>>()
|
|
|
+ .join(",");
|
|
|
format!(
|
|
|
- r#"SELECT "transaction_id" FROM "transaction_accounts" WHERE "account_id" = ? AND "type" IN ({}) ORDER BY "created_at" DESC"#,
|
|
|
- params
|
|
|
+ r#"SELECT
|
|
|
+ "b"."id",
|
|
|
+ "b"."blob"
|
|
|
+ FROM
|
|
|
+ "transaction_accounts" as "ta",
|
|
|
+ "transactions" as "t",
|
|
|
+ "blobs" as "b"
|
|
|
+ WHERE
|
|
|
+ "account_id" = ?
|
|
|
+ AND "t"."transaction_id" = "ta"."transaction_id"
|
|
|
+ AND "t"."blob_id" = "b"."id"
|
|
|
+ AND "type" IN ({types})
|
|
|
+ ORDER BY "ta"."id" DESC"#,
|
|
|
)
|
|
|
};
|
|
|
|
|
|
- let sql = sqlx::query(&sql).bind(account.to_string());
|
|
|
-
|
|
|
- let ids = if !types.is_empty() {
|
|
|
- let mut sql = sql;
|
|
|
- for typ in types.iter() {
|
|
|
- sql = sql.bind::<u32>(typ.into());
|
|
|
- }
|
|
|
- sql
|
|
|
- } else {
|
|
|
- sql
|
|
|
- }
|
|
|
- .fetch_all(&mut *conn)
|
|
|
- .await
|
|
|
- .map_err(|e| Error::Storage(e.to_string()))?
|
|
|
- .into_iter()
|
|
|
- .map(|row| {
|
|
|
- let id: Result<RevisionId, _> = row
|
|
|
- .try_get::<String, usize>(0)
|
|
|
- .map_err(|_| Error::Storage("Invalid transaction_id".to_string()))?
|
|
|
- .as_str()
|
|
|
- .try_into();
|
|
|
-
|
|
|
- id.map_err(|_| Error::Storage("Invalid transaction_id length".to_string()))
|
|
|
- })
|
|
|
- .collect::<Result<Vec<_>, Error>>()?;
|
|
|
-
|
|
|
- drop(conn);
|
|
|
-
|
|
|
- let mut transactions = vec![];
|
|
|
- for id in ids.into_iter() {
|
|
|
- transactions.push(self.get_transaction(&id).await?);
|
|
|
- }
|
|
|
-
|
|
|
- Ok(transactions)
|
|
|
+ sqlx::query(&sql)
|
|
|
+ .bind(account.to_string())
|
|
|
+ .fetch_all(&mut *conn)
|
|
|
+ .await
|
|
|
+ .map_err(|e| Error::Storage(e.to_string()))?
|
|
|
+ .into_iter()
|
|
|
+ .map(|row| {
|
|
|
+ let id = row
|
|
|
+ .try_get::<String, usize>(0)
|
|
|
+ .map_err(|e| Error::Storage(e.to_string()))?;
|
|
|
+ let encoded = row
|
|
|
+ .try_get::<Vec<u8>, usize>(1)
|
|
|
+ .map_err(|e| Error::Storage(e.to_string()))?;
|
|
|
+
|
|
|
+ bincode::deserialize::<Revision>(&encoded)
|
|
|
+ .map_err(|e| Error::Storage(format!("Error parsing {id}: {}", e.to_string())))?
|
|
|
+ .try_into()
|
|
|
+ .map_err(|e| {
|
|
|
+ Error::Storage(format!("Error converting {id} to Transaction: {}", e))
|
|
|
+ })
|
|
|
+ })
|
|
|
+ .collect::<Result<Vec<Transaction>, Error>>()
|
|
|
}
|
|
|
}
|
|
|
|