use holo_hash::{DnaHash, WasmHash};
use holochain_integrity_types::{
zome::ZomeName, AppEntryName, DnaModifiers, EntryDef, EntryDefId, EntryVisibility,
};
use holochain_serialized_bytes::{SerializedBytes, UnsafeBytes};
use holochain_types::prelude::CellId;
use holochain_zome_types::{
prelude::DnaDef,
zome::{CoordinatorZomeDef, IntegrityZomeDef, WasmZome, ZomeDef},
};
use sqlx::FromRow;
use std::borrow::Cow;
#[derive(Debug, Clone, FromRow)]
pub struct WasmModel {
pub hash: Vec<u8>,
pub code: Vec<u8>,
}
impl WasmModel {
pub fn new(hash: WasmHash, code: Vec<u8>) -> Self {
Self {
hash: hash.get_raw_32().to_vec(),
code,
}
}
pub fn wasm_hash(&self) -> WasmHash {
WasmHash::from_raw_32(self.hash.clone())
}
}
#[derive(Debug, Clone, FromRow)]
pub struct DnaDefModel {
pub hash: Vec<u8>,
pub agent: Vec<u8>,
pub name: String,
pub network_seed: String,
pub properties: Vec<u8>,
pub lineage: Option<sqlx::types::JsonValue>,
}
impl DnaDefModel {
pub fn new(
cell_id: &CellId,
name: String,
network_seed: String,
properties: Vec<u8>,
lineage: Option<sqlx::types::JsonValue>,
) -> Self {
Self {
hash: cell_id.dna_hash().get_raw_32().to_vec(),
agent: cell_id.agent_pubkey().get_raw_32().to_vec(),
name,
network_seed,
properties,
lineage,
}
}
pub fn dna_hash(&self) -> DnaHash {
DnaHash::from_raw_32(self.hash.clone())
}
pub fn agent_pubkey(&self) -> holochain_types::prelude::AgentPubKey {
holochain_types::prelude::AgentPubKey::from_raw_32(self.agent.clone())
}
pub fn to_cell_id(&self) -> CellId {
let dna_hash = self.dna_hash();
let agent = self.agent_pubkey();
CellId::new(dna_hash, agent)
}
pub fn to_dna_def(
&self,
integrity_zomes: Vec<IntegrityZomeModel>,
coordinator_zomes: Vec<CoordinatorZomeModel>,
) -> Result<DnaDef, String> {
let modifiers = DnaModifiers {
network_seed: self.network_seed.clone(),
properties: SerializedBytes::from(UnsafeBytes::from(self.properties.clone())),
};
let integrity_zomes: Result<Vec<_>, _> = integrity_zomes
.iter()
.map(|model| model.to_zome_tuple())
.collect();
let integrity_zomes = integrity_zomes?;
let coordinator_zomes: Result<Vec<_>, _> = coordinator_zomes
.iter()
.map(|model| model.to_zome_tuple())
.collect();
let coordinator_zomes = coordinator_zomes?;
#[cfg(feature = "unstable-migration")]
let lineage = self
.lineage
.as_ref()
.map(|json_value| serde_json::from_value(json_value.clone()))
.transpose()
.map_err(|e: serde_json::Error| e.to_string())?
.unwrap_or_default();
Ok(DnaDef {
name: self.name.clone(),
modifiers,
integrity_zomes,
coordinator_zomes,
#[cfg(feature = "unstable-migration")]
lineage,
})
}
}
#[derive(Debug, Clone, FromRow)]
pub struct IntegrityZomeModel {
pub dna_hash: Vec<u8>,
pub agent: Vec<u8>,
pub zome_index: i64,
pub zome_name: String,
pub wasm_hash: Option<Vec<u8>>,
pub dependencies: sqlx::types::Json<Vec<String>>,
}
impl IntegrityZomeModel {
pub fn new(
cell_id: &CellId,
zome_index: usize,
zome_name: String,
wasm_hash: Option<WasmHash>,
dependencies: Vec<String>,
) -> Self {
Self {
dna_hash: cell_id.dna_hash().get_raw_32().to_vec(),
agent: cell_id.agent_pubkey().get_raw_32().to_vec(),
zome_index: zome_index as i64,
zome_name,
wasm_hash: wasm_hash.map(|h| h.get_raw_32().to_vec()),
dependencies: sqlx::types::Json(dependencies),
}
}
pub fn wasm_hash(&self) -> Option<WasmHash> {
self.wasm_hash
.as_ref()
.map(|bytes| WasmHash::from_raw_32(bytes.clone()))
}
pub fn to_zome_tuple(&self) -> Result<(ZomeName, IntegrityZomeDef), String> {
let zome_name = ZomeName(Cow::Owned(self.zome_name.clone()));
let dependencies: Vec<ZomeName> = self
.dependencies
.0
.iter()
.map(|s| ZomeName(Cow::Owned(s.clone())))
.collect();
let zome_def = if let Some(wasm_hash) = self.wasm_hash() {
IntegrityZomeDef::from(ZomeDef::Wasm(WasmZome {
wasm_hash,
dependencies,
}))
} else {
return Err("Cannot reconstruct inline zomes from database".to_string());
};
Ok((zome_name, zome_def))
}
}
#[derive(Debug, Clone, FromRow)]
pub struct CoordinatorZomeModel {
pub dna_hash: Vec<u8>,
pub agent: Vec<u8>,
pub zome_index: i64,
pub zome_name: String,
pub wasm_hash: Option<Vec<u8>>,
pub dependencies: sqlx::types::Json<Vec<String>>,
}
impl CoordinatorZomeModel {
pub fn new(
cell_id: &CellId,
zome_index: usize,
zome_name: String,
wasm_hash: Option<WasmHash>,
dependencies: Vec<String>,
) -> Self {
Self {
dna_hash: cell_id.dna_hash().get_raw_32().to_vec(),
agent: cell_id.agent_pubkey().get_raw_32().to_vec(),
zome_index: zome_index as i64,
zome_name,
wasm_hash: wasm_hash.map(|h| h.get_raw_32().to_vec()),
dependencies: sqlx::types::Json(dependencies),
}
}
pub fn wasm_hash(&self) -> Option<WasmHash> {
self.wasm_hash
.as_ref()
.map(|bytes| WasmHash::from_raw_32(bytes.clone()))
}
pub fn to_zome_tuple(&self) -> Result<(ZomeName, CoordinatorZomeDef), String> {
let zome_name = ZomeName(Cow::Owned(self.zome_name.clone()));
let dependencies: Vec<ZomeName> = self
.dependencies
.0
.iter()
.map(|s| ZomeName(Cow::Owned(s.clone())))
.collect();
let zome_def = if let Some(wasm_hash) = self.wasm_hash() {
CoordinatorZomeDef::from(ZomeDef::Wasm(WasmZome {
wasm_hash,
dependencies,
}))
} else {
return Err("Cannot reconstruct inline zomes from database".to_string());
};
Ok((zome_name, zome_def))
}
}
#[derive(Debug, Clone, FromRow)]
pub struct EntryDefModel {
pub key: Vec<u8>,
pub entry_def_id: String,
pub entry_def_id_type: String,
pub visibility: String,
pub required_validations: i64,
}
impl EntryDefModel {
pub fn new(
key: Vec<u8>,
entry_def_id: String,
entry_def_id_type: String,
visibility: String,
required_validations: u8,
) -> Self {
Self {
key,
entry_def_id,
entry_def_id_type,
visibility,
required_validations: required_validations as i64,
}
}
pub fn from_entry_def(key: Vec<u8>, entry_def: &EntryDef) -> Self {
let (entry_def_id, entry_def_id_type) = match &entry_def.id {
EntryDefId::App(name) => (name.0.to_string(), "App".to_string()),
EntryDefId::CapClaim => ("CapClaim".to_string(), "CapClaim".to_string()),
EntryDefId::CapGrant => ("CapGrant".to_string(), "CapGrant".to_string()),
};
let visibility = match entry_def.visibility {
EntryVisibility::Public => "Public".to_string(),
EntryVisibility::Private => "Private".to_string(),
};
Self {
key,
entry_def_id,
entry_def_id_type,
visibility,
required_validations: u8::from(entry_def.required_validations) as i64,
}
}
pub fn to_entry_def(&self) -> Result<EntryDef, String> {
let id = match self.entry_def_id_type.as_str() {
"App" => EntryDefId::App(AppEntryName(self.entry_def_id.clone().into())),
"CapClaim" => EntryDefId::CapClaim,
"CapGrant" => EntryDefId::CapGrant,
_ => {
return Err(format!(
"Invalid entry_def_id_type: {}",
self.entry_def_id_type
))
}
};
let visibility = match self.visibility.as_str() {
"Public" => EntryVisibility::Public,
"Private" => EntryVisibility::Private,
_ => return Err(format!("Invalid visibility: {}", self.visibility)),
};
let required_validations_u8: u8 = self
.required_validations
.try_into()
.map_err(|e| format!("Invalid required_validations: {e}"))?;
let required_validations = required_validations_u8.into();
Ok(EntryDef {
id,
visibility,
required_validations,
cache_at_agent_activity: false, })
}
}