Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/gitpod-db/src/tables.ts
2498 views
1
/**
2
* Copyright (c) 2020 Gitpod GmbH. All rights reserved.
3
* Licensed under the GNU Affero General Public License (AGPL).
4
* See License.AGPL.txt in the project root for license information.
5
*/
6
7
import { injectable } from "inversify";
8
9
export interface TableDependency {
10
table: string;
11
fields: string[];
12
}
13
14
export interface TableDescription {
15
name: string;
16
primaryKeys: string[];
17
timeColumn: string;
18
dependencies?: string[];
19
expiryColumn?: string;
20
deletionColumn?: string;
21
ignoreColumns?: string[];
22
}
23
24
export interface TableDescriptionProvider {
25
readonly name: string;
26
getSortedTables(): TableDescription[];
27
}
28
29
export const TableDescriptionProvider = Symbol("TableDescriptionProvider");
30
31
@injectable()
32
export class GitpodTableDescriptionProvider implements TableDescriptionProvider {
33
readonly name = "gitpod";
34
protected readonly tables: TableDescription[] = [
35
{
36
name: "d_b_workspace_cluster",
37
primaryKeys: ["name"],
38
timeColumn: "_lastModified",
39
deletionColumn: "deleted",
40
},
41
{
42
name: "d_b_volume_snapshot",
43
primaryKeys: ["id"],
44
timeColumn: "_lastModified",
45
deletionColumn: "deleted",
46
},
47
{
48
name: "d_b_blocked_repository",
49
primaryKeys: ["id"],
50
timeColumn: "updatedAt",
51
deletionColumn: "deleted",
52
},
53
{
54
name: "d_b_identity",
55
primaryKeys: ["authProviderId", "authId"],
56
timeColumn: "_lastModified",
57
deletionColumn: "deleted",
58
dependencies: ["d_b_user"],
59
},
60
{
61
name: "d_b_user",
62
primaryKeys: ["id"],
63
timeColumn: "_lastModified",
64
},
65
{
66
name: "d_b_one_time_secret",
67
primaryKeys: ["id"],
68
deletionColumn: "deleted",
69
timeColumn: "_lastModified",
70
},
71
{
72
name: "d_b_team_membership_invite",
73
primaryKeys: ["id"],
74
deletionColumn: "deleted",
75
timeColumn: "_lastModified",
76
},
77
{
78
name: "d_b_project_info",
79
primaryKeys: ["projectId"],
80
deletionColumn: "deleted",
81
timeColumn: "_lastModified",
82
},
83
{
84
name: "d_b_stripe_customer",
85
primaryKeys: ["stripeCustomerId"],
86
timeColumn: "_lastModified",
87
deletionColumn: "deleted",
88
},
89
{
90
name: "d_b_personal_access_token",
91
primaryKeys: ["id"],
92
timeColumn: "_lastModified",
93
deletionColumn: "deleted",
94
},
95
];
96
97
public getSortedTables(): TableDescription[] {
98
return new TopologicalSort<string, TableDescription>().sort(
99
this.tables,
100
(t) => t.name,
101
(t) => (t.dependencies || []).map((e) => this.tables.find((te) => te.name == e)!),
102
);
103
}
104
}
105
106
class TopologicalSort<K, E> {
107
protected result: E[] = [];
108
protected visitedNodes: Map<K, boolean>;
109
110
public sort(values: E[], key: (e: E) => K, edge: (e: E) => E[]): E[] {
111
this.visitedNodes = new Map<K, boolean>();
112
this.result = [];
113
114
for (const e of values) {
115
const k = key(e);
116
const priorVisit = this.visitedNodes.get(k);
117
if (priorVisit === undefined) {
118
this.visit(e, key, edge);
119
}
120
}
121
122
return this.result;
123
}
124
125
protected visit(e: E, key: (e: E) => K, edges: (e: E) => E[]) {
126
if (this.isMarkedPermanently(key(e))) return;
127
if (this.isMarkedTemporarily(key(e))) {
128
throw new Error("Circle detected in " + key);
129
}
130
131
this.visitedNodes.set(key(e), false);
132
edges(e).forEach((edge) => this.visit(edge, key, edges));
133
this.visitedNodes.set(key(e), true);
134
this.result.push(e);
135
}
136
137
protected isMarkedPermanently(k: K) {
138
return this.visitedNodes.get(k) === true;
139
}
140
141
protected isMarkedTemporarily(k: K) {
142
return this.visitedNodes.get(k) === false;
143
}
144
145
protected isUnmarked(k: K) {
146
return this.visitedNodes.get(k) === undefined;
147
}
148
}
149
150