feat(db): add proposal and proposal_vote tables
This commit is contained in:
@@ -216,3 +216,24 @@ create table if not exists integrity_envelope (
|
|||||||
) STRICT;
|
) STRICT;
|
||||||
|
|
||||||
create unique index if not exists uniq_integrity_envelope_entity on integrity_envelope (entity_kind, entity_id);
|
create unique index if not exists uniq_integrity_envelope_entity on integrity_envelope (entity_kind, entity_id);
|
||||||
|
|
||||||
|
create table if not exists proposal (
|
||||||
|
id integer not null primary key,
|
||||||
|
kind text not null,
|
||||||
|
payload blob not null,
|
||||||
|
initiator_id integer not null references operator_identity(id) on delete restrict,
|
||||||
|
created_at integer not null default(unixepoch('now')),
|
||||||
|
expires_at integer not null,
|
||||||
|
status text not null default 'pending'
|
||||||
|
check (status in ('pending', 'approved', 'rejected', 'expired'))
|
||||||
|
) STRICT;
|
||||||
|
|
||||||
|
create table if not exists proposal_vote (
|
||||||
|
id integer not null primary key,
|
||||||
|
proposal_id integer not null references proposal(id) on delete cascade,
|
||||||
|
operator_id integer not null references operator_identity(id) on delete restrict,
|
||||||
|
approve integer not null check (approve in (0, 1)),
|
||||||
|
signature blob not null,
|
||||||
|
voted_at integer not null default(unixepoch('now')),
|
||||||
|
unique (proposal_id, operator_id)
|
||||||
|
) STRICT;
|
||||||
|
|||||||
@@ -15,10 +15,11 @@ use restructed::Models;
|
|||||||
pub mod types {
|
pub mod types {
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use diesel::{
|
use diesel::{
|
||||||
|
backend::Backend,
|
||||||
deserialize::{FromSql, FromSqlRow},
|
deserialize::{FromSql, FromSqlRow},
|
||||||
expression::AsExpression,
|
expression::AsExpression,
|
||||||
serialize::{IsNull, ToSql},
|
serialize::{IsNull, ToSql},
|
||||||
sql_types::Integer,
|
sql_types::{Integer, Text},
|
||||||
sqlite::{Sqlite, SqliteType},
|
sqlite::{Sqlite, SqliteType},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -61,7 +62,7 @@ pub mod types {
|
|||||||
|
|
||||||
impl FromSql<Integer, Sqlite> for SqliteTimestamp {
|
impl FromSql<Integer, Sqlite> for SqliteTimestamp {
|
||||||
fn from_sql(
|
fn from_sql(
|
||||||
mut bytes: <Sqlite as diesel::backend::Backend>::RawValue<'_>,
|
mut bytes: <Sqlite as Backend>::RawValue<'_>,
|
||||||
) -> diesel::deserialize::Result<Self> {
|
) -> diesel::deserialize::Result<Self> {
|
||||||
let Some(SqliteType::Long) = bytes.value_type() else {
|
let Some(SqliteType::Long) = bytes.value_type() else {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
@@ -141,6 +142,45 @@ pub mod types {
|
|||||||
declare_id!(TlsHistoryId);
|
declare_id!(TlsHistoryId);
|
||||||
declare_id!(EvmWalletId);
|
declare_id!(EvmWalletId);
|
||||||
declare_id!(ClientId);
|
declare_id!(ClientId);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, AsExpression, FromSqlRow)]
|
||||||
|
#[diesel(sql_type = Text)]
|
||||||
|
pub enum ProposalStatus {
|
||||||
|
Pending,
|
||||||
|
Approved,
|
||||||
|
Rejected,
|
||||||
|
Expired,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToSql<Text, Sqlite> for ProposalStatus {
|
||||||
|
fn to_sql<'b>(
|
||||||
|
&'b self,
|
||||||
|
out: &mut diesel::serialize::Output<'b, '_, Sqlite>,
|
||||||
|
) -> diesel::serialize::Result {
|
||||||
|
let s: &str = match self {
|
||||||
|
Self::Pending => "pending",
|
||||||
|
Self::Approved => "approved",
|
||||||
|
Self::Rejected => "rejected",
|
||||||
|
Self::Expired => "expired",
|
||||||
|
};
|
||||||
|
<str as ToSql<Text, Sqlite>>::to_sql(s, out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromSql<Text, Sqlite> for ProposalStatus {
|
||||||
|
fn from_sql(
|
||||||
|
bytes: <Sqlite as Backend>::RawValue<'_>,
|
||||||
|
) -> diesel::deserialize::Result<Self> {
|
||||||
|
let s = <String as FromSql<Text, Sqlite>>::from_sql(bytes)?;
|
||||||
|
match s.as_str() {
|
||||||
|
"pending" => Ok(Self::Pending),
|
||||||
|
"approved" => Ok(Self::Approved),
|
||||||
|
"rejected" => Ok(Self::Rejected),
|
||||||
|
"expired" => Ok(Self::Expired),
|
||||||
|
other => Err(format!("Unknown proposal status: {other}").into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub use types::*;
|
pub use types::*;
|
||||||
|
|
||||||
@@ -438,3 +478,45 @@ pub struct IntegrityEnvelope {
|
|||||||
pub signed_at: SqliteTimestamp,
|
pub signed_at: SqliteTimestamp,
|
||||||
pub created_at: SqliteTimestamp,
|
pub created_at: SqliteTimestamp,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Queryable, Selectable, Identifiable)]
|
||||||
|
#[diesel(table_name = schema::proposal, check_for_backend(Sqlite))]
|
||||||
|
pub struct Proposal {
|
||||||
|
pub id: i32,
|
||||||
|
pub kind: String,
|
||||||
|
pub payload: Vec<u8>,
|
||||||
|
pub initiator_id: i32,
|
||||||
|
pub created_at: SqliteTimestamp,
|
||||||
|
pub expires_at: SqliteTimestamp,
|
||||||
|
pub status: ProposalStatus,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Insertable)]
|
||||||
|
#[diesel(table_name = schema::proposal, check_for_backend(Sqlite))]
|
||||||
|
pub struct NewProposal {
|
||||||
|
pub kind: String,
|
||||||
|
pub payload: Vec<u8>,
|
||||||
|
pub initiator_id: i32,
|
||||||
|
// status defaults to 'pending' at the DB layer
|
||||||
|
pub expires_at: SqliteTimestamp,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Queryable, Selectable, Identifiable)]
|
||||||
|
#[diesel(table_name = schema::proposal_vote, check_for_backend(Sqlite))]
|
||||||
|
pub struct ProposalVote {
|
||||||
|
pub id: i32,
|
||||||
|
pub proposal_id: i32,
|
||||||
|
pub operator_id: i32,
|
||||||
|
pub approve: bool,
|
||||||
|
pub signature: Vec<u8>,
|
||||||
|
pub voted_at: SqliteTimestamp,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Insertable)]
|
||||||
|
#[diesel(table_name = schema::proposal_vote, check_for_backend(Sqlite))]
|
||||||
|
pub struct NewProposalVote {
|
||||||
|
pub proposal_id: i32,
|
||||||
|
pub operator_id: i32,
|
||||||
|
pub approve: bool,
|
||||||
|
pub signature: Vec<u8>,
|
||||||
|
}
|
||||||
|
|||||||
@@ -172,6 +172,29 @@ diesel::table! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
diesel::table! {
|
||||||
|
proposal (id) {
|
||||||
|
id -> Integer,
|
||||||
|
kind -> Text,
|
||||||
|
payload -> Binary,
|
||||||
|
initiator_id -> Integer,
|
||||||
|
created_at -> Integer,
|
||||||
|
expires_at -> Integer,
|
||||||
|
status -> Text,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diesel::table! {
|
||||||
|
proposal_vote (id) {
|
||||||
|
id -> Integer,
|
||||||
|
proposal_id -> Integer,
|
||||||
|
operator_id -> Integer,
|
||||||
|
approve -> Bool,
|
||||||
|
signature -> Binary,
|
||||||
|
voted_at -> Integer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
program_client (id) {
|
program_client (id) {
|
||||||
id -> Integer,
|
id -> Integer,
|
||||||
@@ -225,6 +248,9 @@ diesel::joinable!(evm_wallet_access -> evm_wallet (wallet_id));
|
|||||||
diesel::joinable!(evm_wallet_access -> program_client (client_id));
|
diesel::joinable!(evm_wallet_access -> program_client (client_id));
|
||||||
diesel::joinable!(operator -> operator_identity (id));
|
diesel::joinable!(operator -> operator_identity (id));
|
||||||
diesel::joinable!(program_client -> client_metadata (metadata_id));
|
diesel::joinable!(program_client -> client_metadata (metadata_id));
|
||||||
|
diesel::joinable!(proposal -> operator_identity (initiator_id));
|
||||||
|
diesel::joinable!(proposal_vote -> proposal (proposal_id));
|
||||||
|
diesel::joinable!(proposal_vote -> operator_identity (operator_id));
|
||||||
|
|
||||||
diesel::allow_tables_to_appear_in_same_query!(
|
diesel::allow_tables_to_appear_in_same_query!(
|
||||||
aead_encrypted,
|
aead_encrypted,
|
||||||
@@ -245,6 +271,8 @@ diesel::allow_tables_to_appear_in_same_query!(
|
|||||||
operator,
|
operator,
|
||||||
operator_identity,
|
operator_identity,
|
||||||
program_client,
|
program_client,
|
||||||
|
proposal,
|
||||||
|
proposal_vote,
|
||||||
root_key_history,
|
root_key_history,
|
||||||
tls_history,
|
tls_history,
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user