https://github.com/mixmaxhq/projection-utils
Utilities to work with projections (e.g. mongo)
https://github.com/mixmaxhq/projection-utils
corgi-tag
Last synced: 19 days ago
JSON representation
Utilities to work with projections (e.g. mongo)
- Host: GitHub
- URL: https://github.com/mixmaxhq/projection-utils
- Owner: mixmaxhq
- License: mit
- Created: 2018-07-09T18:33:54.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2023-11-28T16:10:31.000Z (over 1 year ago)
- Last Synced: 2024-09-19T15:18:27.593Z (8 months ago)
- Topics: corgi-tag
- Language: JavaScript
- Size: 187 KB
- Stars: 3
- Watchers: 25
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
projection-utils
================A set of utilities for working with MongoDB-style projections.
Notably, this project exposes a `ProjectionFieldSet` class that tracks, merges,
and intersects multi-level projections.We do not support symmetric or asymmetric diffing of field sets, as the
semantics are not well-defined on mongo projections. A field set that contains
`users` minus a field set that contains `users.accessToken` would need new
syntax to represent the fields under `users` that aren't `accessToken`, or would
need knowledge of all existant fields under the `users` subdocument. It's better
to handle this yourself, using `intersect`, and a whitelist of permitted fields.### `ProjectionFieldSet`
Basic usage:
```js
const permittedFields = ProjectionFieldSet.fromDotted(
['users.id', 'users.email', 'share', 'content']);const desiredFields = ProjectionFieldSet.fromDotted(
['users', 'users.accessToken', 'share', 'invalid']);// The fields we want, where they're permitted.
const selectedFields = permittedFields.intersect(desiredFields);// Add fields that we need for server-side business logic.
const mandatoryFields = ProjectionFieldSet.fromDotted(
['internalVersion']);const queryFields = selectedFields.union(mandatoryFields);
const projection = queryFields.toMongo();
// => {'users.id': 1, 'users.email': 1, share: 1, internalVersion: 1}
```Constructor usage:
```js
// Equivalent to the first fromDotted invocation in the previous example.
const permittedFields = new ProjectionFieldSet([
['users', 'id'],
['users', 'email'],
['share'],
['content'],
]);
```Iterate over paths:
```js
for (const path of permittedFields) {
// path is the array containing the parts of the path, e.g.:
// ['users', 'email']
}// Or just convert to an Array:
const fields = Array.from(permittedFields);
```Enumerate dot-joined paths:
```js
const dotJoined = Array.from(queryFields.toDotted());
// => ['users.id', 'users.email', 'share', 'internalVersion']
```Check for field containment, and partial field containment:
```js
queryFields.contains(['users']);
// => false, because only some of the fields in users are included// equivalent to the above
queryFields.containsDotted('users');// produces the set of fields that are included under the users field
Array.from(queryFields.get(['users']));
// => [['users', 'id'], ['users', 'email']]Array.from(queryFields.getDotted('users'));
// => ['users.id', 'users.email']// both produce no items
Array.from(queryFields.get(['invalid']));
Array.from(queryFields.getDotted('invalid'));
// => []// exclude the users prefix
Array.from(queryFields.get('users', false));
// => [['id'], ['email']]Array.from(queryFields.getDotted('users', false));
// => ['id', 'email']
```Explicitly expand the set of fields:
```js
// Add users.name to queryFields. Unlike intersect and union, this mutates the
// ProjectionFieldSet instead of making a new instance.
queryFields.widen(['users', 'name']);
queryFields.toMongo();
// => {'users.id': 1, 'users.email': 1, 'users.name': 1, share: 1, internalVersion: 1}// Expand queryFields to include all fields of users (even accessToken - take
// care when ordering operations on ProjectionFieldSets, as an intersect won't
// forbid a set of fields being added to the produced ProjectionFieldSet.
queryFields.widen(['users']);
queryFields.toMongo();
// => {users: 1, share: 1, internalVersion: 1}
```Note that field sets can be singular. Unioning with a singular value yields a
singular value, and intersecting with a singular value yields the non-singular
value. For example:```js
// This is distinct from new ProjectionFieldSet([]) (and
// new ProjectionFieldSet()), which yield an empty fieldset, rather than a
// singular fieldset.
const singular = new ProjectionFieldSet([[]]);singular.union(singular);
// => copy of singularsingular.intersect(singular);
// => copy of singularsingular.union(mandatoryFields);
// => copy of singularsingular.intersect(mandatoryFields);
// => copy of mandatoryFieldsconst empty = new ProjectionFieldSet([]);
empty.union(empty);
// => copy of emptyempty.intersect(empty);
// => copy of emptyempty.union(mandatoryFields);
// => copy of mandatoryFieldsempty.intersect(mandatoryFields);
// => copy of emptysingular.union(empty);
// => copy of singularsingular.intersect(empty);
// => copy of empty
```