Trait Object

Source
pub trait Object:
    Any
    + Clone
    + Eq
    + Send
    + Sync
    + DeepSizeOf
    + for<'a> Deserialize<'a>
    + Serialize {
    type Event: Event;

    // Required methods
    fn type_ulid() -> &'static TypeId;
    fn can_create<'a, C>(
        &'a self,
        user: User,
        self_id: ObjectId,
        db: &'a C,
    ) -> impl Future + 'a
       where C: CanDoCallbacks;
    fn can_apply<'a, C>(
        &'a self,
        user: User,
        self_id: ObjectId,
        event: &'a Self::Event,
        db: &'a C,
    ) -> impl Future + 'a
       where C: CanDoCallbacks;
    fn users_who_can_read<'a, C>(&'a self, db: &'a C) -> impl Future + 'a
       where C: CanDoCallbacks;
    fn apply(&mut self, self_id: DbPtr<Self>, event: &Self::Event);
    fn required_binaries(&self) -> Vec<BinPtr>;

    // Provided methods
    fn snapshot_version() -> i32 { ... }
    fn from_old_snapshot(version: i32, data: Value) -> Result<Self, Error> { ... }
}
Expand description

Note that for this trait to be implemented correctly, the Eq trait should be equivalent to equality of the JSON-serialized representation. In particular, this means that things like [HashMap]s should be banned, and [BTreeMap]s should be preferred.

Note that due to postgresql limitations reasons, this type MUST NOT include any null byte in the serialized JSON. Including them will result in internal server errors.

Required Associated Types§

Source

type Event: Event

Note that due to postgresql limitations reasons, this type MUST NOT include any null byte in the serialized JSON. Trying to submit one such event will result in the event being rejected by the server.

Required Methods§

Source

fn type_ulid() -> &'static TypeId

Source

fn can_create<'a, C>( &'a self, user: User, self_id: ObjectId, db: &'a C, ) -> impl Future + 'a
where C: CanDoCallbacks,

Source

fn can_apply<'a, C>( &'a self, user: User, self_id: ObjectId, event: &'a Self::Event, db: &'a C, ) -> impl Future + 'a
where C: CanDoCallbacks,

Note that permissions are always checked with the latest version of the object on the server. So, due to this, CRDB objects are not strictly speaking a CRDT. However, it is required to do so for security, because otherwise a user who lost permissions would still be allowed to submit events antidated to before the permission loss, which would be bad as users could re-grant themselves permissions.

Source

fn users_who_can_read<'a, C>(&'a self, db: &'a C) -> impl Future + 'a
where C: CanDoCallbacks,

Note that db.get calls will be cached. So:

  • Use db.get as little as possible, to avoid useless cache thrashing

  • Make sure to always read objects in a given order. You should consider all your objects as forming a DAG, and each object’s users_who_can_read function should:

    • Only ever operate on a topological sort of the DAG
    • Only call db.get on objects after this object on the topological sort

    Failing to do this might lead to deadlocks within the database, which will result in internal server errors from postgresql. For example, if you have A -> B -> C and A -> C, A’s users_who_can_read should first call get on B before calling it on C, because otherwise B could be running the same function on C and causing a deadlock. Similarly, if A and B both depend on C and D, then users_who_can_read for A and B should always lock C and D in the same order, to avoid deadlocks.

In other words, you should consider db.get() as taking a lock on the obtained object: there must exist a total order for which the vector, consisting of self and then all the C::get calls in-order, is sorted.

In particular, any recursive call of users_who_can_read is most likely wrong.

Source

fn apply(&mut self, self_id: DbPtr<Self>, event: &Self::Event)

Source

fn required_binaries(&self) -> Vec<BinPtr>

Provided Methods§

Source

fn snapshot_version() -> i32

Source

fn from_old_snapshot(version: i32, data: Value) -> Result<Self, Error>

Parse this object type from an older snapshot version

Note that all metadata, in particular required_binaries and users_who_can_read MUST NOT change with a change in versioning. This method is designed only for changing the on-the-wire representation of an object, not for changing its semantics.

Semantics changes should happen by sending an “upgrade” event to the object, and if cleanup is warranted then performing mass object recreation on the server afterwise.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§