pub struct TupleModelManager<T, S>where
T: GrpcService<Body>,
T::Error: Into<StdError>,
T::ResponseBody: Body<Data = Bytes> + Send + 'static,
<T::ResponseBody as Body>::Error: Into<StdError> + Send,{ /* private fields */ }Expand description
Manages AuthorizationModels in OpenFGA.
Authorization models in OpenFGA don’t receive a unique name. Instead, they receive a random id on creation. If we don’t store this ID, we can’t find the model again and use its ID.
This ModelManager stores the mapping of AuthorizationModelVersion
to the ID of the model in OpenFGA directly inside OpenFGA.
This way can query OpenFGA to determine if a model with a certain version
has already exists.
When running TupleModelManager::migrate(), the manager only applies models and their migrations
if they don’t already exist in OpenFGA.
To store the mapping of model versions to OpenFGA IDs, the following needs to part of your Authorization Model:
type auth_model_id
type model_version
relations
define openfga_id: [auth_model_id]
define exists: [auth_model_id:*]Implementations§
Source§impl<T, S> TupleModelManager<T, S>where
T: GrpcService<Body> + Clone,
T::Error: Into<StdError>,
T::ResponseBody: Body<Data = Bytes> + Send + 'static,
<T::ResponseBody as Body>::Error: Into<StdError> + Send,
S: Clone,
impl<T, S> TupleModelManager<T, S>where
T: GrpcService<Body> + Clone,
T::Error: Into<StdError>,
T::ResponseBody: Body<Data = Bytes> + Send + 'static,
<T::ResponseBody as Body>::Error: Into<StdError> + Send,
S: Clone,
Sourcepub fn new(
client: OpenFgaServiceClient<T>,
store_name: &str,
model_prefix: &str,
) -> Self
pub fn new( client: OpenFgaServiceClient<T>, store_name: &str, model_prefix: &str, ) -> Self
Create a new TupleModelManager with the given client and model name.
The model prefix must not change after the first model has been added or
the model manager will not be able to find the model again.
Use different model prefixes if models for different purposes are stored in the
same OpenFGA store.
Sourcepub fn add_model<FutPre, FutPost>(
self,
model: AuthorizationModel,
version: AuthorizationModelVersion,
pre_migration_fn: Option<impl Fn(OpenFgaServiceClient<T>, Option<String>, Option<String>, S) -> FutPre + Send + 'static>,
post_migration_fn: Option<impl Fn(OpenFgaServiceClient<T>, Option<String>, Option<String>, S) -> FutPost + Send + 'static>,
) -> Self
pub fn add_model<FutPre, FutPost>( self, model: AuthorizationModel, version: AuthorizationModelVersion, pre_migration_fn: Option<impl Fn(OpenFgaServiceClient<T>, Option<String>, Option<String>, S) -> FutPre + Send + 'static>, post_migration_fn: Option<impl Fn(OpenFgaServiceClient<T>, Option<String>, Option<String>, S) -> FutPost + Send + 'static>, ) -> Self
Add a new model to the manager. If a model with the same version has already been added, the new model will replace the old one.
Ensure that migration functions are written in an idempotent way. If a migration fails, it might be retried.
Sourcepub async fn migrate(&mut self, state: S) -> Result<()>
pub async fn migrate(&mut self, state: S) -> Result<()>
Run migrations.
This will:
- Get all existing models in the OpenFGA store.
- Determine which migrations need to be performed: All migrations with a version higher than the highest existing model.
- In order of the version of the model, perform the migrations:
- Run the pre-migration hook if it exists.
- Write the model to OpenFGA.
- Run the post-migration hook if it exists.
- Mark the model as applied in OpenFGA.
§Errors
- If OpenFGA cannot be reached or a request fails.
- If any of the migration hooks fail.
Get the OpenFGA Authorization model ID for the specified model version. Ensure that migrations have been run before calling this method.
§Errors
- If the store with the given name does not exist.
- If a call to OpenFGA fails.
Sourcepub async fn get_existing_versions(
&mut self,
) -> Result<Vec<AuthorizationModelVersion>>
pub async fn get_existing_versions( &mut self, ) -> Result<Vec<AuthorizationModelVersion>>
Get versions of all existing models in OpenFGA. Returns an empty vector if the store does not exist.
§Errors
- If the call to determine existing stores fails.
- If a tuple read call fails.
Trait Implementations§
Source§impl<T, S: Clone> Clone for TupleModelManager<T, S>where
T: GrpcService<Body> + Clone,
T::Error: Into<StdError>,
T::ResponseBody: Body<Data = Bytes> + Send + 'static,
<T::ResponseBody as Body>::Error: Into<StdError> + Send,
impl<T, S: Clone> Clone for TupleModelManager<T, S>where
T: GrpcService<Body> + Clone,
T::Error: Into<StdError>,
T::ResponseBody: Body<Data = Bytes> + Send + 'static,
<T::ResponseBody as Body>::Error: Into<StdError> + Send,
Source§fn clone(&self) -> TupleModelManager<T, S>
fn clone(&self) -> TupleModelManager<T, S>
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl<T, S: Debug> Debug for TupleModelManager<T, S>where
T: GrpcService<Body> + Debug,
T::Error: Into<StdError>,
T::ResponseBody: Body<Data = Bytes> + Send + 'static,
<T::ResponseBody as Body>::Error: Into<StdError> + Send,
impl<T, S: Debug> Debug for TupleModelManager<T, S>where
T: GrpcService<Body> + Debug,
T::Error: Into<StdError>,
T::ResponseBody: Body<Data = Bytes> + Send + 'static,
<T::ResponseBody as Body>::Error: Into<StdError> + Send,
Auto Trait Implementations§
impl<T, S> !Freeze for TupleModelManager<T, S>
impl<T, S> !RefUnwindSafe for TupleModelManager<T, S>
impl<T, S> !Send for TupleModelManager<T, S>
impl<T, S> !Sync for TupleModelManager<T, S>
impl<T, S> Unpin for TupleModelManager<T, S>where
<<T as GrpcService<Body>>::ResponseBody as Body>::Error: Sized,
<T as GrpcService<Body>>::Error: Sized,
T: Unpin,
impl<T, S> !UnwindSafe for TupleModelManager<T, S>
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
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request