whatwhywhenandwho-orca v0.1.12
orca
MongoDB Replica Set
In case it doesn't want to start, you have to look for every process running on that port:
sudo lsof -i :27017
And kill it:
kill -9 <processid>
Or restart your machine 🙂
Environment Variables
ORCA_APPLICATION_NAME=string
ORCA_APPLICATION_VERSION=string (SemVer)
ORCA_PATH=string (orca path)
ORCA_APPLICATION_PATH=string (application running orca path)
ORCA_PORT=number
ORCA_CORS=string
ORCA_CLIENT_URL=string
WebSockets
Edge Case: Sending deletion and/or creation signals on update
This happens when entity gets updated, but is considered deleted due to a failed check.
Consider the following example of an arbitrary entity, that defines user access to it via the access
array:
{
deleted: false,
access: [{
userId: '<uuid>',
deleted: false
}]
}
Consider flipping the only access
child's deleted
to true
. From the user's perspective, the top level entity doesn't exist anymore, so we send a deleted signal.
Later, the entity gets updated again, flipping the only access
child's deleted
back to false
. From the user's perspective, the top level entity exist again, however, we cannot know this in WebSocketServer
, because there might be no subscription. To address this, we also send all the creation signals.
Keycloak
Client needs an External ID
mapper to connect to orca.
In case any user query fails, see https://www.appsdeveloperblog.com/keycloak-rest-api-create-a-new-user.
Also:
- Open the console.
- Go to
Master
realm. Clients
>admin-cli
.Service Account Roles
.Client Roles
> your realm.- Add
manage-users
, andview-users
.
Mongoose Chained Reference Query Language (CRQL)
CRQL was developed to be used internally for the purpose of easily resolving chained references. Initially it was developed to serve orcaForeignConstraints
, but was later generalised and is now being used in multiple places.
We always start with 1 to any amount of context documents which we call zeroth documents. We can take any path on these documents and traverse through an unlimited amount of references through any amount of data models to reach the final destination:
AssociatedDataModel1(zerothPath).path->AssociatedDataModel2(firstPath).path->AssociatedDataModel3(secondPath).path->third.path
Or a little bit easier to read:
AssociatedDataModel1(zerothPath).path
->AssociatedDataModel2(firstPath).path
->AssociatedDataModel3(secondPath).path
->third.path
For example, consider we have a document with projectId
. This document also contains a value with userId
. We can take userId
and reference it via a project and workspace user roles, to make sure the document belongs to a project that belongs to a workspace that this user can access:
Project(@projectId)._id
->Workspace(@workspaceId)._id
->userRoles.userId
Note that at (@
) references global/top level fields in case of sub documents. In the final step, we can reference multiple paths by separating them with a comma (,
):
Project(@projectId)._id
->Workspace(@workspaceId)._id
->userRoles.userId,something.else,and.also.this
A few things to consider:
- This saves us a ton of custom logic. So if possible, always go with CRQL.
- There's no limitation as to how deep the connection can go.
- There's no formatting limitations. In other words, use any amount of white spaces you need to make it more readable.
- The only thing to be careful about really, is to always query indexed fields to keep everything as performant as possible.
Mongoose Data Schema Plugins
orcaForeignConstraints
Note: this is only implemented on the top level schema to optimise the amount of queries. Duplicates are ignored.
Checks for reference existence. Doesn't include deleted documents.
There are two seemingly different types, which work the same way under the hood.
- Direct
Used to check one model. It requires a model and one or more paths:
Model.path1[,path2,path3]
For example, if we want to reference a user, we can do:
User._id
We're not limited to primary keys. We can use any path:
User.email
Mind the word path, meaning we can also do:
User.path.to.a.nested.field
Or multiple paths:
User.path.to.a.nested.field,path.to.another.nested.field,path.to.yet.another.nested.field
A few things to consider:
- This saves us a ton of custom logic. So if possible, always go with this.
- There's no formatting limitations. In other words, use any amount of white spaces you need to make it more readable.
The only thing to be careful about really, is to always query indexed fields to keep everything as performant as possible.
Indirect
See CRQL.
orcaLimitByReference
Note: this is only implemented on the top level schema to optimise the amount of queries.
Limits the field value(s) by reference. Consider the following schema:
{
confirmedMemberUserIds: {
type: [
uuid
]
},
invitedEmails: {
type: [
string
],
orcaLimitByReference: 'User(confirmedMemberUserIds)._id->email'
}
}
This is a relatively complicated scenario. On one hand, we have user IDs, and on the other, emails. Things that are impossible to compare directly. With the given query of User(confirmedMemberUserIds)._id->email
, we can check if within confirmedMemberUserIds
already exists a user with one of the emails provided in invitedEmails
, and prevent it. This way we cannot invite a user that is already a member.
orcaUniqueArraySubDocument
Checks for uniqueness of the given keys. Doesn't include deleted records.
orcaLock
Locks the given keys. Includes deleted documents.
Have a nice day 😘
15 days ago
15 days ago
16 days ago
16 days ago
17 days ago
17 days ago
17 days ago
17 days ago
17 days ago
17 days ago
17 days ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago