Skip to content
This repository has been archived by the owner on Jun 3, 2024. It is now read-only.

feat: getDependenciesOfCollection #17

Merged
merged 5 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "payload-dependency-graph",
"version": "2.1.1",
"version": "2.2.0",
"repository": "[email protected]:GeorgeHulpoi/payload-dependency-graph.git",
"homepage": "https://georgehulpoi.github.io/payload-dependency-graph",
"description": "This plugin creates a dependency graph between collections and globals. The graph updates automatically, because the plugin observes the changes made on any collection or globals.",
Expand Down
10 changes: 10 additions & 0 deletions src/dependency-graph/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,16 @@ export abstract class DependencyGraphBase {
collection: string,
): boolean | Promise<boolean>;

/**
* Get dependencies of `resource` that is of `collection`
* @param resource
* @param collection
*/
abstract getDependenciesOfCollection(
resource: DependencyGraphResource,
collection: string,
): DependencyGraphResource[] | Promise<DependencyGraphResource[]>;

/**
* Used at Payload initialization to populate the dependency graph.
* You shouldn't call this function by yourself.
Expand Down
54 changes: 54 additions & 0 deletions src/dependency-graph/in-memory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
DependencyGraphNode,
DependencyGraphResource,
} from '../types';
import { DependencyGraphResourceSet } from '../utils/set';
import { DependencyGraphBase } from './base';

export class InMemoryDependencyGraph extends DependencyGraphBase {
Expand Down Expand Up @@ -198,4 +199,57 @@ export class InMemoryDependencyGraph extends DependencyGraphBase {

return false;
}

getDependenciesOfCollection(
resource: DependencyGraphResource,
collection: string,
): DependencyGraphResource[] {
const resources = this.getDependenciesOfCollectionRecursive(resource, collection);
const set = new DependencyGraphResourceSet(resources);
return Array.from(set);
}

private getDependenciesOfCollectionRecursive(
resource: DependencyGraphResource,
collection: string,
direction?: boolean,
): DependencyGraphResource[] {
if (resource.collection === collection) {
return [resource];
}

const node = this.getDependencyGraphNode(resource);

if (node === undefined) {
return [];
}

const items: DependencyGraphResource[] = [];

if (direction === false || direction === undefined) {
items.push(
...node.dependencyFor.reduce(
(result: DependencyGraphResource[], r: DependencyGraphResource) => [
...result,
...this.getDependenciesOfCollectionRecursive(r, collection, false),
],
[],
),
);
}

if (direction === true || direction === undefined) {
items.push(
...node.dependentOn.reduce(
(result: DependencyGraphResource[], r: DependencyGraphResource) => [
...result,
...this.getDependenciesOfCollectionRecursive(r, collection, true),
],
[],
),
);
}

return items;
}
}
102 changes: 102 additions & 0 deletions src/dependency-graph/mongodb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { Types } from 'mongoose';

import type { DependencyGraphResource } from '../types';
import { DependencyGraphBase } from './base';
import { DependencyGraphResourceSet } from '../utils/set';

export class MongoDBDependencyGraph extends DependencyGraphBase {
async deleteResource(resource: DependencyGraphResource): Promise<void> {
Expand Down Expand Up @@ -198,6 +199,107 @@ export class MongoDBDependencyGraph extends DependencyGraphBase {
});
}

getDependenciesOfCollection(
resource: DependencyGraphResource,
collection: string,
): Promise<DependencyGraphResource[]> {
const dependencyFor$ = this.collection
.aggregate([
{
$match: resource,
},
{
$graphLookup: {
from: '_dependency_graph',
startWith: '$dependencyFor',
connectFromField: 'dependencyFor',
connectToField: '_id',
as: 'result',
},
},
{
$unwind: {
path: '$result',
},
},
{
$replaceRoot: {
newRoot: '$result',
},
},
{
$match: {
collection,
},
},
{
$project: {
_id: 1,
id: 1,
collection: 1,
},
},
])
.toArray()
.then((docs) => {
return docs.map((doc) => ({
id: doc.id,
collection: doc.collection,
}));
});

const dependentOn$ = this.collection
.aggregate([
{
$match: resource,
},
{
$graphLookup: {
from: '_dependency_graph',
startWith: '$dependentOn',
connectFromField: 'dependentOn',
connectToField: '_id',
as: 'result',
},
},
{
$unwind: {
path: '$result',
},
},
{
$replaceRoot: {
newRoot: '$result',
},
},
{
$match: {
collection,
},
},
{
$project: {
_id: 1,
id: 1,
collection: 1,
},
},
])
.toArray()
.then((docs) => {
return docs.map((doc) => ({
id: doc.id,
collection: doc.collection,
}));
});

return Promise.all([dependencyFor$, dependentOn$]).then(([docs1, docs2]) => {
const set = new DependencyGraphResourceSet(docs1);
docs2.forEach((r) => set.add(r));
return Array.from(set);
});
}

/**
* Get collection and if doesn't exist, it will create it
*/
Expand Down
10 changes: 8 additions & 2 deletions src/utils/set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,18 @@ import type { DependencyGraphResource } from '../types';
export class DependencyGraphResourceSet {
private readonly _map: Map<string, DependencyGraphResource>;

constructor(iterable?: DependencyGraphResourceSet) {
if (iterable) {
constructor(iterable?: DependencyGraphResourceSet | DependencyGraphResource[]) {
if (iterable && iterable instanceof DependencyGraphResourceSet) {
this._map = new Map(iterable._map);
} else {
this._map = new Map();
}

if (iterable && !(iterable instanceof DependencyGraphResourceSet)) {
for (const r of iterable) {
this.add(r);
}
}
}

/**
Expand Down
7 changes: 7 additions & 0 deletions tests/dependency-graph/base.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ class DummyDependencyGraph extends DependencyGraphBase {
): boolean {
return true;
}

getDependenciesOfCollection(
resource: DependencyGraphResource,
collection: string,
): DependencyGraphResource[] {
return [];
}
}

describe('DependencyGraphBase', () => {
Expand Down
22 changes: 22 additions & 0 deletions tests/dependency-graph/in-memory/in-memory-e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,28 @@ describe('InMemoryDependencyGraph e2e', () => {
});
});

it('getDependenciesOfCollection should return right resources', () => {
const deps = graph.getDependenciesOfCollection(
{
id: 'dog_charlie',
collection: 'dogs',
},
'pages',
);

expect(deps).toContainEqual({
collection: 'pages',
id: 'home',
});

expect(deps).toContainEqual({
collection: 'pages',
id: 'dogs_page',
});

expect(deps).toHaveLength(2);
});

it('should add resource in graph', async () => {
callback.mockReset();

Expand Down
22 changes: 22 additions & 0 deletions tests/dependency-graph/mongodb/mongodb.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,28 @@ describe('MongoDBDependencyGraph', () => {
});
});

it('getDependenciesOfCollection should return right resources', async () => {
const deps = await dependencyGraph.getDependenciesOfCollection(
{
id: 'dog_charlie',
collection: 'dogs',
},
'pages',
);

expect(deps).toContainEqual({
collection: 'pages',
id: 'home',
});

expect(deps).toContainEqual({
collection: 'pages',
id: 'dogs_page',
});

expect(deps).toHaveLength(2);
});

it('should add resource in graph', async () => {
callback.mockReset();

Expand Down
Loading
Loading