{"id":19932707,"url":"https://github.com/mixmaxhq/projection-utils","last_synced_at":"2025-05-03T11:32:42.456Z","repository":{"id":43148184,"uuid":"140327242","full_name":"mixmaxhq/projection-utils","owner":"mixmaxhq","description":"Utilities to work with projections (e.g. mongo)","archived":false,"fork":false,"pushed_at":"2023-11-28T16:10:31.000Z","size":191,"stargazers_count":3,"open_issues_count":2,"forks_count":0,"subscribers_count":25,"default_branch":"master","last_synced_at":"2024-09-19T15:18:27.593Z","etag":null,"topics":["corgi-tag"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mixmaxhq.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-07-09T18:33:54.000Z","updated_at":"2023-07-12T23:36:11.000Z","dependencies_parsed_at":"2023-11-28T17:30:41.684Z","dependency_job_id":"b8e31a21-1016-42eb-9615-8dbf8dd0fa87","html_url":"https://github.com/mixmaxhq/projection-utils","commit_stats":{"total_commits":9,"total_committers":3,"mean_commits":3.0,"dds":0.4444444444444444,"last_synced_commit":"d58586c8e5de91870428da227b538e818b0ea7bb"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mixmaxhq%2Fprojection-utils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mixmaxhq%2Fprojection-utils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mixmaxhq%2Fprojection-utils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mixmaxhq%2Fprojection-utils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mixmaxhq","download_url":"https://codeload.github.com/mixmaxhq/projection-utils/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224000803,"owners_count":17239000,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["corgi-tag"],"created_at":"2024-11-12T23:11:17.746Z","updated_at":"2024-11-12T23:11:18.211Z","avatar_url":"https://github.com/mixmaxhq.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"projection-utils\n================\n\nA set of utilities for working with MongoDB-style projections.\n\nNotably, this project exposes a `ProjectionFieldSet` class that tracks, merges,\nand intersects multi-level projections.\n\nWe do not support symmetric or asymmetric diffing of field sets, as the\nsemantics are not well-defined on mongo projections. A field set that contains\n`users` minus a field set that contains `users.accessToken` would need new\nsyntax to represent the fields under `users` that aren't `accessToken`, or would\nneed knowledge of all existant fields under the `users` subdocument. It's better\nto handle this yourself, using `intersect`, and a whitelist of permitted fields.\n\n### `ProjectionFieldSet`\n\nBasic usage:\n\n```js\nconst permittedFields = ProjectionFieldSet.fromDotted(\n  ['users.id', 'users.email', 'share', 'content']);\n\nconst desiredFields = ProjectionFieldSet.fromDotted(\n  ['users', 'users.accessToken', 'share', 'invalid']);\n\n// The fields we want, where they're permitted.\nconst selectedFields = permittedFields.intersect(desiredFields);\n\n// Add fields that we need for server-side business logic.\nconst mandatoryFields = ProjectionFieldSet.fromDotted(\n  ['internalVersion']);\n\nconst queryFields = selectedFields.union(mandatoryFields);\nconst projection = queryFields.toMongo();\n// =\u003e {'users.id': 1, 'users.email': 1, share: 1, internalVersion: 1}\n```\n\nConstructor usage:\n\n```js\n// Equivalent to the first fromDotted invocation in the previous example.\nconst permittedFields = new ProjectionFieldSet([\n  ['users', 'id'],\n  ['users', 'email'],\n  ['share'],\n  ['content'],\n]);\n```\n\nIterate over paths:\n\n```js\nfor (const path of permittedFields) {\n  // path is the array containing the parts of the path, e.g.:\n  // ['users', 'email']\n}\n\n// Or just convert to an Array:\nconst fields = Array.from(permittedFields);\n```\n\nEnumerate dot-joined paths:\n\n```js\nconst dotJoined = Array.from(queryFields.toDotted());\n// =\u003e ['users.id', 'users.email', 'share', 'internalVersion']\n```\n\nCheck for field containment, and partial field containment:\n\n```js\nqueryFields.contains(['users']);\n// =\u003e false, because only some of the fields in users are included\n\n// equivalent to the above\nqueryFields.containsDotted('users');\n\n// produces the set of fields that are included under the users field\nArray.from(queryFields.get(['users']));\n// =\u003e [['users', 'id'], ['users', 'email']]\n\nArray.from(queryFields.getDotted('users'));\n// =\u003e ['users.id', 'users.email']\n\n// both produce no items\nArray.from(queryFields.get(['invalid']));\nArray.from(queryFields.getDotted('invalid'));\n// =\u003e []\n\n// exclude the users prefix\nArray.from(queryFields.get('users', false));\n// =\u003e [['id'], ['email']]\n\nArray.from(queryFields.getDotted('users', false));\n// =\u003e ['id', 'email']\n```\n\nExplicitly expand the set of fields:\n\n```js\n// Add users.name to queryFields. Unlike intersect and union, this mutates the\n// ProjectionFieldSet instead of making a new instance.\nqueryFields.widen(['users', 'name']);\nqueryFields.toMongo();\n// =\u003e {'users.id': 1, 'users.email': 1, 'users.name': 1, share: 1, internalVersion: 1}\n\n// Expand queryFields to include all fields of users (even accessToken - take\n// care when ordering operations on ProjectionFieldSets, as an intersect won't\n// forbid a set of fields being added to the produced ProjectionFieldSet.\nqueryFields.widen(['users']);\nqueryFields.toMongo();\n// =\u003e {users: 1, share: 1, internalVersion: 1}\n```\n\nNote that field sets can be singular. Unioning with a singular value yields a\nsingular value, and intersecting with a singular value yields the non-singular\nvalue. For example:\n\n```js\n// This is distinct from new ProjectionFieldSet([]) (and\n// new ProjectionFieldSet()), which yield an empty fieldset, rather than a\n// singular fieldset.\nconst singular = new ProjectionFieldSet([[]]);\n\nsingular.union(singular);\n// =\u003e copy of singular\n\nsingular.intersect(singular);\n// =\u003e copy of singular\n\nsingular.union(mandatoryFields);\n// =\u003e copy of singular\n\nsingular.intersect(mandatoryFields);\n// =\u003e copy of mandatoryFields\n\nconst empty = new ProjectionFieldSet([]);\n\nempty.union(empty);\n// =\u003e copy of empty\n\nempty.intersect(empty);\n// =\u003e copy of empty\n\nempty.union(mandatoryFields);\n// =\u003e copy of mandatoryFields\n\nempty.intersect(mandatoryFields);\n// =\u003e copy of empty\n\n\nsingular.union(empty);\n// =\u003e copy of singular\n\nsingular.intersect(empty);\n// =\u003e copy of empty\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmixmaxhq%2Fprojection-utils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmixmaxhq%2Fprojection-utils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmixmaxhq%2Fprojection-utils/lists"}