nocobase/packages/core/utils/src/collections-graph.ts
ChengLei Shao ca95edf295
refactor: multi-app (#1578)
* feat: compact theme

* fix: theme

* fix: styling

* fix: margin

* feat: improve

* fix: remove console.log

* test: enable plugin test

* refactor: multi app

* test: lazy load sync plugin

* test: lazy load test

* fix: beforeGetApplication Event

* feat: loadFromDatabase options in traverseSubApps

* fix: test

* fix: multi app manager test

* chore: test

* test: should upgrade sub apps when main app upgrade

* feat: plugin require check

* chore: yarn.lock

* fix: sql typo

* feat: share collections

* fix: record name

* test: belongs to many repository

* fix: belongs to many with targetKey alias

* fix: extend collection error

* fix: transaction error

* feat: collection graph

* fix: update options in collection

* chore: collections graph

* chore: export uitls

* feat: connected nodes method in collections graph

* feat: exclude params in connected nodes

* chore: sub app collection list params

* fix: collections graph

* feat: syncToApps migration

* fix:  translation

---------

Co-authored-by: chenos <chenlinxh@gmail.com>
2023-03-19 23:40:42 +08:00

78 lines
2.3 KiB
TypeScript

import * as graphlib from 'graphlib';
import { castArray } from 'lodash';
type BuildGraphOptions = {
direction?: 'forward' | 'reverse';
collections: any[];
};
export class CollectionsGraph {
static graphlib() {
return graphlib;
}
static connectedNodes(options: BuildGraphOptions & { nodes: Array<string>; excludes?: Array<string> }) {
const nodes = castArray(options.nodes);
const excludes = castArray(options.excludes || []);
const graph = CollectionsGraph.build(options);
const connectedNodes = new Set();
for (const node of nodes) {
const connected = graphlib.alg.preorder(graph, node);
for (const connectedNode of connected) {
if (excludes.includes(connectedNode)) continue;
connectedNodes.add(connectedNode);
}
}
return Array.from(connectedNodes);
}
static preOrder(options: BuildGraphOptions & { node: string }) {
return CollectionsGraph.graphlib().alg.preorder(CollectionsGraph.build(options), options.node);
}
static build(options: BuildGraphOptions) {
const collections = options.collections;
const direction = options?.direction || 'forward';
const isForward = direction === 'forward';
const graph = new graphlib.Graph();
for (const collection of collections) {
graph.setNode(collection.name);
}
for (const collection of collections) {
const parents = collection.inherits || [];
for (const parent of parents) {
if (isForward) {
graph.setEdge(collection.name, parent);
} else {
graph.setEdge(parent, collection.name);
}
}
for (const field of collection.fields || []) {
if (field.type === 'hasMany' || field.type === 'belongsTo' || field.type === 'hasOne') {
isForward ? graph.setEdge(collection.name, field.target) : graph.setEdge(field.target, collection.name);
}
if (field.type === 'belongsToMany') {
const throughCollection = field.through;
if (isForward) {
graph.setEdge(collection.name, throughCollection);
graph.setEdge(throughCollection, field.target);
} else {
graph.setEdge(field.target, throughCollection);
graph.setEdge(throughCollection, collection.name);
}
}
}
}
return graph;
}
}