0.1.12 • Published 15 days ago

whatwhywhenandwho-orca v0.1.12

Weekly downloads
-
License
-
Repository
-
Last release
15 days ago

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:

  1. Open the console.
  2. Go to Master realm.
  3. Clients > admin-cli.
  4. Service Account Roles.
  5. Client Roles > your realm.
  6. Add manage-users, and view-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:

  1. This saves us a ton of custom logic. So if possible, always go with CRQL.
  2. There's no limitation as to how deep the connection can go.
  3. There's no formatting limitations. In other words, use any amount of white spaces you need to make it more readable.
  4. 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.

  1. 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:

  1. This saves us a ton of custom logic. So if possible, always go with this.
  2. There's no formatting limitations. In other words, use any amount of white spaces you need to make it more readable.
  3. The only thing to be careful about really, is to always query indexed fields to keep everything as performant as possible.

  4. 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 😘