revisium 2.0.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +32 -0
- package/README.md +23 -3
- package/dist/e2e/setup/global-setup.js +2 -3
- package/dist/e2e/setup/global-setup.js.map +1 -1
- package/dist/e2e/setup/global-teardown.js +0 -2
- package/dist/e2e/setup/global-teardown.js.map +1 -1
- package/dist/e2e/utils/constants.d.ts +0 -2
- package/dist/e2e/utils/constants.js +0 -2
- package/dist/e2e/utils/constants.js.map +1 -1
- package/dist/e2e/utils/docker-helper.d.ts +0 -2
- package/dist/e2e/utils/docker-helper.js +0 -13
- package/dist/e2e/utils/docker-helper.js.map +1 -1
- package/dist/package.json +27 -14
- package/dist/src/commands/migration/apply-migrations.command.d.ts +1 -1
- package/dist/src/commands/migration/apply-migrations.command.js +4 -5
- package/dist/src/commands/migration/apply-migrations.command.js.map +1 -1
- package/dist/src/commands/migration/save-migrations.command.d.ts +1 -1
- package/dist/src/commands/migration/save-migrations.command.js +6 -6
- package/dist/src/commands/migration/save-migrations.command.js.map +1 -1
- package/dist/src/commands/rows/save-rows.command.d.ts +1 -1
- package/dist/src/commands/rows/save-rows.command.js +12 -10
- package/dist/src/commands/rows/save-rows.command.js.map +1 -1
- package/dist/src/commands/rows/upload-rows.command.d.ts +1 -1
- package/dist/src/commands/rows/upload-rows.command.js +12 -15
- package/dist/src/commands/rows/upload-rows.command.js.map +1 -1
- package/dist/src/commands/schema/create-migrations.command.js.map +1 -1
- package/dist/src/commands/schema/save-schema.command.d.ts +1 -1
- package/dist/src/commands/schema/save-schema.command.js +7 -7
- package/dist/src/commands/schema/save-schema.command.js.map +1 -1
- package/dist/src/config/meta-schema.d.ts +3 -0
- package/dist/src/config/meta-schema.js +43 -1
- package/dist/src/config/meta-schema.js.map +1 -1
- package/dist/src/services/connection/api-client-adapter.d.ts +2 -4
- package/dist/src/services/connection/api-client-adapter.js +40 -36
- package/dist/src/services/connection/api-client-adapter.js.map +1 -1
- package/dist/src/services/connection/api-client.d.ts +3 -4
- package/dist/src/services/connection/api-client.js +11 -33
- package/dist/src/services/connection/api-client.js.map +1 -1
- package/dist/src/services/connection/connection-factory.service.d.ts +4 -6
- package/dist/src/services/connection/connection-factory.service.js +18 -39
- package/dist/src/services/connection/connection-factory.service.js.map +1 -1
- package/dist/src/services/connection/connection.service.d.ts +2 -73
- package/dist/src/services/connection/connection.service.js +2 -11
- package/dist/src/services/connection/connection.service.js.map +1 -1
- package/dist/src/services/sync/commit-revision.service.js +6 -28
- package/dist/src/services/sync/commit-revision.service.js.map +1 -1
- package/dist/src/services/sync/row-sync.service.d.ts +5 -5
- package/dist/src/services/sync/row-sync.service.js +10 -10
- package/dist/src/services/sync/row-sync.service.js.map +1 -1
- package/dist/src/services/sync/sync-data.service.d.ts +1 -0
- package/dist/src/services/sync/sync-data.service.js +21 -21
- package/dist/src/services/sync/sync-data.service.js.map +1 -1
- package/dist/src/services/sync/sync-schema.service.d.ts +1 -0
- package/dist/src/services/sync/sync-schema.service.js +11 -10
- package/dist/src/services/sync/sync-schema.service.js.map +1 -1
- package/dist/src/services/url/auth-prompt.service.js +1 -1
- package/dist/src/services/url/auth-prompt.service.js.map +1 -1
- package/dist/src/types/migration.types.d.ts +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/docs/authentication.md +3 -3
- package/docs/configuration.md +58 -9
- package/docs/docker-deployment.md +48 -13
- package/docs/migrate-commands.md +35 -10
- package/docs/rows-commands.md +30 -7
- package/docs/schema-commands.md +21 -5
- package/docs/sync-commands.md +44 -12
- package/docs/url-format.md +2 -2
- package/e2e/setup/global-setup.ts +3 -9
- package/e2e/setup/global-teardown.ts +0 -6
- package/e2e/utils/constants.ts +0 -2
- package/e2e/utils/docker-helper.ts +0 -23
- package/package.json +27 -14
- package/src/commands/migration/apply-migrations.command.ts +5 -6
- package/src/commands/migration/save-migrations.command.ts +7 -6
- package/src/commands/rows/save-rows.command.ts +14 -28
- package/src/commands/rows/upload-rows.command.ts +7 -15
- package/src/commands/schema/create-migrations.command.ts +1 -1
- package/src/commands/schema/save-schema.command.ts +9 -14
- package/src/config/meta-schema.ts +47 -0
- package/src/services/connection/__tests__/connection-factory.service.spec.ts +117 -0
- package/src/services/connection/__tests__/connection.service.spec.ts +27 -117
- package/src/services/connection/api-client-adapter.ts +41 -45
- package/src/services/connection/api-client.ts +11 -50
- package/src/services/connection/connection-factory.service.ts +35 -65
- package/src/services/connection/connection.service.ts +3 -14
- package/src/services/sync/__tests__/row-sync.service.spec.ts +3 -6
- package/src/services/sync/commit-revision.service.ts +7 -51
- package/src/services/sync/row-sync.service.ts +4 -18
- package/src/services/sync/sync-data.service.ts +32 -45
- package/src/services/sync/sync-schema.service.ts +14 -22
- package/src/services/url/auth-prompt.service.ts +1 -1
- package/src/types/migration.types.ts +2 -2
- package/dist/src/__generated__/api.d.ts +0 -688
- package/dist/src/__generated__/api.js +0 -698
- package/dist/src/__generated__/api.js.map +0 -1
- package/e2e/docker-compose.e2e.yml +0 -31
- package/src/__generated__/api.ts +0 -2598
|
@@ -61,26 +61,8 @@ describe('ConnectionService', () => {
|
|
|
61
61
|
);
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
-
it('throws error when accessing
|
|
65
|
-
expect(() => service.
|
|
66
|
-
'Connection not established. Call connect() first.',
|
|
67
|
-
);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('throws error when accessing revisionId before connect', () => {
|
|
71
|
-
expect(() => service.revisionId).toThrow(
|
|
72
|
-
'Connection not established. Call connect() first.',
|
|
73
|
-
);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('throws error when accessing draftRevisionId before connect', () => {
|
|
77
|
-
expect(() => service.draftRevisionId).toThrow(
|
|
78
|
-
'Connection not established. Call connect() first.',
|
|
79
|
-
);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('throws error when accessing headRevisionId before connect', () => {
|
|
83
|
-
expect(() => service.headRevisionId).toThrow(
|
|
64
|
+
it('throws error when accessing revisionScope before connect', () => {
|
|
65
|
+
expect(() => service.revisionScope).toThrow(
|
|
84
66
|
'Connection not established. Call connect() first.',
|
|
85
67
|
);
|
|
86
68
|
});
|
|
@@ -179,114 +161,42 @@ describe('ConnectionService', () => {
|
|
|
179
161
|
});
|
|
180
162
|
});
|
|
181
163
|
|
|
182
|
-
describe('revision resolution', () => {
|
|
183
|
-
it('uses draft revision when revision is draft', async () => {
|
|
184
|
-
const url = { ...mockUrl, revision: 'draft' };
|
|
185
|
-
setupSuccessfulConnection(url, {
|
|
186
|
-
headId: 'head-123',
|
|
187
|
-
draftId: 'draft-456',
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
await service.connect();
|
|
191
|
-
|
|
192
|
-
expect(service.revisionId).toBe('draft-456');
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
it('uses head revision when revision is head', async () => {
|
|
196
|
-
const url = { ...mockUrl, revision: 'head' };
|
|
197
|
-
setupSuccessfulConnection(url, {
|
|
198
|
-
headId: 'head-123',
|
|
199
|
-
draftId: 'draft-456',
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
await service.connect();
|
|
203
|
-
|
|
204
|
-
expect(service.revisionId).toBe('head-123');
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
it('uses specific revision ID when provided', async () => {
|
|
208
|
-
const url = { ...mockUrl, revision: 'specific-rev-id' };
|
|
209
|
-
setupSuccessfulConnection(url, {
|
|
210
|
-
headId: 'head-123',
|
|
211
|
-
draftId: 'draft-456',
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
await service.connect();
|
|
215
|
-
|
|
216
|
-
expect(service.revisionId).toBe('specific-rev-id');
|
|
217
|
-
});
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
describe('connection properties after connect', () => {
|
|
221
|
-
it('provides access to headRevisionId', async () => {
|
|
222
|
-
setupSuccessfulConnection(mockUrl, {
|
|
223
|
-
headId: 'test-head-id',
|
|
224
|
-
draftId: 'test-draft-id',
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
await service.connect();
|
|
228
|
-
|
|
229
|
-
expect(service.headRevisionId).toBe('test-head-id');
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
it('provides access to draftRevisionId', async () => {
|
|
233
|
-
setupSuccessfulConnection(mockUrl, {
|
|
234
|
-
headId: 'test-head-id',
|
|
235
|
-
draftId: 'test-draft-id',
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
await service.connect();
|
|
239
|
-
|
|
240
|
-
expect(service.draftRevisionId).toBe('test-draft-id');
|
|
241
|
-
});
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
function setupSuccessfulConnection(
|
|
245
|
-
url: RevisiumUrlComplete,
|
|
246
|
-
revisions: { headId: string; draftId: string },
|
|
247
|
-
) {
|
|
248
|
-
urlBuilderServiceFake.parseAndComplete.mockResolvedValue(url);
|
|
249
|
-
|
|
250
|
-
const resolveRevisionId = (): string => {
|
|
251
|
-
if (url.revision === 'head') {
|
|
252
|
-
return revisions.headId;
|
|
253
|
-
}
|
|
254
|
-
if (url.revision === 'draft') {
|
|
255
|
-
return revisions.draftId;
|
|
256
|
-
}
|
|
257
|
-
return url.revision;
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
connectionFactoryFake.createConnection.mockResolvedValue({
|
|
261
|
-
url,
|
|
262
|
-
client: createMockApiClient(),
|
|
263
|
-
revisionId: resolveRevisionId(),
|
|
264
|
-
headRevisionId: revisions.headId,
|
|
265
|
-
draftRevisionId: revisions.draftId,
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
|
|
269
164
|
function createMockConnectionInfo(url: RevisiumUrlComplete) {
|
|
270
165
|
return {
|
|
271
166
|
url,
|
|
272
167
|
client: createMockApiClient(),
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
draftRevisionId: 'draft-id',
|
|
168
|
+
branchScope: createMockBranchScope(),
|
|
169
|
+
revisionScope: createMockRevisionScope(),
|
|
276
170
|
};
|
|
277
171
|
}
|
|
278
172
|
|
|
279
173
|
function createMockApiClient() {
|
|
280
174
|
return {
|
|
281
|
-
|
|
282
|
-
me: jest.fn().mockResolvedValue({
|
|
283
|
-
|
|
284
|
-
headRevision: jest.fn().mockResolvedValue({ data: { id: 'head-id' } }),
|
|
285
|
-
draftRevision: jest
|
|
286
|
-
.fn()
|
|
287
|
-
.mockResolvedValue({ data: { id: 'draft-id' } }),
|
|
175
|
+
client: {
|
|
176
|
+
me: jest.fn().mockResolvedValue({ username: 'test-user' }),
|
|
177
|
+
branch: jest.fn(),
|
|
288
178
|
},
|
|
289
179
|
authenticate: jest.fn().mockResolvedValue('test-user'),
|
|
290
180
|
};
|
|
291
181
|
}
|
|
182
|
+
|
|
183
|
+
function createMockBranchScope() {
|
|
184
|
+
return {
|
|
185
|
+
draft: jest.fn(),
|
|
186
|
+
head: jest.fn(),
|
|
187
|
+
headRevisionId: 'head-id',
|
|
188
|
+
draftRevisionId: 'draft-id',
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function createMockRevisionScope() {
|
|
193
|
+
return {
|
|
194
|
+
getTables: jest.fn(),
|
|
195
|
+
getRows: jest.fn(),
|
|
196
|
+
getMigrations: jest.fn(),
|
|
197
|
+
commit: jest.fn(),
|
|
198
|
+
revisionId: 'draft-id',
|
|
199
|
+
isDraft: true,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
292
202
|
});
|
|
@@ -1,58 +1,54 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RevisionScope } from '@revisium/client';
|
|
2
2
|
import { ApiClient } from '../sync/row-sync.service';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
export function createApiClientAdapter(
|
|
5
|
+
revisionScope: RevisionScope,
|
|
6
|
+
): ApiClient {
|
|
7
7
|
return {
|
|
8
|
-
async rows(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
hasNextPage: result.data.pageInfo.hasNextPage,
|
|
26
|
-
endCursor: result.data.pageInfo.endCursor ?? '',
|
|
8
|
+
async rows(tableId, options) {
|
|
9
|
+
try {
|
|
10
|
+
const data = await revisionScope.getRows(tableId, {
|
|
11
|
+
first: options.first,
|
|
12
|
+
after: options.after,
|
|
13
|
+
orderBy: options.orderBy,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
data: {
|
|
18
|
+
edges: data.edges.map((e) => ({
|
|
19
|
+
node: { id: e.node.id, data: e.node.data },
|
|
20
|
+
})),
|
|
21
|
+
pageInfo: {
|
|
22
|
+
hasNextPage: data.pageInfo.hasNextPage,
|
|
23
|
+
endCursor: data.pageInfo.endCursor ?? '',
|
|
24
|
+
},
|
|
27
25
|
},
|
|
28
|
-
}
|
|
29
|
-
}
|
|
26
|
+
};
|
|
27
|
+
} catch (error) {
|
|
28
|
+
return { error };
|
|
29
|
+
}
|
|
30
30
|
},
|
|
31
31
|
|
|
32
|
-
async createRows(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return { error
|
|
32
|
+
async createRows(tableId, data) {
|
|
33
|
+
try {
|
|
34
|
+
await revisionScope.createRows(tableId, data.rows, {
|
|
35
|
+
isRestore: data.isRestore,
|
|
36
|
+
});
|
|
37
|
+
return { data: true };
|
|
38
|
+
} catch (error) {
|
|
39
|
+
return { error };
|
|
40
40
|
}
|
|
41
|
-
|
|
42
|
-
return { data: result.data };
|
|
43
41
|
},
|
|
44
42
|
|
|
45
|
-
async updateRows(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return { error
|
|
43
|
+
async updateRows(tableId, data) {
|
|
44
|
+
try {
|
|
45
|
+
await revisionScope.updateRows(tableId, data.rows, {
|
|
46
|
+
isRestore: data.isRestore,
|
|
47
|
+
});
|
|
48
|
+
return { data: true };
|
|
49
|
+
} catch (error) {
|
|
50
|
+
return { error };
|
|
53
51
|
}
|
|
54
|
-
|
|
55
|
-
return { data: result.data };
|
|
56
52
|
},
|
|
57
53
|
};
|
|
58
54
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RevisiumClient } from '@revisium/client';
|
|
2
2
|
import { AuthCredentials } from '../url';
|
|
3
3
|
|
|
4
|
-
export class RevisiumApiClient
|
|
5
|
-
public
|
|
4
|
+
export class RevisiumApiClient {
|
|
5
|
+
public readonly client: RevisiumClient;
|
|
6
6
|
|
|
7
7
|
constructor(baseUrl: string) {
|
|
8
|
-
|
|
8
|
+
this.client = new RevisiumClient({ baseUrl });
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
public async authenticate(auth: AuthCredentials): Promise<string> {
|
|
@@ -32,61 +32,22 @@ export class RevisiumApiClient extends Api<unknown> {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
private async authenticateWithToken(token: string): Promise<string> {
|
|
35
|
-
this.
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
if (response.error) {
|
|
39
|
-
throw new Error(
|
|
40
|
-
`Token validation failed: ${JSON.stringify(response.error)}`,
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return response.data.username || 'authenticated user';
|
|
35
|
+
this.client.loginWithToken(token);
|
|
36
|
+
const me = await this.client.me();
|
|
37
|
+
return me.username || 'authenticated user';
|
|
45
38
|
}
|
|
46
39
|
|
|
47
40
|
private async authenticateWithApiKey(apikey: string): Promise<string> {
|
|
48
|
-
this.
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
if (response.error) {
|
|
52
|
-
throw new Error(
|
|
53
|
-
`API key validation failed: ${JSON.stringify(response.error)}`,
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return response.data.username || 'authenticated user';
|
|
41
|
+
this.client.loginWithToken(apikey);
|
|
42
|
+
const me = await this.client.me();
|
|
43
|
+
return me.username || 'authenticated user';
|
|
58
44
|
}
|
|
59
45
|
|
|
60
46
|
private async authenticateWithPassword(
|
|
61
47
|
username: string,
|
|
62
48
|
password: string,
|
|
63
49
|
): Promise<string> {
|
|
64
|
-
|
|
65
|
-
emailOrUsername: username,
|
|
66
|
-
password: password,
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
if (response.error) {
|
|
70
|
-
throw new Error(`Login failed: ${JSON.stringify(response.error)}`);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
this.authToken = response.data.accessToken;
|
|
50
|
+
await this.client.login(username, password);
|
|
74
51
|
return username;
|
|
75
52
|
}
|
|
76
|
-
|
|
77
|
-
protected mergeRequestParams(
|
|
78
|
-
params1: RequestParams,
|
|
79
|
-
params2?: RequestParams,
|
|
80
|
-
): RequestParams {
|
|
81
|
-
const params = super.mergeRequestParams(params1, params2);
|
|
82
|
-
|
|
83
|
-
params.headers ??= {};
|
|
84
|
-
|
|
85
|
-
if (this.authToken) {
|
|
86
|
-
(params.headers as Record<string, string>)['Authorization'] =
|
|
87
|
-
`Bearer ${this.authToken}`;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return params;
|
|
91
|
-
}
|
|
92
53
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import { BranchScope, RevisionScope } from '@revisium/client';
|
|
2
3
|
import { RevisiumApiClient } from './api-client';
|
|
3
4
|
import { LoggerService } from '../common';
|
|
4
5
|
import { RevisiumUrlComplete, UrlBuilderService } from '../url';
|
|
@@ -6,9 +7,8 @@ import { RevisiumUrlComplete, UrlBuilderService } from '../url';
|
|
|
6
7
|
export interface ConnectionInfo {
|
|
7
8
|
url: RevisiumUrlComplete;
|
|
8
9
|
client: RevisiumApiClient;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
draftRevisionId: string;
|
|
10
|
+
branchScope: BranchScope;
|
|
11
|
+
revisionScope: RevisionScope;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export interface ConnectOptions {
|
|
@@ -32,11 +32,24 @@ export class ConnectionFactoryService {
|
|
|
32
32
|
this.logger.connecting(label, formattedUrl);
|
|
33
33
|
|
|
34
34
|
const client = await this.createAuthenticatedClient(url);
|
|
35
|
-
await this.validateProject(client, url);
|
|
36
|
-
const revisions = await this.fetchRevisions(client, url);
|
|
37
35
|
|
|
38
|
-
const
|
|
39
|
-
|
|
36
|
+
const branchScope = await client.client.branch({
|
|
37
|
+
org: url.organization,
|
|
38
|
+
project: url.project,
|
|
39
|
+
branch: url.branch || 'master',
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const revisionScope = await this.resolveRevisionScope(
|
|
43
|
+
url.revision,
|
|
44
|
+
branchScope,
|
|
45
|
+
);
|
|
46
|
+
const revisionId = revisionScope.revisionId;
|
|
47
|
+
const revisionLabel = this.formatRevisionLabel(
|
|
48
|
+
url.revision,
|
|
49
|
+
branchScope.headRevisionId,
|
|
50
|
+
branchScope.draftRevisionId,
|
|
51
|
+
revisionId,
|
|
52
|
+
);
|
|
40
53
|
|
|
41
54
|
this.logger.connected(
|
|
42
55
|
`Project: ${url.organization}/${url.project}, Branch: ${url.branch || 'master'}, Revision: ${revisionLabel}`,
|
|
@@ -45,9 +58,8 @@ export class ConnectionFactoryService {
|
|
|
45
58
|
return {
|
|
46
59
|
url,
|
|
47
60
|
client,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
draftRevisionId: revisions.draftRevisionId,
|
|
61
|
+
branchScope,
|
|
62
|
+
revisionScope,
|
|
51
63
|
};
|
|
52
64
|
}
|
|
53
65
|
|
|
@@ -62,64 +74,24 @@ export class ConnectionFactoryService {
|
|
|
62
74
|
return client;
|
|
63
75
|
}
|
|
64
76
|
|
|
65
|
-
private async
|
|
66
|
-
client: RevisiumApiClient,
|
|
67
|
-
url: RevisiumUrlComplete,
|
|
68
|
-
): Promise<void> {
|
|
69
|
-
const response = await client.api.project(url.organization, url.project);
|
|
70
|
-
|
|
71
|
-
if (response.error) {
|
|
72
|
-
throw new Error(
|
|
73
|
-
`Failed to get project: ${JSON.stringify(response.error)}`,
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
private async fetchRevisions(
|
|
79
|
-
client: RevisiumApiClient,
|
|
80
|
-
url: RevisiumUrlComplete,
|
|
81
|
-
): Promise<{ headRevisionId: string; draftRevisionId: string }> {
|
|
82
|
-
const branchName = url.branch || 'master';
|
|
83
|
-
|
|
84
|
-
const [headResponse, draftResponse] = await Promise.all([
|
|
85
|
-
client.api.headRevision(url.organization, url.project, branchName),
|
|
86
|
-
client.api.draftRevision(url.organization, url.project, branchName),
|
|
87
|
-
]);
|
|
88
|
-
|
|
89
|
-
if (headResponse.error) {
|
|
90
|
-
throw new Error(
|
|
91
|
-
`Failed to get head revision: ${JSON.stringify(headResponse.error)}`,
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (draftResponse.error) {
|
|
96
|
-
throw new Error(
|
|
97
|
-
`Failed to get draft revision: ${JSON.stringify(draftResponse.error)}`,
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return {
|
|
102
|
-
headRevisionId: headResponse.data.id,
|
|
103
|
-
draftRevisionId: draftResponse.data.id,
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
private resolveRevisionId(
|
|
77
|
+
private async resolveRevisionScope(
|
|
108
78
|
revision: string,
|
|
109
|
-
|
|
110
|
-
):
|
|
111
|
-
if (revision === 'head') {
|
|
112
|
-
return revisions.headRevisionId;
|
|
113
|
-
}
|
|
79
|
+
branchScope: BranchScope,
|
|
80
|
+
): Promise<RevisionScope> {
|
|
114
81
|
if (revision === 'draft') {
|
|
115
|
-
return
|
|
82
|
+
return branchScope.draft();
|
|
116
83
|
}
|
|
117
|
-
|
|
84
|
+
if (revision === 'head') {
|
|
85
|
+
return branchScope.head();
|
|
86
|
+
}
|
|
87
|
+
return branchScope.revision(revision);
|
|
118
88
|
}
|
|
119
89
|
|
|
120
90
|
private formatRevisionLabel(
|
|
121
91
|
revision: string,
|
|
122
|
-
|
|
92
|
+
headRevisionId: string,
|
|
93
|
+
draftRevisionId: string,
|
|
94
|
+
resolvedId: string,
|
|
123
95
|
): string {
|
|
124
96
|
if (revision === 'head') {
|
|
125
97
|
return 'head';
|
|
@@ -128,12 +100,10 @@ export class ConnectionFactoryService {
|
|
|
128
100
|
return 'draft';
|
|
129
101
|
}
|
|
130
102
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (resolvedId === revisions.headRevisionId) {
|
|
103
|
+
if (resolvedId === headRevisionId) {
|
|
134
104
|
return `${resolvedId} (head)`;
|
|
135
105
|
}
|
|
136
|
-
if (resolvedId ===
|
|
106
|
+
if (resolvedId === draftRevisionId) {
|
|
137
107
|
return `${resolvedId} (draft)`;
|
|
138
108
|
}
|
|
139
109
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Injectable } from '@nestjs/common';
|
|
2
2
|
import { ConfigService } from '@nestjs/config';
|
|
3
|
+
import { RevisionScope } from '@revisium/client';
|
|
3
4
|
import {
|
|
4
5
|
ConnectionFactoryService,
|
|
5
6
|
ConnectionInfo,
|
|
@@ -29,20 +30,8 @@ export class ConnectionService {
|
|
|
29
30
|
return this._connection;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
public get
|
|
33
|
-
return this.connection.
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
public get revisionId(): string {
|
|
37
|
-
return this.connection.revisionId;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
public get draftRevisionId(): string {
|
|
41
|
-
return this.connection.draftRevisionId;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
public get headRevisionId(): string {
|
|
45
|
-
return this.connection.headRevisionId;
|
|
33
|
+
public get revisionScope(): RevisionScope {
|
|
34
|
+
return this.connection.revisionScope;
|
|
46
35
|
}
|
|
47
36
|
|
|
48
37
|
public async connect(options: ConnectionOptions = {}): Promise<void> {
|
|
@@ -97,7 +97,7 @@ describe('RowSyncService', () => {
|
|
|
97
97
|
updateRows: jest.fn(),
|
|
98
98
|
};
|
|
99
99
|
|
|
100
|
-
const result = await service.getExistingRows(mockApi, '
|
|
100
|
+
const result = await service.getExistingRows(mockApi, 'table1');
|
|
101
101
|
|
|
102
102
|
expect(result.size).toBe(3);
|
|
103
103
|
expect(result.get('row1')).toEqual({ name: 'A' });
|
|
@@ -113,7 +113,7 @@ describe('RowSyncService', () => {
|
|
|
113
113
|
updateRows: jest.fn(),
|
|
114
114
|
};
|
|
115
115
|
|
|
116
|
-
const result = await service.getExistingRows(mockApi, '
|
|
116
|
+
const result = await service.getExistingRows(mockApi, 'table1');
|
|
117
117
|
|
|
118
118
|
expect(result.size).toBe(0);
|
|
119
119
|
});
|
|
@@ -131,7 +131,7 @@ describe('RowSyncService', () => {
|
|
|
131
131
|
};
|
|
132
132
|
const onProgress = jest.fn();
|
|
133
133
|
|
|
134
|
-
await service.getExistingRows(mockApi, '
|
|
134
|
+
await service.getExistingRows(mockApi, 'table1', onProgress);
|
|
135
135
|
|
|
136
136
|
expect(onProgress).toHaveBeenCalledWith({
|
|
137
137
|
operation: 'fetch',
|
|
@@ -160,7 +160,6 @@ describe('RowSyncService', () => {
|
|
|
160
160
|
|
|
161
161
|
const stats = await service.syncTableRows(
|
|
162
162
|
mockApi,
|
|
163
|
-
'rev1',
|
|
164
163
|
'table1',
|
|
165
164
|
sourceRows,
|
|
166
165
|
100,
|
|
@@ -188,7 +187,6 @@ describe('RowSyncService', () => {
|
|
|
188
187
|
|
|
189
188
|
const stats = await service.syncTableRows(
|
|
190
189
|
mockApi,
|
|
191
|
-
'rev1',
|
|
192
190
|
'table1',
|
|
193
191
|
sourceRows,
|
|
194
192
|
100,
|
|
@@ -217,7 +215,6 @@ describe('RowSyncService', () => {
|
|
|
217
215
|
|
|
218
216
|
const stats = await service.syncTableRows(
|
|
219
217
|
mockApi,
|
|
220
|
-
'rev1',
|
|
221
218
|
'table1',
|
|
222
219
|
sourceRows,
|
|
223
220
|
100,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import { RevisionScope } from '@revisium/client';
|
|
2
3
|
import { ConnectionInfo as SyncConnectionInfo } from './sync-api.service';
|
|
3
4
|
import { ConnectionService } from '../connection';
|
|
4
5
|
import { LoggerService } from '../common';
|
|
@@ -7,20 +8,6 @@ export interface CommitResult {
|
|
|
7
8
|
revisionId: string;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
interface CommitParams {
|
|
11
|
-
organization: string;
|
|
12
|
-
project: string;
|
|
13
|
-
branch: string;
|
|
14
|
-
api: {
|
|
15
|
-
createRevision: (
|
|
16
|
-
org: string,
|
|
17
|
-
proj: string,
|
|
18
|
-
branch: string,
|
|
19
|
-
data: { comment: string },
|
|
20
|
-
) => Promise<{ data?: { id: string }; error?: unknown }>;
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
|
|
24
11
|
@Injectable()
|
|
25
12
|
export class CommitRevisionService {
|
|
26
13
|
constructor(
|
|
@@ -34,12 +21,7 @@ export class CommitRevisionService {
|
|
|
34
21
|
): Promise<CommitResult> {
|
|
35
22
|
const connection = this.connectionService.connection;
|
|
36
23
|
return this.doCommit(
|
|
37
|
-
|
|
38
|
-
organization: connection.url.organization,
|
|
39
|
-
project: connection.url.project,
|
|
40
|
-
branch: connection.url.branch,
|
|
41
|
-
api: connection.client.api,
|
|
42
|
-
},
|
|
24
|
+
connection.revisionScope,
|
|
43
25
|
actionDescription,
|
|
44
26
|
changeCount,
|
|
45
27
|
);
|
|
@@ -69,19 +51,14 @@ export class CommitRevisionService {
|
|
|
69
51
|
}
|
|
70
52
|
|
|
71
53
|
await this.doCommit(
|
|
72
|
-
|
|
73
|
-
organization: connection.url.organization,
|
|
74
|
-
project: connection.url.project,
|
|
75
|
-
branch: connection.url.branch,
|
|
76
|
-
api: connection.client.api,
|
|
77
|
-
},
|
|
54
|
+
connection.revisionScope,
|
|
78
55
|
actionDescription,
|
|
79
56
|
changeCount,
|
|
80
57
|
);
|
|
81
58
|
}
|
|
82
59
|
|
|
83
60
|
private async doCommit(
|
|
84
|
-
|
|
61
|
+
revisionScope: RevisionScope,
|
|
85
62
|
actionDescription: string,
|
|
86
63
|
changeCount: number,
|
|
87
64
|
): Promise<CommitResult> {
|
|
@@ -89,37 +66,16 @@ export class CommitRevisionService {
|
|
|
89
66
|
|
|
90
67
|
const comment = this.generateCommitComment(actionDescription, changeCount);
|
|
91
68
|
|
|
92
|
-
let result: { data?: { id: string }; error?: unknown };
|
|
93
69
|
try {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
params.branch,
|
|
98
|
-
{ comment },
|
|
99
|
-
);
|
|
70
|
+
const revision = await revisionScope.commit(comment);
|
|
71
|
+
this.logger.commitSuccess(revision.id);
|
|
72
|
+
return { revisionId: revision.id };
|
|
100
73
|
} catch (error) {
|
|
101
74
|
const errorMessage =
|
|
102
75
|
error instanceof Error ? error.message : String(error);
|
|
103
76
|
this.logger.commitError(errorMessage);
|
|
104
77
|
throw error;
|
|
105
78
|
}
|
|
106
|
-
|
|
107
|
-
if (result.error) {
|
|
108
|
-
const errorMessage =
|
|
109
|
-
typeof result.error === 'string'
|
|
110
|
-
? result.error
|
|
111
|
-
: JSON.stringify(result.error);
|
|
112
|
-
this.logger.commitError(errorMessage);
|
|
113
|
-
throw new Error(errorMessage);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (result.data) {
|
|
117
|
-
this.logger.commitSuccess(result.data.id);
|
|
118
|
-
return { revisionId: result.data.id };
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
this.logger.commitError('No data returned');
|
|
122
|
-
throw new Error('Failed to create revision');
|
|
123
79
|
}
|
|
124
80
|
|
|
125
81
|
private generateCommitComment(
|