pub struct ApplicationPortabilityManifest { /* private fields */ }Expand description
Immutable content-addressed adapter portability manifest.
Implementations§
Source§impl ApplicationPortabilityManifest
impl ApplicationPortabilityManifest
Sourcepub fn compile(
input: ApplicationPortabilityManifestInput,
) -> Result<ApplicationPortabilityManifest, ApplicationPortabilityError>
pub fn compile( input: ApplicationPortabilityManifestInput, ) -> Result<ApplicationPortabilityManifest, ApplicationPortabilityError>
Compiles one bounded mapping manifest without executing application code.
Examples found in repository?
examples/generate_portability_fixtures.rs (lines 119-170)
93fn generate_domain(root: &Path, domain: &Domain<'_>, write: bool) {
94 let bundle = ContractBundle::decode(
95 &fs::read(
96 root.join(domain.application_root)
97 .join("generated/riffdb.contract.bundle"),
98 )
99 .expect("read adapter contract bundle"),
100 )
101 .expect("decode adapter contract bundle");
102 let adapter = AdapterConformanceManifest::decode_canonical(
103 &fs::read(
104 root.join("fixtures/adapters/conformance")
105 .join(domain.name)
106 .join("adapter.conformance.json"),
107 )
108 .expect("read adapter manifest"),
109 )
110 .expect("decode adapter manifest");
111 let observation_hash = empty_observation_hash(domain.empty_collection);
112 let module_hash = adapter
113 .input()
114 .artifacts
115 .iter()
116 .find(|artifact| artifact.kind() == InstallationArtifactKind::QueryModule)
117 .map(|artifact| QueryModuleHash::from_bytes(*artifact.content_hash().as_bytes()))
118 .expect("adapter query module");
119 let manifest = ApplicationPortabilityManifest::compile(ApplicationPortabilityManifestInput {
120 adapter_manifest_hash: adapter.identity(),
121 contract_lineage: bundle.lineage().clone(),
122 contract_version: bundle.contract_version(),
123 contract_bundle_hash: bundle.bundle_hash(),
124 mappings: domain
125 .mappings
126 .iter()
127 .map(|(entity, command)| {
128 PortableRecordMapping::new(
129 PortableRecordClass::Entity,
130 symbol(entity),
131 PortableReimportStrategy::reimport_command(symbol(command)),
132 )
133 })
134 .collect(),
135 omissions: vec![
136 PortableOmission::new(
137 PortableOmissionClass::Provenance,
138 None,
139 PortableOmissionReason::HistoricalRecordsNotRegenerable,
140 )
141 .expect("provenance omission"),
142 PortableOmission::new(
143 PortableOmissionClass::PublicAudit,
144 None,
145 PortableOmissionReason::HistoricalRecordsNotRegenerable,
146 )
147 .expect("audit omission"),
148 ],
149 observations: vec![
150 ReimportObservation::new_with_parameters(
151 symbol("application_observation"),
152 symbol(domain.query),
153 module_hash,
154 domain
155 .parameters
156 .iter()
157 .map(|(name, suffix)| {
158 ReimportObservationParameter::new(
159 symbol(name),
160 CanonicalValue::Uuid(application_uuid(*suffix)),
161 )
162 .expect("observation parameter")
163 })
164 .collect(),
165 observation_hash,
166 500,
167 )
168 .expect("observation"),
169 ],
170 })
171 .expect("compile portability manifest");
172 manifest
173 .validate_compiled_contract(&bundle)
174 .expect("compiled contract mapping");
175 assert_eq!(manifest.input().adapter_manifest_hash, adapter.identity());
176 assert_eq!(
177 manifest.input().contract_lineage,
178 adapter.input().contract_lineage
179 );
180 assert!(adapter.input().evolution.iter().any(|evolution| {
181 evolution.successor().version() == manifest.input().contract_version
182 && evolution.successor().bundle_hash() == manifest.input().contract_bundle_hash
183 }));
184 manifest
185 .validate_adapter_conformance(&adapter)
186 .unwrap_or_else(|error| panic!("{} adapter mapping: {error:?}", domain.name));
187
188 let outcome_hash = hash_generated_artifact(format!("{}-outcomes-v1", domain.name).as_bytes());
189 let destination = root.join("fixtures/export").join(domain.name);
190 let receipt = reimport_receipt(&manifest, domain, outcome_hash);
191 update(
192 destination.join("portability-manifest-v3.json"),
193 manifest.canonical_bytes(),
194 write,
195 );
196 let legacy_manifest_path = destination.join("portability-manifest-v2.json");
197 if legacy_manifest_path.is_file() {
198 let legacy_manifest = ApplicationPortabilityManifest::decode_canonical(
199 &fs::read(legacy_manifest_path).expect("read V2 portability manifest"),
200 )
201 .expect("decode V2 portability manifest");
202 let legacy_receipt = reimport_receipt(&legacy_manifest, domain, outcome_hash);
203 update(
204 destination.join("reimport-receipt-v2.json"),
205 legacy_receipt.canonical_bytes(),
206 write,
207 );
208 }
209 update(
210 destination.join("reimport-receipt-v3.json"),
211 receipt.canonical_bytes(),
212 write,
213 );
214}Sourcepub fn decode_canonical(
bytes: &[u8],
) -> Result<ApplicationPortabilityManifest, ApplicationPortabilityError>
pub fn decode_canonical( bytes: &[u8], ) -> Result<ApplicationPortabilityManifest, ApplicationPortabilityError>
Strictly decodes one canonical manifest, retaining frozen v1 readability.
Examples found in repository?
examples/generate_portability_fixtures.rs (lines 198-200)
93fn generate_domain(root: &Path, domain: &Domain<'_>, write: bool) {
94 let bundle = ContractBundle::decode(
95 &fs::read(
96 root.join(domain.application_root)
97 .join("generated/riffdb.contract.bundle"),
98 )
99 .expect("read adapter contract bundle"),
100 )
101 .expect("decode adapter contract bundle");
102 let adapter = AdapterConformanceManifest::decode_canonical(
103 &fs::read(
104 root.join("fixtures/adapters/conformance")
105 .join(domain.name)
106 .join("adapter.conformance.json"),
107 )
108 .expect("read adapter manifest"),
109 )
110 .expect("decode adapter manifest");
111 let observation_hash = empty_observation_hash(domain.empty_collection);
112 let module_hash = adapter
113 .input()
114 .artifacts
115 .iter()
116 .find(|artifact| artifact.kind() == InstallationArtifactKind::QueryModule)
117 .map(|artifact| QueryModuleHash::from_bytes(*artifact.content_hash().as_bytes()))
118 .expect("adapter query module");
119 let manifest = ApplicationPortabilityManifest::compile(ApplicationPortabilityManifestInput {
120 adapter_manifest_hash: adapter.identity(),
121 contract_lineage: bundle.lineage().clone(),
122 contract_version: bundle.contract_version(),
123 contract_bundle_hash: bundle.bundle_hash(),
124 mappings: domain
125 .mappings
126 .iter()
127 .map(|(entity, command)| {
128 PortableRecordMapping::new(
129 PortableRecordClass::Entity,
130 symbol(entity),
131 PortableReimportStrategy::reimport_command(symbol(command)),
132 )
133 })
134 .collect(),
135 omissions: vec![
136 PortableOmission::new(
137 PortableOmissionClass::Provenance,
138 None,
139 PortableOmissionReason::HistoricalRecordsNotRegenerable,
140 )
141 .expect("provenance omission"),
142 PortableOmission::new(
143 PortableOmissionClass::PublicAudit,
144 None,
145 PortableOmissionReason::HistoricalRecordsNotRegenerable,
146 )
147 .expect("audit omission"),
148 ],
149 observations: vec![
150 ReimportObservation::new_with_parameters(
151 symbol("application_observation"),
152 symbol(domain.query),
153 module_hash,
154 domain
155 .parameters
156 .iter()
157 .map(|(name, suffix)| {
158 ReimportObservationParameter::new(
159 symbol(name),
160 CanonicalValue::Uuid(application_uuid(*suffix)),
161 )
162 .expect("observation parameter")
163 })
164 .collect(),
165 observation_hash,
166 500,
167 )
168 .expect("observation"),
169 ],
170 })
171 .expect("compile portability manifest");
172 manifest
173 .validate_compiled_contract(&bundle)
174 .expect("compiled contract mapping");
175 assert_eq!(manifest.input().adapter_manifest_hash, adapter.identity());
176 assert_eq!(
177 manifest.input().contract_lineage,
178 adapter.input().contract_lineage
179 );
180 assert!(adapter.input().evolution.iter().any(|evolution| {
181 evolution.successor().version() == manifest.input().contract_version
182 && evolution.successor().bundle_hash() == manifest.input().contract_bundle_hash
183 }));
184 manifest
185 .validate_adapter_conformance(&adapter)
186 .unwrap_or_else(|error| panic!("{} adapter mapping: {error:?}", domain.name));
187
188 let outcome_hash = hash_generated_artifact(format!("{}-outcomes-v1", domain.name).as_bytes());
189 let destination = root.join("fixtures/export").join(domain.name);
190 let receipt = reimport_receipt(&manifest, domain, outcome_hash);
191 update(
192 destination.join("portability-manifest-v3.json"),
193 manifest.canonical_bytes(),
194 write,
195 );
196 let legacy_manifest_path = destination.join("portability-manifest-v2.json");
197 if legacy_manifest_path.is_file() {
198 let legacy_manifest = ApplicationPortabilityManifest::decode_canonical(
199 &fs::read(legacy_manifest_path).expect("read V2 portability manifest"),
200 )
201 .expect("decode V2 portability manifest");
202 let legacy_receipt = reimport_receipt(&legacy_manifest, domain, outcome_hash);
203 update(
204 destination.join("reimport-receipt-v2.json"),
205 legacy_receipt.canonical_bytes(),
206 write,
207 );
208 }
209 update(
210 destination.join("reimport-receipt-v3.json"),
211 receipt.canonical_bytes(),
212 write,
213 );
214}Sourcepub const fn identity(&self) -> ApplicationPortabilityManifestHash
pub const fn identity(&self) -> ApplicationPortabilityManifestHash
Exact manifest content identity.
Sourcepub const fn input(&self) -> &ApplicationPortabilityManifestInput
pub const fn input(&self) -> &ApplicationPortabilityManifestInput
Validated mappings and reconciliation contract.
Examples found in repository?
examples/generate_portability_fixtures.rs (line 175)
93fn generate_domain(root: &Path, domain: &Domain<'_>, write: bool) {
94 let bundle = ContractBundle::decode(
95 &fs::read(
96 root.join(domain.application_root)
97 .join("generated/riffdb.contract.bundle"),
98 )
99 .expect("read adapter contract bundle"),
100 )
101 .expect("decode adapter contract bundle");
102 let adapter = AdapterConformanceManifest::decode_canonical(
103 &fs::read(
104 root.join("fixtures/adapters/conformance")
105 .join(domain.name)
106 .join("adapter.conformance.json"),
107 )
108 .expect("read adapter manifest"),
109 )
110 .expect("decode adapter manifest");
111 let observation_hash = empty_observation_hash(domain.empty_collection);
112 let module_hash = adapter
113 .input()
114 .artifacts
115 .iter()
116 .find(|artifact| artifact.kind() == InstallationArtifactKind::QueryModule)
117 .map(|artifact| QueryModuleHash::from_bytes(*artifact.content_hash().as_bytes()))
118 .expect("adapter query module");
119 let manifest = ApplicationPortabilityManifest::compile(ApplicationPortabilityManifestInput {
120 adapter_manifest_hash: adapter.identity(),
121 contract_lineage: bundle.lineage().clone(),
122 contract_version: bundle.contract_version(),
123 contract_bundle_hash: bundle.bundle_hash(),
124 mappings: domain
125 .mappings
126 .iter()
127 .map(|(entity, command)| {
128 PortableRecordMapping::new(
129 PortableRecordClass::Entity,
130 symbol(entity),
131 PortableReimportStrategy::reimport_command(symbol(command)),
132 )
133 })
134 .collect(),
135 omissions: vec![
136 PortableOmission::new(
137 PortableOmissionClass::Provenance,
138 None,
139 PortableOmissionReason::HistoricalRecordsNotRegenerable,
140 )
141 .expect("provenance omission"),
142 PortableOmission::new(
143 PortableOmissionClass::PublicAudit,
144 None,
145 PortableOmissionReason::HistoricalRecordsNotRegenerable,
146 )
147 .expect("audit omission"),
148 ],
149 observations: vec![
150 ReimportObservation::new_with_parameters(
151 symbol("application_observation"),
152 symbol(domain.query),
153 module_hash,
154 domain
155 .parameters
156 .iter()
157 .map(|(name, suffix)| {
158 ReimportObservationParameter::new(
159 symbol(name),
160 CanonicalValue::Uuid(application_uuid(*suffix)),
161 )
162 .expect("observation parameter")
163 })
164 .collect(),
165 observation_hash,
166 500,
167 )
168 .expect("observation"),
169 ],
170 })
171 .expect("compile portability manifest");
172 manifest
173 .validate_compiled_contract(&bundle)
174 .expect("compiled contract mapping");
175 assert_eq!(manifest.input().adapter_manifest_hash, adapter.identity());
176 assert_eq!(
177 manifest.input().contract_lineage,
178 adapter.input().contract_lineage
179 );
180 assert!(adapter.input().evolution.iter().any(|evolution| {
181 evolution.successor().version() == manifest.input().contract_version
182 && evolution.successor().bundle_hash() == manifest.input().contract_bundle_hash
183 }));
184 manifest
185 .validate_adapter_conformance(&adapter)
186 .unwrap_or_else(|error| panic!("{} adapter mapping: {error:?}", domain.name));
187
188 let outcome_hash = hash_generated_artifact(format!("{}-outcomes-v1", domain.name).as_bytes());
189 let destination = root.join("fixtures/export").join(domain.name);
190 let receipt = reimport_receipt(&manifest, domain, outcome_hash);
191 update(
192 destination.join("portability-manifest-v3.json"),
193 manifest.canonical_bytes(),
194 write,
195 );
196 let legacy_manifest_path = destination.join("portability-manifest-v2.json");
197 if legacy_manifest_path.is_file() {
198 let legacy_manifest = ApplicationPortabilityManifest::decode_canonical(
199 &fs::read(legacy_manifest_path).expect("read V2 portability manifest"),
200 )
201 .expect("decode V2 portability manifest");
202 let legacy_receipt = reimport_receipt(&legacy_manifest, domain, outcome_hash);
203 update(
204 destination.join("reimport-receipt-v2.json"),
205 legacy_receipt.canonical_bytes(),
206 write,
207 );
208 }
209 update(
210 destination.join("reimport-receipt-v3.json"),
211 receipt.canonical_bytes(),
212 write,
213 );
214}
215
216fn reimport_receipt(
217 manifest: &ApplicationPortabilityManifest,
218 domain: &Domain<'_>,
219 outcome_hash: riffdb_types::GeneratedArtifactHash,
220) -> ApplicationReimportReceipt {
221 ApplicationReimportReceipt::reconcile(
222 manifest,
223 ApplicationExportManifestHash::from_bytes(
224 *hash_generated_artifact(format!("{}-export-v1", domain.name).as_bytes()).as_bytes(),
225 ),
226 database_id(domain.seed),
227 manifest
228 .input()
229 .mappings
230 .iter()
231 .map(|mapping| {
232 ReimportMappingResult::new(
233 mapping.class(),
234 mapping.symbol().clone(),
235 2,
236 2,
237 0,
238 outcome_hash,
239 )
240 .expect("mapping result")
241 })
242 .collect(),
243 manifest
244 .input()
245 .observations
246 .iter()
247 .map(|observation| {
248 ReimportObservationResult::new(
249 observation.name().clone(),
250 observation.expected_hash(),
251 )
252 })
253 .collect(),
254 )
255 .expect("reimport receipt")
256}Sourcepub fn canonical_bytes(&self) -> &[u8] ⓘ
pub fn canonical_bytes(&self) -> &[u8] ⓘ
Exact canonical JSON bytes with one trailing newline.
Examples found in repository?
examples/generate_portability_fixtures.rs (line 193)
93fn generate_domain(root: &Path, domain: &Domain<'_>, write: bool) {
94 let bundle = ContractBundle::decode(
95 &fs::read(
96 root.join(domain.application_root)
97 .join("generated/riffdb.contract.bundle"),
98 )
99 .expect("read adapter contract bundle"),
100 )
101 .expect("decode adapter contract bundle");
102 let adapter = AdapterConformanceManifest::decode_canonical(
103 &fs::read(
104 root.join("fixtures/adapters/conformance")
105 .join(domain.name)
106 .join("adapter.conformance.json"),
107 )
108 .expect("read adapter manifest"),
109 )
110 .expect("decode adapter manifest");
111 let observation_hash = empty_observation_hash(domain.empty_collection);
112 let module_hash = adapter
113 .input()
114 .artifacts
115 .iter()
116 .find(|artifact| artifact.kind() == InstallationArtifactKind::QueryModule)
117 .map(|artifact| QueryModuleHash::from_bytes(*artifact.content_hash().as_bytes()))
118 .expect("adapter query module");
119 let manifest = ApplicationPortabilityManifest::compile(ApplicationPortabilityManifestInput {
120 adapter_manifest_hash: adapter.identity(),
121 contract_lineage: bundle.lineage().clone(),
122 contract_version: bundle.contract_version(),
123 contract_bundle_hash: bundle.bundle_hash(),
124 mappings: domain
125 .mappings
126 .iter()
127 .map(|(entity, command)| {
128 PortableRecordMapping::new(
129 PortableRecordClass::Entity,
130 symbol(entity),
131 PortableReimportStrategy::reimport_command(symbol(command)),
132 )
133 })
134 .collect(),
135 omissions: vec![
136 PortableOmission::new(
137 PortableOmissionClass::Provenance,
138 None,
139 PortableOmissionReason::HistoricalRecordsNotRegenerable,
140 )
141 .expect("provenance omission"),
142 PortableOmission::new(
143 PortableOmissionClass::PublicAudit,
144 None,
145 PortableOmissionReason::HistoricalRecordsNotRegenerable,
146 )
147 .expect("audit omission"),
148 ],
149 observations: vec![
150 ReimportObservation::new_with_parameters(
151 symbol("application_observation"),
152 symbol(domain.query),
153 module_hash,
154 domain
155 .parameters
156 .iter()
157 .map(|(name, suffix)| {
158 ReimportObservationParameter::new(
159 symbol(name),
160 CanonicalValue::Uuid(application_uuid(*suffix)),
161 )
162 .expect("observation parameter")
163 })
164 .collect(),
165 observation_hash,
166 500,
167 )
168 .expect("observation"),
169 ],
170 })
171 .expect("compile portability manifest");
172 manifest
173 .validate_compiled_contract(&bundle)
174 .expect("compiled contract mapping");
175 assert_eq!(manifest.input().adapter_manifest_hash, adapter.identity());
176 assert_eq!(
177 manifest.input().contract_lineage,
178 adapter.input().contract_lineage
179 );
180 assert!(adapter.input().evolution.iter().any(|evolution| {
181 evolution.successor().version() == manifest.input().contract_version
182 && evolution.successor().bundle_hash() == manifest.input().contract_bundle_hash
183 }));
184 manifest
185 .validate_adapter_conformance(&adapter)
186 .unwrap_or_else(|error| panic!("{} adapter mapping: {error:?}", domain.name));
187
188 let outcome_hash = hash_generated_artifact(format!("{}-outcomes-v1", domain.name).as_bytes());
189 let destination = root.join("fixtures/export").join(domain.name);
190 let receipt = reimport_receipt(&manifest, domain, outcome_hash);
191 update(
192 destination.join("portability-manifest-v3.json"),
193 manifest.canonical_bytes(),
194 write,
195 );
196 let legacy_manifest_path = destination.join("portability-manifest-v2.json");
197 if legacy_manifest_path.is_file() {
198 let legacy_manifest = ApplicationPortabilityManifest::decode_canonical(
199 &fs::read(legacy_manifest_path).expect("read V2 portability manifest"),
200 )
201 .expect("decode V2 portability manifest");
202 let legacy_receipt = reimport_receipt(&legacy_manifest, domain, outcome_hash);
203 update(
204 destination.join("reimport-receipt-v2.json"),
205 legacy_receipt.canonical_bytes(),
206 write,
207 );
208 }
209 update(
210 destination.join("reimport-receipt-v3.json"),
211 receipt.canonical_bytes(),
212 write,
213 );
214}Trait Implementations§
Source§impl ApplicationPortabilityValidation for ApplicationPortabilityManifest
impl ApplicationPortabilityValidation for ApplicationPortabilityManifest
Source§fn validate_compiled_contract(
&self,
bundle: &ContractBundle,
) -> Result<(), ApplicationPortabilityError>
fn validate_compiled_contract( &self, bundle: &ContractBundle, ) -> Result<(), ApplicationPortabilityError>
Verifies every mapping against one exact compiler-owned contract bundle.
Source§fn compiled_reimport_entity_schedule(
&self,
bundle: &ContractBundle,
) -> Result<Vec<EntityTypeId>, ApplicationPortabilityError>
fn compiled_reimport_entity_schedule( &self, bundle: &ContractBundle, ) -> Result<Vec<EntityTypeId>, ApplicationPortabilityError>
Derives the only legal entity reconstitution order.
Source§fn validate_adapter_conformance(
&self,
adapter: &AdapterConformanceManifest,
) -> Result<(), ApplicationPortabilityError>
fn validate_adapter_conformance( &self, adapter: &AdapterConformanceManifest, ) -> Result<(), ApplicationPortabilityError>
Binds mappings and observations to one exact adapter-owned public surface.
Source§impl Clone for ApplicationPortabilityManifest
impl Clone for ApplicationPortabilityManifest
Source§fn clone(&self) -> ApplicationPortabilityManifest
fn clone(&self) -> ApplicationPortabilityManifest
Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from
source. Read moreimpl Eq for ApplicationPortabilityManifest
impl StructuralPartialEq for ApplicationPortabilityManifest
Auto Trait Implementations§
impl Freeze for ApplicationPortabilityManifest
impl RefUnwindSafe for ApplicationPortabilityManifest
impl Send for ApplicationPortabilityManifest
impl Sync for ApplicationPortabilityManifest
impl Unpin for ApplicationPortabilityManifest
impl UnsafeUnpin for ApplicationPortabilityManifest
impl UnwindSafe for ApplicationPortabilityManifest
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more