| 1 | |
|
| 2 | |
|
| 3 | | use super::{now_ms, Pool}; |
| 4 | | use sqlx::FromRow; |
| 5 | |
|
| 6 | | #[derive(Clone, Debug, FromRow)] |
| 7 | | pub struct TfState { |
| 8 | | pub repo_id: i64, |
| 9 | | pub name: String, |
| 10 | | |
| 11 | | pub body: Vec<u8>, |
| 12 | | pub serial: i64, |
| 13 | | pub lock_id: String, |
| 14 | | pub lock_info: String, |
| 15 | | pub locked_by: String, |
| 16 | | pub locked_ms: Option<i64>, |
| 17 | | pub updated_by: String, |
| 18 | | pub updated_ms: i64, |
| 19 | | } |
| 20 | |
|
| 21 | 19× | pub async fn get(pool: &Pool, repo_id: i64, name: &str) -> sqlx::Result<Option<TfState>> { |
| 22 | 19× | sqlx::query_as("SELECT * FROM terraform_states WHERE repo_id = $1 AND name = $2").bind(repo_id).bind(name).fetch_optional(pool).await |
| 23 | 19× | } |
| 24 | |
|
| 25 | 3× | pub async fn of_repo(pool: &Pool, repo_id: i64) -> sqlx::Result<Vec<TfState>> { |
| 26 | 3× | sqlx::query_as("SELECT * FROM terraform_states WHERE repo_id = $1 ORDER BY name").bind(repo_id).fetch_all(pool).await |
| 27 | 3× | } |
| 28 | |
|
| 29 | |
|
| 30 | 1× | pub async fn versions(pool: &Pool, repo_id: i64, name: &str) -> sqlx::Result<i64> { |
| 31 | 1× | sqlx::query_scalar("SELECT COUNT(*) FROM terraform_state_versions WHERE repo_id = $1 AND name = $2") |
| 32 | 1× | .bind(repo_id) |
| 33 | 1× | .bind(name) |
| 34 | 1× | .fetch_one(pool) |
| 35 | 1× | .await |
| 36 | 1× | } |
| 37 | |
|
| 38 | |
|
| 39 | | #[derive(Clone, Debug, FromRow)] |
| 40 | | pub struct TfVersion { |
| 41 | | pub id: i64, |
| 42 | | pub serial: i64, |
| 43 | | pub created_by: String, |
| 44 | | pub created_ms: i64, |
| 45 | | } |
| 46 | |
|
| 47 | |
|
| 48 | 5× | pub async fn version_list(pool: &Pool, repo_id: i64, name: &str) -> sqlx::Result<Vec<TfVersion>> { |
| 49 | 5× | sqlx::query_as( |
| 50 | 5× | "SELECT id, serial, created_by, created_ms FROM terraform_state_versions WHERE repo_id = $1 AND name = $2 ORDER BY id DESC", |
| 51 | 5× | ) |
| 52 | 5× | .bind(repo_id) |
| 53 | 5× | .bind(name) |
| 54 | 5× | .fetch_all(pool) |
| 55 | 5× | .await |
| 56 | 5× | } |
| 57 | |
|
| 58 | |
|
| 59 | 6× | pub async fn version_body(pool: &Pool, repo_id: i64, name: &str, id: i64) -> sqlx::Result<Option<(Vec<u8>, i64)>> { |
| 60 | 6× | sqlx::query_as("SELECT body, serial FROM terraform_state_versions WHERE repo_id = $1 AND name = $2 AND id = $3") |
| 61 | 6× | .bind(repo_id) |
| 62 | 6× | .bind(name) |
| 63 | 6× | .bind(id) |
| 64 | 6× | .fetch_optional(pool) |
| 65 | 6× | .await |
| 66 | 6× | } |
| 67 | |
|
| 68 | |
|
| 69 | |
|
| 70 | 5× | pub async fn put(pool: &Pool, repo_id: i64, name: &str, body: &[u8], serial: i64, by: &str, keep: i64) -> sqlx::Result<()> { |
| 71 | 5× | let now = now_ms(); |
| 72 | 5× | let mut tx = pool.begin().await?; |
| 73 | 5× | sqlx::query( |
| 74 | 5× | "INSERT INTO terraform_state_versions (repo_id, name, body, serial, created_by, created_ms) \ |
| 75 | 5× | SELECT repo_id, name, body, serial, updated_by, updated_ms FROM terraform_states \ |
| 76 | 5× | WHERE repo_id = $1 AND name = $2 AND length(body) > 0", |
| 77 | 5× | ) |
| 78 | 5× | .bind(repo_id) |
| 79 | 5× | .bind(name) |
| 80 | 5× | .execute(&mut *tx) |
| 81 | 5× | .await?; |
| 82 | 5× | sqlx::query( |
| 83 | 5× | "INSERT INTO terraform_states (repo_id, name, body, serial, updated_by, updated_ms) VALUES ($1, $2, $3, $4, $5, $6) \ |
| 84 | 5× | ON CONFLICT (repo_id, name) DO UPDATE SET body = $3, serial = $4, updated_by = $5, updated_ms = $6", |
| 85 | 5× | ) |
| 86 | 5× | .bind(repo_id) |
| 87 | 5× | .bind(name) |
| 88 | 5× | .bind(body) |
| 89 | 5× | .bind(serial) |
| 90 | 5× | .bind(by) |
| 91 | 5× | .bind(now) |
| 92 | 5× | .execute(&mut *tx) |
| 93 | 5× | .await?; |
| 94 | 5× | sqlx::query( |
| 95 | 5× | "DELETE FROM terraform_state_versions WHERE repo_id = $1 AND name = $2 AND id NOT IN \ |
| 96 | 5× | (SELECT id FROM terraform_state_versions WHERE repo_id = $1 AND name = $2 ORDER BY id DESC LIMIT $3)", |
| 97 | 5× | ) |
| 98 | 5× | .bind(repo_id) |
| 99 | 5× | .bind(name) |
| 100 | 5× | .bind(keep) |
| 101 | 5× | .execute(&mut *tx) |
| 102 | 5× | .await?; |
| 103 | 5× | tx.commit().await |
| 104 | 5× | } |
| 105 | |
|
| 106 | |
|
| 107 | 0× | pub async fn delete(pool: &Pool, repo_id: i64, name: &str) -> sqlx::Result<()> { |
| 108 | 0× | sqlx::query("DELETE FROM terraform_states WHERE repo_id = $1 AND name = $2").bind(repo_id).bind(name).execute(pool).await?; |
| 109 | 0× | Ok(()) |
| 110 | 0× | } |
| 111 | |
|
| 112 | |
|
| 113 | 2× | pub async fn lock(pool: &Pool, repo_id: i64, name: &str, id: &str, info: &str, by: &str) -> sqlx::Result<bool> { |
| 114 | 2× | let now = now_ms(); |
| 115 | 2× | let r = sqlx::query( |
| 116 | 2× | "INSERT INTO terraform_states (repo_id, name, body, lock_id, lock_info, locked_by, locked_ms, updated_ms) \ |
| 117 | 2× | VALUES ($1, $2, $3, $4, $5, $6, $7, $7) \ |
| 118 | 2× | ON CONFLICT (repo_id, name) DO UPDATE SET lock_id = $4, lock_info = $5, locked_by = $6, locked_ms = $7 \ |
| 119 | 2× | WHERE terraform_states.lock_id = ''", |
| 120 | 2× | ) |
| 121 | 2× | .bind(repo_id) |
| 122 | 2× | .bind(name) |
| 123 | 2× | .bind(Vec::<u8>::new()) |
| 124 | 2× | .bind(id) |
| 125 | 2× | .bind(info) |
| 126 | 2× | .bind(by) |
| 127 | 2× | .bind(now) |
| 128 | 2× | .execute(pool) |
| 129 | 2× | .await?; |
| 130 | 2× | Ok(r.rows_affected() == 1) |
| 131 | 2× | } |
| 132 | |
|
| 133 | 2× | pub async fn unlock(pool: &Pool, repo_id: i64, name: &str) -> sqlx::Result<()> { |
| 134 | 2× | sqlx::query( |
| 135 | 2× | "UPDATE terraform_states SET lock_id = '', lock_info = '', locked_by = '', locked_ms = NULL WHERE repo_id = $1 AND name = $2", |
| 136 | 2× | ) |
| 137 | 2× | .bind(repo_id) |
| 138 | 2× | .bind(name) |
| 139 | 2× | .execute(pool) |
| 140 | 2× | .await?; |
| 141 | 2× | Ok(()) |
| 142 | 2× | } |