|
@@ -1,202 +0,0 @@
|
|
|
-use crate::{
|
|
|
- prelude::*,
|
|
|
- schema::{
|
|
|
- datum::{ConcreteDatumList, Datum, DatumDiscriminator, DatumDiscriminatorRef},
|
|
|
- entity::{Entity, EntityID, EntityPart, EntityPartList, EntityPartVisitor, EntityVisitor},
|
|
|
- relation::{Relation, RelationDomain, RelationMap, RelationRange},
|
|
|
- },
|
|
|
-};
|
|
|
-
|
|
|
-use super::{CLIError, EntityInterface, ValueRole};
|
|
|
-use clap::{FromArgMatches, Subcommand};
|
|
|
-
|
|
|
-
|
|
|
-// helper alias for later
|
|
|
-type UniqueList<E> = <<E as Entity>::Keys as EntityPartList>::DatumList;
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-#[derive(Debug)]
|
|
|
-/// Type implementing `Subcommand` for a given entity and interface.
|
|
|
-pub struct ClapInterface<O: CLIObject, IC: InterfaceCustomization> {
|
|
|
- verb: InterfaceVerb<O>,
|
|
|
- _ghost: std::marker::PhantomData<IC>,
|
|
|
-}
|
|
|
-
|
|
|
-impl<O: CLIObject, IC: InterfaceCustomization> ClapInterface<O, IC> {
|
|
|
- /// Execute the action that this ClapInterface instance describes. Note that if `Spec` is
|
|
|
- /// chosen as [`EmptyList`](../schema/entity/struct.EmptyList.html), the value passed for the
|
|
|
- /// `spec` parameter should be the unit type, `()`.
|
|
|
- pub fn perform(
|
|
|
- &self,
|
|
|
- data: &O::CommandData,
|
|
|
- ic: &IC,
|
|
|
- query_ctx: impl microrm::prelude::Queryable<EntityOutput = O>,
|
|
|
- insert_ctx: &impl microrm::prelude::Insertable<O>,
|
|
|
- ) -> Result<(), O::Error> {
|
|
|
- match &self.verb {
|
|
|
- InterfaceVerb::Attach {
|
|
|
- local_keys,
|
|
|
- relation,
|
|
|
- remote_keys,
|
|
|
- } => {
|
|
|
- let local_keys = EntityKey::to_string_vec(local_keys, ic);
|
|
|
- let remote_keys = EntityKey::to_string_vec(remote_keys, ic);
|
|
|
- let outer_obj = query_ctx
|
|
|
- .keyed(
|
|
|
- UniqueList::<O>::build_equivalent(local_keys.iter().map(String::as_str))
|
|
|
- .unwrap(),
|
|
|
- )
|
|
|
- .get()?
|
|
|
- .ok_or(<O::Error>::no_such_entity(
|
|
|
- O::entity_name(),
|
|
|
- local_keys
|
|
|
- .iter()
|
|
|
- .cloned()
|
|
|
- .reduce(|a, b| format!("{},{}", a, b))
|
|
|
- .unwrap()
|
|
|
- .to_string(),
|
|
|
- ))?;
|
|
|
-
|
|
|
- let mut attacher = Attacher {
|
|
|
- do_attach: true,
|
|
|
- relation,
|
|
|
- remote_keys,
|
|
|
- err: None,
|
|
|
- _ghost: Default::default(),
|
|
|
- };
|
|
|
- outer_obj.accept_part_visitor_ref(&mut attacher);
|
|
|
-
|
|
|
- if let Some(err) = attacher.err {
|
|
|
- return Err(err);
|
|
|
- }
|
|
|
- },
|
|
|
- InterfaceVerb::Create(params) => {
|
|
|
- insert_ctx.insert(O::create_from_params(data, params)?)?;
|
|
|
- },
|
|
|
- InterfaceVerb::Delete(keys) => {
|
|
|
- let keys = EntityKey::to_string_vec(keys, ic);
|
|
|
- query_ctx
|
|
|
- .keyed(
|
|
|
- UniqueList::<O>::build_equivalent(keys.iter().map(String::as_str)).unwrap(),
|
|
|
- )
|
|
|
- .delete()?;
|
|
|
- },
|
|
|
- InterfaceVerb::Detach {
|
|
|
- local_keys,
|
|
|
- relation,
|
|
|
- remote_keys,
|
|
|
- } => {
|
|
|
- let local_keys = EntityKey::to_string_vec(local_keys, ic);
|
|
|
- let remote_keys = EntityKey::to_string_vec(remote_keys, ic);
|
|
|
- let outer_obj = query_ctx
|
|
|
- .keyed(
|
|
|
- UniqueList::<O>::build_equivalent(local_keys.iter().map(String::as_str))
|
|
|
- .unwrap(),
|
|
|
- )
|
|
|
- .get()?
|
|
|
- .ok_or(<O::Error>::no_such_entity(
|
|
|
- O::entity_name(),
|
|
|
- local_keys
|
|
|
- .iter()
|
|
|
- .cloned()
|
|
|
- .reduce(|a, b| format!("{},{}", a, b))
|
|
|
- .unwrap()
|
|
|
- .to_string(),
|
|
|
- ))?;
|
|
|
-
|
|
|
- let mut attacher = Attacher {
|
|
|
- do_attach: false,
|
|
|
- relation,
|
|
|
- remote_keys,
|
|
|
- err: None,
|
|
|
- _ghost: Default::default(),
|
|
|
- };
|
|
|
- outer_obj.accept_part_visitor_ref(&mut attacher);
|
|
|
-
|
|
|
- if let Some(err) = attacher.err {
|
|
|
- return Err(err);
|
|
|
- }
|
|
|
- },
|
|
|
- InterfaceVerb::ListAll => {
|
|
|
- println!(
|
|
|
- "Listing all {}(s): ({})",
|
|
|
- O::entity_name(),
|
|
|
- query_ctx.clone().count()?
|
|
|
- );
|
|
|
- for obj in query_ctx.get()?.into_iter() {
|
|
|
- println!(" - {}", obj.shortname());
|
|
|
- }
|
|
|
- },
|
|
|
- InterfaceVerb::Inspect(keys) => {
|
|
|
- let keys = EntityKey::to_string_vec(keys, ic);
|
|
|
- let obj = query_ctx
|
|
|
- .keyed(
|
|
|
- UniqueList::<O>::build_equivalent(keys.iter().map(String::as_str)).unwrap(),
|
|
|
- )
|
|
|
- .get()?
|
|
|
- .ok_or(<O::Error>::no_such_entity(
|
|
|
- O::entity_name(),
|
|
|
- keys.iter()
|
|
|
- .cloned()
|
|
|
- .reduce(|a, b| format!("{},{}", a, b))
|
|
|
- .unwrap()
|
|
|
- .to_string(),
|
|
|
- ))?;
|
|
|
- println!("{:#?}", obj.as_ref());
|
|
|
-
|
|
|
- fn inspect_ai<AI: RelationInterface>(name: &'static str, ai: &AI) {
|
|
|
- println!("{}: ({})", name, ai.count().unwrap());
|
|
|
- for a in ai.get().expect("couldn't get object relations") {
|
|
|
- println!("[#{:3}]: {:?}", a.id().into_raw(), a.wrapped());
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- struct RelationFieldWalker<E: Entity>(std::marker::PhantomData<E>);
|
|
|
- impl<E: Entity> EntityPartVisitor for RelationFieldWalker<E> {
|
|
|
- type Entity = E;
|
|
|
- fn visit_datum<EP: EntityPart>(&mut self, datum: &EP::Datum) {
|
|
|
- struct Discriminator(&'static str);
|
|
|
-
|
|
|
- impl DatumDiscriminatorRef for Discriminator {
|
|
|
- fn visit_serialized<
|
|
|
- T: serde::Serialize + serde::de::DeserializeOwned,
|
|
|
- >(
|
|
|
- &mut self,
|
|
|
- _: &T,
|
|
|
- ) {
|
|
|
- }
|
|
|
- fn visit_bare_field<T: Datum>(&mut self, _: &T) {}
|
|
|
- fn visit_entity_id<E: Entity>(&mut self, _: &E::ID) {}
|
|
|
- fn visit_relation_map<E: Entity>(&mut self, amap: &RelationMap<E>) {
|
|
|
- inspect_ai(self.0, amap);
|
|
|
- }
|
|
|
- fn visit_relation_domain<R: Relation>(
|
|
|
- &mut self,
|
|
|
- adomain: &RelationDomain<R>,
|
|
|
- ) {
|
|
|
- inspect_ai(self.0, adomain);
|
|
|
- }
|
|
|
- fn visit_relation_range<R: Relation>(
|
|
|
- &mut self,
|
|
|
- arange: &RelationRange<R>,
|
|
|
- ) {
|
|
|
- inspect_ai(self.0, arange);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- datum.accept_discriminator_ref(&mut Discriminator(EP::part_name()));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- obj.accept_part_visitor_ref(&mut RelationFieldWalker(Default::default()));
|
|
|
- },
|
|
|
- InterfaceVerb::Extra(extra) => {
|
|
|
- O::run_extra_command(data, extra, query_ctx, insert_ctx)?;
|
|
|
- },
|
|
|
- }
|
|
|
- Ok(())
|
|
|
- }
|
|
|
-
|
|
|
-}
|
|
|
-
|