use std::collections::HashMap;
use std::sync::Arc;
use arc_swap::ArcSwap;
use dashmap::DashMap;
use parking_lot::{Mutex, RwLock};
use smol_str::SmolStr;
use crate::errors::PluginError;
use crate::plugin::PluginId;
use crate::qname::QName;
use crate::traits::aggregate::{AggSignature, AggregatePluginFn};
use crate::traits::algorithm::{AlgorithmProvider, PregelProgramProvider};
use crate::traits::background::BackgroundJobProvider;
use crate::traits::catalog::{CatalogProvider, ReplacementScanProvider};
use crate::traits::cdc::CdcOutputProvider;
use crate::traits::collation::CollationProvider;
use crate::traits::connector::{AuthProvider, AuthzPolicy, Connector};
use crate::traits::crdt::{CrdtKind, CrdtKindProvider};
use crate::traits::hook::SessionHook;
use crate::traits::index::{IndexHandle, IndexKind, IndexKindProvider};
use crate::traits::locy::{LocyAggregate, LocyPredicate, PredSignature};
use crate::traits::operator::{OperatorProvider, OptimizerRuleProvider};
use crate::traits::procedure::{ProcedurePlugin, ProcedureSignature};
use crate::traits::scalar::{FnSignature, ScalarPluginFn};
use crate::traits::storage::StorageBackend;
use crate::traits::trigger::TriggerPlugin;
use crate::traits::types::LogicalTypeProvider;
use crate::traits::window::{WindowPluginFn, WindowSignature};
pub struct ScalarEntry {
pub plugin: PluginId,
pub signature: FnSignature,
pub function: Arc<dyn ScalarPluginFn>,
}
impl std::fmt::Debug for ScalarEntry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ScalarEntry")
.field("plugin", &self.plugin)
.field("signature", &self.signature)
.finish_non_exhaustive()
}
}
pub struct AggregateEntry {
pub plugin: PluginId,
pub signature: AggSignature,
pub aggregate: Arc<dyn AggregatePluginFn>,
}
impl std::fmt::Debug for AggregateEntry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AggregateEntry")
.field("plugin", &self.plugin)
.field("signature", &self.signature)
.finish_non_exhaustive()
}
}
pub struct WindowEntry {
pub plugin: PluginId,
pub signature: WindowSignature,
pub window: Arc<dyn WindowPluginFn>,
}
impl std::fmt::Debug for WindowEntry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("WindowEntry")
.field("plugin", &self.plugin)
.field("signature", &self.signature)
.finish_non_exhaustive()
}
}
pub struct ProcedureEntry {
pub plugin: PluginId,
pub signature: ProcedureSignature,
pub procedure: Arc<dyn ProcedurePlugin>,
}
impl std::fmt::Debug for ProcedureEntry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ProcedureEntry")
.field("plugin", &self.plugin)
.field("signature", &self.signature)
.finish_non_exhaustive()
}
}
pub struct LocyAggregateEntry {
pub plugin: PluginId,
pub aggregate: Arc<dyn LocyAggregate>,
}
impl std::fmt::Debug for LocyAggregateEntry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LocyAggregateEntry")
.field("plugin", &self.plugin)
.finish_non_exhaustive()
}
}
pub struct LocyPredicateEntry {
pub plugin: PluginId,
pub signature: PredSignature,
pub predicate: Arc<dyn LocyPredicate>,
}
impl std::fmt::Debug for LocyPredicateEntry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LocyPredicateEntry")
.field("plugin", &self.plugin)
.field("signature", &self.signature)
.finish_non_exhaustive()
}
}
#[derive(Clone)]
pub struct IndexHandleEntry {
pub kind: IndexKind,
pub handle: Arc<dyn IndexHandle>,
}
impl std::fmt::Debug for IndexHandleEntry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("IndexHandleEntry")
.field("kind", &self.kind)
.finish_non_exhaustive()
}
}
#[derive(Clone)]
pub struct VirtualEntry {
pub name: SmolStr,
pub table: Arc<dyn crate::traits::catalog::CatalogTable>,
}
impl std::fmt::Debug for VirtualEntry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("VirtualEntry")
.field("name", &self.name)
.finish_non_exhaustive()
}
}
trait VirtualId:
Copy + Eq + Ord + std::hash::Hash + std::fmt::Debug + std::fmt::LowerHex + 'static
{
const START: Self;
const SENTINEL: Self;
const KIND_LABEL: &'static str;
fn next(self) -> Self;
}
impl VirtualId for u16 {
const START: Self = uni_common::core::schema::VIRTUAL_LABEL_ID_START;
const SENTINEL: Self = uni_common::core::schema::VIRTUAL_LABEL_ID_SENTINEL;
const KIND_LABEL: &'static str = "label";
fn next(self) -> Self {
self.saturating_add(1)
}
}
impl VirtualId for u32 {
const START: Self = uni_common::core::edge_type::VIRTUAL_EDGE_TYPE_ID_START;
const SENTINEL: Self = uni_common::core::edge_type::VIRTUAL_EDGE_TYPE_ID_SENTINEL;
const KIND_LABEL: &'static str = "edge-type";
fn next(self) -> Self {
self.saturating_add(1)
}
}
#[derive(Debug)]
struct VirtualIdSpace<Id: VirtualId> {
name_to_id: HashMap<SmolStr, Id>,
id_to_entry: HashMap<Id, VirtualEntry>,
next_id: Id,
}
impl<Id: VirtualId> Default for VirtualIdSpace<Id> {
fn default() -> Self {
Self {
name_to_id: HashMap::new(),
id_to_entry: HashMap::new(),
next_id: Id::START,
}
}
}
impl<Id: VirtualId> VirtualIdSpace<Id> {
fn register(
&mut self,
name: SmolStr,
table: Arc<dyn crate::traits::catalog::CatalogTable>,
) -> Result<Id, PluginError> {
if let Some(&id) = self.name_to_id.get(&name) {
self.id_to_entry.insert(
id,
VirtualEntry {
name: name.clone(),
table,
},
);
return Ok(id);
}
if self.next_id >= Id::SENTINEL {
return Err(PluginError::Internal(format!(
"virtual {}-ID space exhausted ({} slots taken; sentinel {:#x})",
Id::KIND_LABEL,
self.id_to_entry.len(),
Id::SENTINEL,
)));
}
let id = self.next_id;
self.next_id = self.next_id.next();
self.name_to_id.insert(name.clone(), id);
self.id_to_entry.insert(id, VirtualEntry { name, table });
Ok(id)
}
}
#[derive(Default, Debug)]
pub(crate) struct PluginRecord {
pub(crate) scalars: Vec<QName>,
pub(crate) aggregates: Vec<QName>,
pub(crate) windows: Vec<QName>,
pub(crate) procedures: Vec<(QName, usize)>,
pub(crate) locy_aggregates: Vec<QName>,
pub(crate) locy_predicates: Vec<QName>,
pub(crate) operators: Vec<QName>,
pub(crate) algorithms: Vec<QName>,
pub(crate) pregels: Vec<QName>,
pub(crate) index_kinds: Vec<IndexKind>,
pub(crate) storage_schemes: Vec<SmolStr>,
pub(crate) label_storages: Vec<SmolStr>,
pub(crate) crdt_kinds: Vec<CrdtKind>,
pub(crate) logical_types: Vec<SmolStr>,
pub(crate) collations: Vec<SmolStr>,
pub(crate) cdc_outputs: Vec<SmolStr>,
pub(crate) catalogs: Vec<SmolStr>,
pub(crate) hook_count: usize,
pub(crate) auth_count: usize,
pub(crate) authz_count: usize,
pub(crate) connector_count: usize,
pub(crate) trigger_count: usize,
pub(crate) replacement_scan_count: usize,
pub(crate) optimizer_rule_count: usize,
pub(crate) background_job_count: usize,
}
#[derive(Clone, Debug, Default)]
pub struct PluginRecordSnapshot {
pub scalars: Vec<QName>,
pub aggregates: Vec<QName>,
pub windows: Vec<QName>,
pub procedures: Vec<(QName, usize)>,
pub locy_aggregates: Vec<QName>,
pub locy_predicates: Vec<QName>,
pub operators: Vec<QName>,
pub algorithms: Vec<QName>,
pub pregels: Vec<QName>,
pub index_kinds: Vec<IndexKind>,
pub storage_schemes: Vec<SmolStr>,
pub label_storages: Vec<SmolStr>,
pub crdt_kinds: Vec<CrdtKind>,
pub logical_types: Vec<SmolStr>,
pub collations: Vec<SmolStr>,
pub cdc_outputs: Vec<SmolStr>,
pub catalogs: Vec<SmolStr>,
pub hook_count: usize,
pub auth_count: usize,
pub authz_count: usize,
pub connector_count: usize,
pub trigger_count: usize,
pub replacement_scan_count: usize,
pub optimizer_rule_count: usize,
pub background_job_count: usize,
}
impl From<&PluginRecord> for PluginRecordSnapshot {
fn from(r: &PluginRecord) -> Self {
Self {
scalars: r.scalars.clone(),
aggregates: r.aggregates.clone(),
windows: r.windows.clone(),
procedures: r.procedures.clone(),
locy_aggregates: r.locy_aggregates.clone(),
locy_predicates: r.locy_predicates.clone(),
operators: r.operators.clone(),
algorithms: r.algorithms.clone(),
pregels: r.pregels.clone(),
index_kinds: r.index_kinds.clone(),
storage_schemes: r.storage_schemes.clone(),
label_storages: r.label_storages.clone(),
crdt_kinds: r.crdt_kinds.clone(),
logical_types: r.logical_types.clone(),
collations: r.collations.clone(),
cdc_outputs: r.cdc_outputs.clone(),
catalogs: r.catalogs.clone(),
hook_count: r.hook_count,
auth_count: r.auth_count,
authz_count: r.authz_count,
connector_count: r.connector_count,
trigger_count: r.trigger_count,
replacement_scan_count: r.replacement_scan_count,
optimizer_rule_count: r.optimizer_rule_count,
background_job_count: r.background_job_count,
}
}
}
#[derive(Default)]
pub struct PluginRegistry {
pub(crate) scalars: DashMap<QName, Arc<ScalarEntry>>,
pub(crate) aggregates: DashMap<QName, Arc<AggregateEntry>>,
pub(crate) windows: DashMap<QName, Arc<WindowEntry>>,
pub(crate) procedures: DashMap<QName, Vec<Arc<ProcedureEntry>>>,
pub(crate) locy_aggregates: DashMap<QName, Arc<LocyAggregateEntry>>,
pub(crate) locy_predicates: DashMap<QName, Arc<LocyPredicateEntry>>,
pub(crate) operators: DashMap<QName, Arc<dyn OperatorProvider>>,
pub(crate) optimizer_rules:
ArcSwap<Vec<crate::surfaces::AppendEntry<dyn OptimizerRuleProvider>>>,
pub(crate) algorithms: DashMap<QName, Arc<dyn AlgorithmProvider>>,
pub(crate) pregels: DashMap<QName, Arc<dyn PregelProgramProvider>>,
pub(crate) index_kinds: DashMap<IndexKind, Arc<dyn IndexKindProvider>>,
index_handles: DashMap<SmolStr, IndexHandleEntry>,
pub(crate) storage_backends: DashMap<SmolStr, Arc<dyn StorageBackend>>,
pub(crate) label_storages: DashMap<SmolStr, Arc<dyn crate::traits::storage::Storage>>,
pub(crate) crdt_kinds: DashMap<CrdtKind, Arc<dyn CrdtKindProvider>>,
pub(crate) hooks: ArcSwap<Vec<crate::surfaces::AppendEntry<dyn SessionHook>>>,
pub(crate) logical_types: DashMap<SmolStr, Arc<dyn LogicalTypeProvider>>,
pub(crate) auth_providers: ArcSwap<Vec<crate::surfaces::AppendEntry<dyn AuthProvider>>>,
pub(crate) authz_policies: ArcSwap<Vec<crate::surfaces::AppendEntry<dyn AuthzPolicy>>>,
pub(crate) connectors: ArcSwap<Vec<crate::surfaces::AppendEntry<dyn Connector>>>,
pub(crate) triggers: ArcSwap<Vec<crate::surfaces::AppendEntry<dyn TriggerPlugin>>>,
pub(crate) collations: DashMap<SmolStr, Arc<dyn CollationProvider>>,
pub(crate) cdc_outputs: DashMap<SmolStr, Arc<dyn CdcOutputProvider>>,
pub(crate) catalogs: DashMap<SmolStr, Arc<dyn CatalogProvider>>,
pub(crate) replacement_scans:
ArcSwap<Vec<crate::surfaces::AppendEntry<dyn ReplacementScanProvider>>>,
pub(crate) background_jobs:
ArcSwap<Vec<crate::surfaces::AppendEntry<dyn BackgroundJobProvider>>>,
virtual_labels: Mutex<VirtualIdSpace<u16>>,
virtual_edge_types: Mutex<VirtualIdSpace<u32>>,
per_plugin: RwLock<dashmap::DashMap<PluginId, PluginRecord>>,
}
impl std::fmt::Debug for PluginRegistry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PluginRegistry")
.field("scalar_fns", &self.scalars.len())
.field("aggregates", &self.aggregates.len())
.field("procedures", &self.procedures.len())
.field("locy_aggregates", &self.locy_aggregates.len())
.field("algorithms", &self.algorithms.len())
.field("storage_backends", &self.storage_backends.len())
.field("index_kinds", &self.index_kinds.len())
.field("hooks", &self.hooks.load().len())
.field("plugins", &self.per_plugin.read().len())
.finish()
}
}
impl PluginRegistry {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn scalar_fn(&self, q: &QName) -> Option<Arc<ScalarEntry>> {
self.scalars.get(q).map(|e| Arc::clone(e.value()))
}
#[must_use]
pub fn iter_scalars(&self) -> Vec<(QName, Arc<ScalarEntry>)> {
self.scalars
.iter()
.map(|kv| (kv.key().clone(), Arc::clone(kv.value())))
.collect()
}
#[must_use]
pub fn iter_procedures(&self) -> Vec<(QName, Arc<ProcedureEntry>)> {
self.procedures
.iter()
.flat_map(|kv| {
let q = kv.key().clone();
kv.value()
.iter()
.map(move |e| (q.clone(), Arc::clone(e)))
.collect::<Vec<_>>()
})
.collect()
}
#[must_use]
pub fn iter_locy_aggregates(&self) -> Vec<(QName, Arc<LocyAggregateEntry>)> {
self.locy_aggregates
.iter()
.map(|kv| (kv.key().clone(), Arc::clone(kv.value())))
.collect()
}
#[must_use]
pub fn iter_algorithms(&self) -> Vec<(QName, Arc<dyn AlgorithmProvider>)> {
self.algorithms
.iter()
.map(|kv| (kv.key().clone(), Arc::clone(kv.value())))
.collect()
}
#[must_use]
pub fn iter_index_kinds(&self) -> Vec<(IndexKind, Arc<dyn IndexKindProvider>)> {
self.index_kinds
.iter()
.map(|kv| (kv.key().clone(), Arc::clone(kv.value())))
.collect()
}
#[must_use]
pub fn catalogs(&self) -> Vec<Arc<dyn CatalogProvider>> {
self.catalogs
.iter()
.map(|kv| Arc::clone(kv.value()))
.collect()
}
#[must_use]
pub fn aggregate(&self, q: &QName) -> Option<Arc<AggregateEntry>> {
self.aggregates.get(q).map(|e| Arc::clone(e.value()))
}
#[must_use]
pub fn window(&self, q: &QName) -> Option<Arc<WindowEntry>> {
self.windows.get(q).map(|e| Arc::clone(e.value()))
}
#[must_use]
pub fn procedure(&self, q: &QName) -> Option<Arc<ProcedureEntry>> {
self.procedures
.get(q)
.and_then(|e| e.value().first().map(Arc::clone))
}
#[must_use]
pub fn procedure_with_arity(&self, q: &QName, arity: usize) -> Option<Arc<ProcedureEntry>> {
self.procedures.get(q).and_then(|e| {
e.value()
.iter()
.find(|entry| entry.signature.args.len() == arity)
.map(Arc::clone)
})
}
#[must_use]
pub fn procedure_overloads(&self, q: &QName) -> Vec<Arc<ProcedureEntry>> {
self.procedures
.get(q)
.map(|e| e.value().iter().map(Arc::clone).collect())
.unwrap_or_default()
}
#[must_use]
pub fn locy_aggregate(&self, q: &QName) -> Option<Arc<LocyAggregateEntry>> {
self.locy_aggregates.get(q).map(|e| Arc::clone(e.value()))
}
#[must_use]
pub fn locy_predicate(&self, q: &QName) -> Option<Arc<LocyPredicateEntry>> {
self.locy_predicates.get(q).map(|e| Arc::clone(e.value()))
}
#[must_use]
pub fn storage_backend(&self, scheme: &str) -> Option<Arc<dyn StorageBackend>> {
self.storage_backends
.get(&SmolStr::new(scheme))
.map(|e| Arc::clone(e.value()))
}
#[must_use]
pub fn lookup_label_storage(
&self,
label: &str,
) -> Option<Arc<dyn crate::traits::storage::Storage>> {
self.label_storages
.get(&SmolStr::new(label))
.map(|e| Arc::clone(e.value()))
}
#[must_use]
pub fn index_kind(&self, k: &IndexKind) -> Option<Arc<dyn IndexKindProvider>> {
self.index_kinds.get(k).map(|e| Arc::clone(e.value()))
}
pub fn register_index_handle(
&self,
name: impl Into<SmolStr>,
kind: IndexKind,
handle: Arc<dyn IndexHandle>,
) {
self.index_handles
.insert(name.into(), IndexHandleEntry { kind, handle });
}
#[must_use]
pub fn index_handle(&self, name: &str) -> Option<IndexHandleEntry> {
self.index_handles
.get(&SmolStr::new(name))
.map(|e| e.value().clone())
}
pub fn deregister_index_handle(&self, name: &str) -> Option<IndexHandleEntry> {
self.index_handles
.remove(&SmolStr::new(name))
.map(|(_, v)| v)
}
pub fn register_virtual_label(
&self,
name: impl Into<SmolStr>,
table: Arc<dyn crate::traits::catalog::CatalogTable>,
) -> Result<u16, PluginError> {
self.virtual_labels.lock().register(name.into(), table)
}
#[must_use]
pub fn virtual_label_by_name(&self, name: &str) -> Option<u16> {
let inner = self.virtual_labels.lock();
inner.name_to_id.get(&SmolStr::new(name)).copied()
}
#[must_use]
pub fn virtual_label_by_id(&self, id: u16) -> Option<VirtualEntry> {
self.virtual_labels.lock().id_to_entry.get(&id).cloned()
}
pub fn register_virtual_edge_type(
&self,
name: impl Into<SmolStr>,
table: Arc<dyn crate::traits::catalog::CatalogTable>,
) -> Result<u32, PluginError> {
self.virtual_edge_types.lock().register(name.into(), table)
}
#[must_use]
pub fn virtual_edge_type_by_name(&self, name: &str) -> Option<u32> {
let inner = self.virtual_edge_types.lock();
inner.name_to_id.get(&SmolStr::new(name)).copied()
}
#[must_use]
pub fn virtual_edge_type_by_id(&self, id: u32) -> Option<VirtualEntry> {
self.virtual_edge_types.lock().id_to_entry.get(&id).cloned()
}
#[must_use]
pub fn algorithm(&self, q: &QName) -> Option<Arc<dyn AlgorithmProvider>> {
self.algorithms.get(q).map(|e| Arc::clone(e.value()))
}
#[must_use]
pub fn crdt_kind(&self, k: &CrdtKind) -> Option<Arc<dyn CrdtKindProvider>> {
self.crdt_kinds.get(k).map(|e| Arc::clone(e.value()))
}
#[must_use]
pub fn logical_type(&self, name: &SmolStr) -> Option<Arc<dyn LogicalTypeProvider>> {
self.logical_types.get(name).map(|e| Arc::clone(e.value()))
}
#[must_use]
pub fn hooks(&self) -> Arc<Vec<Arc<dyn SessionHook>>> {
Self::project_append(&self.hooks)
}
#[must_use]
pub fn optimizer_rules(&self) -> Arc<Vec<Arc<dyn OptimizerRuleProvider>>> {
Self::project_append(&self.optimizer_rules)
}
#[must_use]
pub fn triggers(&self) -> Arc<Vec<Arc<dyn TriggerPlugin>>> {
Self::project_append(&self.triggers)
}
#[must_use]
pub fn cdc_outputs_snapshot(&self) -> Vec<(SmolStr, Arc<dyn CdcOutputProvider>)> {
self.cdc_outputs
.iter()
.map(|e| (e.key().clone(), Arc::clone(e.value())))
.collect()
}
#[must_use]
pub fn cdc_outputs_is_empty(&self) -> bool {
self.cdc_outputs.is_empty()
}
#[must_use]
pub fn auth_providers(&self) -> Arc<Vec<Arc<dyn AuthProvider>>> {
Self::project_append(&self.auth_providers)
}
#[must_use]
pub fn authz_policies(&self) -> Arc<Vec<Arc<dyn AuthzPolicy>>> {
Self::project_append(&self.authz_policies)
}
#[must_use]
pub fn connectors(&self) -> Arc<Vec<Arc<dyn Connector>>> {
Self::project_append(&self.connectors)
}
#[must_use]
pub fn replacement_scans(&self) -> Arc<Vec<Arc<dyn ReplacementScanProvider>>> {
Self::project_append(&self.replacement_scans)
}
pub(crate) fn apply_pending(
&self,
plugin_id: &PluginId,
pending: Vec<Box<dyn crate::surfaces::DynPendingRegistration>>,
) -> Result<(), PluginError> {
for reg in &pending {
reg.preflight(self)?;
}
let mut record = PluginRecord::default();
for reg in pending {
reg.apply(self, plugin_id.clone(), &mut record);
}
self.per_plugin.read().insert(plugin_id.clone(), record);
Ok(())
}
#[must_use]
pub fn background_jobs(&self) -> Arc<Vec<Arc<dyn BackgroundJobProvider>>> {
Self::project_append(&self.background_jobs)
}
fn project_append<P: ?Sized>(
slot: &ArcSwap<Vec<crate::surfaces::AppendEntry<P>>>,
) -> Arc<Vec<Arc<P>>> {
let snap = slot.load();
let v: Vec<Arc<P>> = snap.iter().map(|e| Arc::clone(&e.provider)).collect();
Arc::new(v)
}
#[must_use]
pub fn iter_for_plugin(&self, plugin: &PluginId) -> Option<PluginRecordSnapshot> {
let guard = self.per_plugin.read();
guard.get(plugin).map(|r| PluginRecordSnapshot::from(&*r))
}
pub fn remove_plugin(&self, plugin: &PluginId) {
use crate::surfaces::{
AggregateSurface, AlgorithmSurface, AppendOps, AuthSurface, AuthzSurface,
BackgroundJobSurface, CatalogSurface, CdcSurface, CollationSurface, ConnectorSurface,
CrdtSurface, Discriminator, HookSurface, IndexKindSurface, KeyedUniqueOps,
LabelStorageSurface, LocyAggregateSurface, LocyPredicateSurface, LogicalTypeSurface,
NamedUniqueOps, OperatorSurface, OptimizerRuleSurface, PregelSurface, ProcedureSurface,
ReplacementScanSurface, ScalarSurface, StorageBackendSurface, TriggerSurface,
VersionedOps, WindowSurface,
};
let record = self.per_plugin.read().remove(plugin).map(|(_, r)| r);
let Some(record) = record else { return };
for q in record.scalars {
<ScalarSurface as NamedUniqueOps>::remove(self, &q);
}
for q in record.aggregates {
<AggregateSurface as NamedUniqueOps>::remove(self, &q);
}
for q in record.windows {
<WindowSurface as NamedUniqueOps>::remove(self, &q);
}
for (q, arity) in record.procedures {
<ProcedureSurface as VersionedOps>::remove(self, &q, Discriminator::Arity(arity));
}
for q in record.locy_aggregates {
<LocyAggregateSurface as NamedUniqueOps>::remove(self, &q);
}
for q in record.locy_predicates {
<LocyPredicateSurface as NamedUniqueOps>::remove(self, &q);
}
for q in record.operators {
<OperatorSurface as NamedUniqueOps>::remove(self, &q);
}
for q in record.algorithms {
<AlgorithmSurface as NamedUniqueOps>::remove(self, &q);
}
for q in record.pregels {
<PregelSurface as NamedUniqueOps>::remove(self, &q);
}
for k in record.index_kinds {
<IndexKindSurface as KeyedUniqueOps>::remove(self, &k);
}
for s in record.storage_schemes {
<StorageBackendSurface as KeyedUniqueOps>::remove(self, &s);
}
for l in record.label_storages {
<LabelStorageSurface as KeyedUniqueOps>::remove(self, &l);
}
for k in record.crdt_kinds {
<CrdtSurface as KeyedUniqueOps>::remove(self, &k);
}
for k in record.logical_types {
<LogicalTypeSurface as KeyedUniqueOps>::remove(self, &k);
}
for k in record.collations {
<CollationSurface as KeyedUniqueOps>::remove(self, &k);
}
for k in record.cdc_outputs {
<CdcSurface as KeyedUniqueOps>::remove(self, &k);
}
for k in record.catalogs {
<CatalogSurface as KeyedUniqueOps>::remove(self, &k);
}
<OptimizerRuleSurface as AppendOps>::remove_plugin(self, plugin);
<HookSurface as AppendOps>::remove_plugin(self, plugin);
<AuthSurface as AppendOps>::remove_plugin(self, plugin);
<AuthzSurface as AppendOps>::remove_plugin(self, plugin);
<ConnectorSurface as AppendOps>::remove_plugin(self, plugin);
<TriggerSurface as AppendOps>::remove_plugin(self, plugin);
<ReplacementScanSurface as AppendOps>::remove_plugin(self, plugin);
<BackgroundJobSurface as AppendOps>::remove_plugin(self, plugin);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn registry_default_is_empty() {
let r = PluginRegistry::new();
assert!(r.scalar_fn(&QName::builtin("anything")).is_none());
assert!(r.procedure(&QName::builtin("anything")).is_none());
assert_eq!(r.hooks().len(), 0);
}
#[test]
fn debug_smoke() {
let r = PluginRegistry::new();
let s = format!("{r:?}");
assert!(s.contains("PluginRegistry"));
}
}