@stryker-mutator/dashboard-data-access 0.14.4-pr-822.16 → 0.15.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.
@@ -1,5 +1,5 @@
1
1
  import { ModelClass } from './ModelClass.js';
2
- import { TableQuery } from 'azure-storage';
2
+ import { TableEntityQueryOptions } from '@azure/data-tables';
3
3
  export declare class DashboardQuery<TModel, TPartitionKeyFields extends keyof TModel, TRowKeyFields extends keyof TModel> {
4
4
  protected ModelClass: ModelClass<TModel, TPartitionKeyFields, TRowKeyFields>;
5
5
  private readonly whereConditions;
@@ -7,6 +7,6 @@ export declare class DashboardQuery<TModel, TPartitionKeyFields extends keyof TM
7
7
  whereRowKeyNotEquals(rowKey: Pick<TModel, TRowKeyFields>): DashboardQuery<TModel, TPartitionKeyFields, TRowKeyFields>;
8
8
  wherePartitionKeyEquals(partitionKey: Pick<TModel, TPartitionKeyFields>): DashboardQuery<TModel, TPartitionKeyFields, TRowKeyFields>;
9
9
  static create<TModel, TPartitionKeyFields extends keyof TModel, TRowKeyFields extends keyof TModel>(ModelClass: ModelClass<TModel, TPartitionKeyFields, TRowKeyFields>): DashboardQuery<TModel, TPartitionKeyFields, TRowKeyFields>;
10
- build(): TableQuery;
10
+ build(): TableEntityQueryOptions;
11
11
  }
12
12
  //# sourceMappingURL=DashboardQuery.d.ts.map
@@ -1,22 +1,16 @@
1
- import { TableQuery } from 'azure-storage';
2
1
  import { encodeKey } from '../utils.js';
2
+ import { odata } from '@azure/data-tables';
3
3
  export class DashboardQuery {
4
4
  constructor(ModelClass, whereConditions) {
5
5
  this.ModelClass = ModelClass;
6
6
  this.whereConditions = whereConditions;
7
7
  }
8
8
  whereRowKeyNotEquals(rowKey) {
9
- const whereCondition = {
10
- condition: 'not(RowKey eq ?)',
11
- params: [encodeKey(this.ModelClass.createRowKey(rowKey) || '')],
12
- };
9
+ const whereCondition = odata `RowKey ne ${encodeKey(this.ModelClass.createRowKey(rowKey) || '')}`;
13
10
  return new DashboardQuery(this.ModelClass, [...this.whereConditions, whereCondition]);
14
11
  }
15
12
  wherePartitionKeyEquals(partitionKey) {
16
- const whereCondition = {
17
- condition: 'PartitionKey eq ?',
18
- params: [encodeKey(this.ModelClass.createPartitionKey(partitionKey))],
19
- };
13
+ const whereCondition = odata `PartitionKey eq ${encodeKey(this.ModelClass.createPartitionKey(partitionKey))}`;
20
14
  return new DashboardQuery(this.ModelClass, [...this.whereConditions, whereCondition]);
21
15
  }
22
16
  static create(ModelClass) {
@@ -25,12 +19,12 @@ export class DashboardQuery {
25
19
  build() {
26
20
  return this.whereConditions.reduce((tableQuery, whereCondition, index) => {
27
21
  if (index === 0) {
28
- return tableQuery.where(whereCondition.condition, ...whereCondition.params);
22
+ return { filter: whereCondition };
29
23
  }
30
24
  else {
31
- return tableQuery.and(whereCondition.condition, whereCondition.params);
25
+ return { filter: `${tableQuery.filter} and ${whereCondition}` };
32
26
  }
33
- }, new TableQuery());
27
+ }, {});
34
28
  }
35
29
  }
36
30
  //# sourceMappingURL=DashboardQuery.js.map
@@ -1,15 +1,14 @@
1
- import { BlobServiceAsPromised } from '../services/BlobServiceAsPromised.js';
2
- import { BlobService } from 'azure-storage';
3
1
  import * as schema from 'mutation-testing-report-schema';
4
2
  import { ReportIdentifier } from '@stryker-mutator/dashboard-common';
3
+ import { BlobServiceClient, ContainerCreateIfNotExistsResponse } from '@azure/storage-blob';
5
4
  /**
6
5
  * The report json part of a mutation testing report is stored in blob storage
7
6
  */
8
7
  export declare class MutationTestingResultMapper {
9
- private readonly blobService;
8
+ #private;
10
9
  private static readonly CONTAINER_NAME;
11
- constructor(blobService?: BlobServiceAsPromised);
12
- createStorageIfNotExists(): Promise<BlobService.ContainerResult>;
10
+ constructor(blobService?: BlobServiceClient);
11
+ createStorageIfNotExists(): Promise<ContainerCreateIfNotExistsResponse>;
13
12
  insertOrReplace(id: ReportIdentifier, result: schema.MutationTestResult | null): Promise<void>;
14
13
  findOne(identifier: ReportIdentifier): Promise<schema.MutationTestResult | null>;
15
14
  delete(id: ReportIdentifier): Promise<void>;
@@ -1,31 +1,46 @@
1
- import { BlobServiceAsPromised } from '../services/BlobServiceAsPromised.js';
2
- import { Constants } from 'azure-storage';
3
- import { isStorageError, toBlobName } from '../utils.js';
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _MutationTestingResultMapper_containerClient;
13
+ import { hasErrorCode, toBlobName } from '../utils.js';
4
14
  import { OptimisticConcurrencyError } from '../errors/index.js';
5
- const additionalErrorCodes = Object.freeze({
15
+ import { createBlobServiceClient } from '../services/BlobServiceClient.js';
16
+ const errCodes = Object.freeze({
6
17
  BLOB_HAS_BEEN_MODIFIED: 'BlobHasBeenModified',
18
+ BLOB_NOT_FOUND: 'BlobNotFound',
7
19
  });
8
20
  /**
9
21
  * The report json part of a mutation testing report is stored in blob storage
10
22
  */
11
23
  export class MutationTestingResultMapper {
12
- constructor(blobService = new BlobServiceAsPromised()) {
13
- this.blobService = blobService;
24
+ constructor(blobService = createBlobServiceClient()) {
25
+ _MutationTestingResultMapper_containerClient.set(this, void 0);
26
+ __classPrivateFieldSet(this, _MutationTestingResultMapper_containerClient, blobService.getContainerClient(MutationTestingResultMapper.CONTAINER_NAME), "f");
14
27
  }
15
28
  createStorageIfNotExists() {
16
- return this.blobService.createContainerIfNotExists(MutationTestingResultMapper.CONTAINER_NAME, {});
29
+ return __classPrivateFieldGet(this, _MutationTestingResultMapper_containerClient, "f").createIfNotExists({});
17
30
  }
18
31
  async insertOrReplace(id, result) {
19
32
  try {
20
- await this.blobService.createBlockBlobFromText(MutationTestingResultMapper.CONTAINER_NAME, toBlobName(id), JSON.stringify(result), {
21
- contentSettings: {
22
- contentType: 'application/json',
23
- contentEncoding: 'utf8',
33
+ await __classPrivateFieldGet(this, _MutationTestingResultMapper_containerClient, "f")
34
+ .getBlockBlobClient(toBlobName(id))
35
+ .uploadData(Buffer.from(JSON.stringify(result), 'utf-8'), {
36
+ blobHTTPHeaders: {
37
+ blobContentType: 'application/json',
38
+ blobContentEncoding: 'utf8',
24
39
  },
25
40
  });
26
41
  }
27
42
  catch (err) {
28
- if (isStorageError(err) && err.code === additionalErrorCodes.BLOB_HAS_BEEN_MODIFIED) {
43
+ if (hasErrorCode(err, errCodes.BLOB_HAS_BEEN_MODIFIED)) {
29
44
  throw new OptimisticConcurrencyError(`Blob "${JSON.stringify(id)}" was modified by another process`);
30
45
  }
31
46
  else {
@@ -36,11 +51,11 @@ export class MutationTestingResultMapper {
36
51
  async findOne(identifier) {
37
52
  const blobName = toBlobName(identifier);
38
53
  try {
39
- const result = JSON.parse(await this.blobService.blobToText(MutationTestingResultMapper.CONTAINER_NAME, blobName));
54
+ const result = JSON.parse((await __classPrivateFieldGet(this, _MutationTestingResultMapper_containerClient, "f").getBlockBlobClient(blobName).downloadToBuffer()).toString('utf-8'));
40
55
  return result;
41
56
  }
42
57
  catch (error) {
43
- if (isStorageError(error) && error.code === Constants.BlobErrorCodeStrings.BLOB_NOT_FOUND) {
58
+ if (hasErrorCode(error, errCodes.BLOB_NOT_FOUND)) {
44
59
  return null;
45
60
  }
46
61
  else {
@@ -51,8 +66,9 @@ export class MutationTestingResultMapper {
51
66
  }
52
67
  async delete(id) {
53
68
  const blobName = toBlobName(id);
54
- await this.blobService.deleteBlobIfExists(MutationTestingResultMapper.CONTAINER_NAME, blobName);
69
+ await __classPrivateFieldGet(this, _MutationTestingResultMapper_containerClient, "f").getBlockBlobClient(blobName).deleteIfExists();
55
70
  }
56
71
  }
72
+ _MutationTestingResultMapper_containerClient = new WeakMap();
57
73
  MutationTestingResultMapper.CONTAINER_NAME = 'mutation-testing-report';
58
74
  //# sourceMappingURL=MutationTestingResultMapper.js.map
@@ -1,11 +1,11 @@
1
- import TableServiceAsPromised from '../services/TableServiceAsPromised.js';
2
1
  import { Mapper, Result } from './Mapper.js';
3
2
  import { ModelClass } from './ModelClass.js';
4
3
  import { DashboardQuery } from './DashboardQuery.js';
4
+ import { TableClient } from '@azure/data-tables';
5
5
  export default class TableStorageMapper<TModel extends object, TPartitionKeyFields extends keyof TModel, TRowKeyFields extends keyof TModel> implements Mapper<TModel, TPartitionKeyFields, TRowKeyFields> {
6
+ #private;
6
7
  private readonly ModelClass;
7
- private readonly tableService;
8
- constructor(ModelClass: ModelClass<TModel, TPartitionKeyFields, TRowKeyFields>, tableService?: TableServiceAsPromised);
8
+ constructor(ModelClass: ModelClass<TModel, TPartitionKeyFields, TRowKeyFields>, tableClient?: TableClient);
9
9
  createStorageIfNotExists(): Promise<void>;
10
10
  insertOrMerge(model: TModel): Promise<void>;
11
11
  findOne(identity: Pick<TModel, TPartitionKeyFields | TRowKeyFields>): Promise<Result<TModel> | null>;
@@ -1,28 +1,51 @@
1
- import { Constants } from 'azure-storage';
2
- import TableServiceAsPromised from '../services/TableServiceAsPromised.js';
3
- import { encodeKey, decodeKey, isStorageError } from '../utils.js';
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var __asyncValues = (this && this.__asyncValues) || function (o) {
13
+ if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
14
+ var m = o[Symbol.asyncIterator], i;
15
+ return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
16
+ function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
17
+ function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
18
+ };
19
+ var _TableStorageMapper_tableClient;
20
+ import { encodeKey, decodeKey, hasErrorCode } from '../utils.js';
4
21
  import { OptimisticConcurrencyError } from '../errors/index.js';
5
22
  import { DashboardQuery } from './DashboardQuery.js';
6
- export default class TableStorageMapper {
7
- constructor(ModelClass, tableService = new TableServiceAsPromised()) {
23
+ import { createTableClient } from '../services/TableClient.js';
24
+ const errCodes = Object.freeze({
25
+ UPDATE_CONDITION_NOT_SATISFIED: 'UpdateConditionNotSatisfied',
26
+ ENTITY_ALREADY_EXISTS: 'EntityAlreadyExists',
27
+ RESOURCE_NOT_FOUND: 'ResourceNotFound',
28
+ });
29
+ class TableStorageMapper {
30
+ constructor(ModelClass, tableClient = createTableClient(ModelClass.name)) {
8
31
  this.ModelClass = ModelClass;
9
- this.tableService = tableService;
32
+ _TableStorageMapper_tableClient.set(this, void 0);
33
+ __classPrivateFieldSet(this, _TableStorageMapper_tableClient, tableClient, "f");
10
34
  }
11
35
  async createStorageIfNotExists() {
12
- await this.tableService.createTableIfNotExists(this.ModelClass.tableName);
36
+ await __classPrivateFieldGet(this, _TableStorageMapper_tableClient, "f").createTable();
13
37
  }
14
38
  async insertOrMerge(model) {
15
39
  const entity = this.toEntity(model);
16
- await this.tableService.insertOrMergeEntity(this.ModelClass.tableName, entity);
40
+ await __classPrivateFieldGet(this, _TableStorageMapper_tableClient, "f").upsertEntity(entity, 'Merge');
17
41
  }
18
42
  async findOne(identity) {
19
43
  try {
20
- const result = await this.tableService.retrieveEntity(this.ModelClass.tableName, encodeKey(this.ModelClass.createPartitionKey(identity)), encodeKey(this.ModelClass.createRowKey(identity) || ''));
44
+ const result = await __classPrivateFieldGet(this, _TableStorageMapper_tableClient, "f").getEntity(encodeKey(this.ModelClass.createPartitionKey(identity)), encodeKey(this.ModelClass.createRowKey(identity) || ''));
21
45
  return this.toModel(result);
22
46
  }
23
47
  catch (err) {
24
- if (isStorageError(err) &&
25
- err.code === Constants.StorageErrorCodeStrings.RESOURCE_NOT_FOUND) {
48
+ if (hasErrorCode(err, errCodes.RESOURCE_NOT_FOUND)) {
26
49
  return null;
27
50
  }
28
51
  else {
@@ -32,9 +55,26 @@ export default class TableStorageMapper {
32
55
  }
33
56
  }
34
57
  async findAll(query = DashboardQuery.create(this.ModelClass)) {
58
+ var _a, e_1, _b, _c;
35
59
  const tableQuery = query.build();
36
- const results = await this.tableService.queryEntities(this.ModelClass.tableName, tableQuery, undefined);
37
- return results.entries.map((entity) => this.toModel(entity));
60
+ const entities = __classPrivateFieldGet(this, _TableStorageMapper_tableClient, "f").listEntities({ queryOptions: tableQuery });
61
+ const results = [];
62
+ try {
63
+ for (var _d = true, entities_1 = __asyncValues(entities), entities_1_1; entities_1_1 = await entities_1.next(), _a = entities_1_1.done, !_a; _d = true) {
64
+ _c = entities_1_1.value;
65
+ _d = false;
66
+ const entity = _c;
67
+ results.push(this.toModel(entity));
68
+ }
69
+ }
70
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
71
+ finally {
72
+ try {
73
+ if (!_d && !_a && (_b = entities_1.return)) await _b.call(entities_1);
74
+ }
75
+ finally { if (e_1) throw e_1.error; }
76
+ }
77
+ return results;
38
78
  }
39
79
  /**
40
80
  * Replace an entity of a specific version (throws error otherwise)
@@ -44,15 +84,13 @@ export default class TableStorageMapper {
44
84
  */
45
85
  async replace(model, etag) {
46
86
  const entity = this.toEntity(model);
47
- entity['.metadata'].etag = etag;
48
87
  try {
49
- const result = await this.tableService.replaceEntity(this.ModelClass.tableName, entity, {});
50
- return { model, etag: result['.metadata'].etag };
88
+ const result = await __classPrivateFieldGet(this, _TableStorageMapper_tableClient, "f").updateEntity(entity, 'Replace', { etag });
89
+ return { model, etag: result.etag };
51
90
  }
52
91
  catch (err) {
53
- if (isStorageError(err) &&
54
- err.code === Constants.StorageErrorCodeStrings.UPDATE_CONDITION_NOT_SATISFIED) {
55
- throw new OptimisticConcurrencyError(`Replace entity with etag ${etag} resulted in ${Constants.StorageErrorCodeStrings.UPDATE_CONDITION_NOT_SATISFIED}`);
92
+ if (hasErrorCode(err, errCodes.UPDATE_CONDITION_NOT_SATISFIED)) {
93
+ throw new OptimisticConcurrencyError(`Replace entity with etag ${etag} resulted in ${errCodes.UPDATE_CONDITION_NOT_SATISFIED}`);
56
94
  }
57
95
  else {
58
96
  throw err;
@@ -62,13 +100,12 @@ export default class TableStorageMapper {
62
100
  async insert(model) {
63
101
  const entity = this.toEntity(model);
64
102
  try {
65
- const result = await this.tableService.insertEntity(this.ModelClass.tableName, entity, {});
66
- return { model, etag: result['.metadata'].etag };
103
+ const result = await __classPrivateFieldGet(this, _TableStorageMapper_tableClient, "f").createEntity(entity);
104
+ return { model, etag: result.etag };
67
105
  }
68
106
  catch (err) {
69
- if (isStorageError(err) &&
70
- err.code === Constants.TableErrorCodeStrings.ENTITY_ALREADY_EXISTS) {
71
- throw new OptimisticConcurrencyError(`Trying to insert "${entity.PartitionKey}" "${entity.RowKey}" which already exists (${Constants.TableErrorCodeStrings.ENTITY_ALREADY_EXISTS})`);
107
+ if (hasErrorCode(err, errCodes.ENTITY_ALREADY_EXISTS)) {
108
+ throw new OptimisticConcurrencyError(`Trying to insert "${entity.partitionKey}" "${entity.rowKey}" which already exists (${errCodes.ENTITY_ALREADY_EXISTS})`);
72
109
  }
73
110
  else {
74
111
  throw err;
@@ -77,21 +114,22 @@ export default class TableStorageMapper {
77
114
  }
78
115
  toModel(entity) {
79
116
  const value = new this.ModelClass();
80
- this.ModelClass.identify(value, decodeKey(entity.PartitionKey._), decodeKey(entity.RowKey._));
81
- this.ModelClass.persistedFields.forEach((field) => (value[field] = entity[field]._));
117
+ this.ModelClass.identify(value, decodeKey(entity.partitionKey), decodeKey(entity.rowKey));
118
+ this.ModelClass.persistedFields.forEach((field) => (value[field] = entity[field]));
82
119
  return {
83
- etag: entity['.metadata'].etag,
120
+ etag: entity.etag,
84
121
  model: value,
85
122
  };
86
123
  }
87
124
  toEntity(entity) {
88
125
  const data = {
89
- PartitionKey: encodeKey(this.ModelClass.createPartitionKey(entity)),
90
- RowKey: encodeKey(this.ModelClass.createRowKey(entity) || ''),
126
+ partitionKey: encodeKey(this.ModelClass.createPartitionKey(entity)),
127
+ rowKey: encodeKey(this.ModelClass.createRowKey(entity) || ''),
91
128
  };
92
129
  this.ModelClass.persistedFields.forEach((field) => (data[field] = entity[field]));
93
- data['.metadata'] = {};
94
130
  return data;
95
131
  }
96
132
  }
133
+ _TableStorageMapper_tableClient = new WeakMap();
134
+ export default TableStorageMapper;
97
135
  //# sourceMappingURL=TableStorageMapper.js.map
@@ -0,0 +1,3 @@
1
+ import { BlobServiceClient } from '@azure/storage-blob';
2
+ export declare const createBlobServiceClient: () => BlobServiceClient;
3
+ //# sourceMappingURL=BlobServiceClient.d.ts.map
@@ -0,0 +1,11 @@
1
+ import { BlobServiceClient } from '@azure/storage-blob';
2
+ export const createBlobServiceClient = () => {
3
+ const connectionString = process.env.AZURE_STORAGE_CONNECTION_STRING;
4
+ if (connectionString) {
5
+ return BlobServiceClient.fromConnectionString(connectionString);
6
+ }
7
+ else {
8
+ throw new Error('AZURE_STORAGE_CONNECTION_STRING is not set');
9
+ }
10
+ };
11
+ //# sourceMappingURL=BlobServiceClient.js.map
@@ -1,10 +1,10 @@
1
1
  import { ReportIdentifier } from '@stryker-mutator/dashboard-common';
2
- import { BlobServiceAsPromised } from './BlobServiceAsPromised.js';
3
2
  import { MutantResult } from 'mutation-testing-report-schema';
3
+ import { BlobServiceClient } from '@azure/storage-blob';
4
4
  export declare class RealTimeMutantsBlobService {
5
5
  #private;
6
6
  private static readonly CONTAINER_NAME;
7
- constructor(blobService?: BlobServiceAsPromised);
7
+ constructor(blobService?: BlobServiceClient);
8
8
  createStorageIfNotExists(): Promise<void>;
9
9
  createReport(id: ReportIdentifier): Promise<void>;
10
10
  appendToReport(id: ReportIdentifier, mutants: Array<Partial<MutantResult>>): Promise<void>;
@@ -9,33 +9,31 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _RealTimeMutantsBlobService_blobService;
13
- import { BlobServiceAsPromised } from './BlobServiceAsPromised.js';
12
+ var _RealTimeMutantsBlobService_containerClient;
14
13
  import { toBlobName } from '../utils.js';
14
+ import { createBlobServiceClient } from './BlobServiceClient.js';
15
15
  // To make resource delete themselves automatically, this should be managed from within Azure:
16
16
  // https://learn.microsoft.com/en-us/azure/storage/blobs/lifecycle-management-overview?tabs=azure-portal
17
17
  export class RealTimeMutantsBlobService {
18
- constructor(blobService = new BlobServiceAsPromised()) {
19
- _RealTimeMutantsBlobService_blobService.set(this, void 0);
20
- __classPrivateFieldSet(this, _RealTimeMutantsBlobService_blobService, blobService, "f");
18
+ constructor(blobService = createBlobServiceClient()) {
19
+ _RealTimeMutantsBlobService_containerClient.set(this, void 0);
20
+ __classPrivateFieldSet(this, _RealTimeMutantsBlobService_containerClient, blobService.getContainerClient(RealTimeMutantsBlobService.CONTAINER_NAME), "f");
21
21
  }
22
22
  async createStorageIfNotExists() {
23
- await __classPrivateFieldGet(this, _RealTimeMutantsBlobService_blobService, "f").createContainerIfNotExists(RealTimeMutantsBlobService.CONTAINER_NAME, {});
23
+ await __classPrivateFieldGet(this, _RealTimeMutantsBlobService_containerClient, "f").createIfNotExists({});
24
24
  }
25
25
  async createReport(id) {
26
- await __classPrivateFieldGet(this, _RealTimeMutantsBlobService_blobService, "f").createAppendBlobFromText(RealTimeMutantsBlobService.CONTAINER_NAME, toBlobName(id), '');
26
+ await __classPrivateFieldGet(this, _RealTimeMutantsBlobService_containerClient, "f").getAppendBlobClient(toBlobName(id)).create();
27
27
  }
28
28
  async appendToReport(id, mutants) {
29
29
  const blobName = toBlobName(id);
30
30
  const data = mutants.map((mutant) => `${JSON.stringify(mutant)}\n`).join('');
31
- await __classPrivateFieldGet(this, _RealTimeMutantsBlobService_blobService, "f").appendBlockFromText(RealTimeMutantsBlobService.CONTAINER_NAME, blobName, data);
31
+ await __classPrivateFieldGet(this, _RealTimeMutantsBlobService_containerClient, "f").getAppendBlobClient(blobName).appendBlock(data, data.length);
32
32
  }
33
33
  async getReport(id) {
34
- const data = await __classPrivateFieldGet(this, _RealTimeMutantsBlobService_blobService, "f").blobToText(RealTimeMutantsBlobService.CONTAINER_NAME, toBlobName(id));
35
- if (data === '') {
36
- return [];
37
- }
34
+ const data = await __classPrivateFieldGet(this, _RealTimeMutantsBlobService_containerClient, "f").getAppendBlobClient(toBlobName(id)).downloadToBuffer();
38
35
  return (data
36
+ .toString('utf-8')
39
37
  .split('\n')
40
38
  // Since every line has a newline it will produce an empty string in the list.
41
39
  // Remove it, so nothing breaks.
@@ -44,9 +42,9 @@ export class RealTimeMutantsBlobService {
44
42
  }
45
43
  async delete(id) {
46
44
  const blobName = toBlobName(id);
47
- __classPrivateFieldGet(this, _RealTimeMutantsBlobService_blobService, "f").deleteBlobIfExists(RealTimeMutantsBlobService.CONTAINER_NAME, blobName);
45
+ await __classPrivateFieldGet(this, _RealTimeMutantsBlobService_containerClient, "f").getAppendBlobClient(blobName).deleteIfExists();
48
46
  }
49
47
  }
50
- _RealTimeMutantsBlobService_blobService = new WeakMap();
48
+ _RealTimeMutantsBlobService_containerClient = new WeakMap();
51
49
  RealTimeMutantsBlobService.CONTAINER_NAME = 'real-time-mutant-results';
52
50
  //# sourceMappingURL=RealTimeMutantsBlobService.js.map
@@ -0,0 +1,3 @@
1
+ import { TableClient } from '@azure/data-tables';
2
+ export declare const createTableClient: (tableName: string) => TableClient;
3
+ //# sourceMappingURL=TableClient.d.ts.map
@@ -0,0 +1,13 @@
1
+ import { TableClient } from '@azure/data-tables';
2
+ export const createTableClient = (tableName) => {
3
+ const connectionString = process.env.AZURE_STORAGE_CONNECTION_STRING;
4
+ if (connectionString) {
5
+ return TableClient.fromConnectionString(connectionString, tableName, {
6
+ allowInsecureConnection: process.env.NODE_ENV !== 'production',
7
+ });
8
+ }
9
+ else {
10
+ throw new Error('AZURE_STORAGE_CONNECTION_STRING is not set');
11
+ }
12
+ };
13
+ //# sourceMappingURL=TableClient.js.map
@@ -1,7 +1,8 @@
1
1
  import { ReportIdentifier } from '@stryker-mutator/dashboard-common';
2
- import { StorageError } from 'azure-storage';
2
+ import { RestError } from '@azure/storage-blob';
3
3
  export declare function encodeKey(inputWithSlashes: string): string;
4
4
  export declare function decodeKey(inputWithSemiColons: string): string;
5
- export declare function isStorageError(maybeStorageError: unknown): maybeStorageError is StorageError;
5
+ export declare function isStorageError(maybeStorageError: unknown): maybeStorageError is RestError;
6
+ export declare function hasErrorCode(err: unknown, code: string): boolean;
6
7
  export declare function toBlobName({ projectName, version, moduleName, realTime }: ReportIdentifier): string;
7
8
  //# sourceMappingURL=utils.d.ts.map
package/dist/src/utils.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { RestError } from '@azure/storage-blob';
1
2
  export function encodeKey(inputWithSlashes) {
2
3
  return inputWithSlashes.replace(/\//g, ';');
3
4
  }
@@ -5,8 +6,16 @@ export function decodeKey(inputWithSemiColons) {
5
6
  return inputWithSemiColons.replace(/;/g, '/');
6
7
  }
7
8
  export function isStorageError(maybeStorageError) {
8
- return (maybeStorageError instanceof Error &&
9
- maybeStorageError.name === 'StorageError');
9
+ return maybeStorageError instanceof RestError;
10
+ }
11
+ export function hasErrorCode(err, code) {
12
+ var _a;
13
+ if (!isStorageError(err))
14
+ return false;
15
+ const details = err.details;
16
+ return (typeof details === 'object' &&
17
+ details !== null &&
18
+ (details.errorCode === code || ((_a = details.odataError) === null || _a === void 0 ? void 0 : _a.code) === code));
10
19
  }
11
20
  export function toBlobName({ projectName, version, moduleName, realTime }) {
12
21
  const slug = [projectName, version, moduleName, realTime ? 'real-time' : realTime]
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@stryker-mutator/dashboard-data-access",
3
- "version": "0.14.4-pr-822.16",
3
+ "version": "0.15.0",
4
4
  "type": "module",
5
5
  "description": "This package contains the data access layer of the stryker dashboard application.",
6
6
  "scripts": {
7
7
  "test": "c8 --check-coverage --reporter=html --report-dir=reports/coverage --lines 80 --functions 75 --branches 65 mocha --node-option enable-source-maps \"dist/test/helpers/**/*.js\" \"dist/test/unit/**/*.js\"",
8
+ "test:integration": "mocha --node-option enable-source-maps \"dist/test/helpers/**/*.js\" \"dist/test/integration/**/*.js\"",
8
9
  "stryker": "stryker run"
9
10
  },
10
11
  "publishConfig": {
@@ -21,10 +22,11 @@
21
22
  "typings": "src/index.ts",
22
23
  "license": "ISC",
23
24
  "dependencies": {
24
- "@stryker-mutator/dashboard-common": "0.14.4-pr-822.16",
25
- "azure-storage": "2.10.7",
25
+ "@azure/data-tables": "13.2.2",
26
+ "@azure/storage-blob": "12.24.0",
27
+ "@stryker-mutator/dashboard-common": "0.15.0",
26
28
  "mutation-testing-metrics": "3.2.0",
27
29
  "mutation-testing-report-schema": "3.1.1"
28
30
  },
29
- "gitHead": "5ce06f30a58b922b79f7c5e2450de56ef94d0660"
31
+ "gitHead": "4fc5cd971e4e86fdb4b4e994651b8d40594c03aa"
30
32
  }
@@ -1,11 +0,0 @@
1
- import { BlobService } from 'azure-storage';
2
- export declare class BlobServiceAsPromised {
3
- createContainerIfNotExists: (container: string, options: BlobService.CreateContainerOptions) => Promise<BlobService.ContainerResult>;
4
- createBlockBlobFromText: (container: string, blob: string, text: string | Buffer, options: BlobService.CreateBlobRequestOptions) => Promise<BlobService.BlobResult>;
5
- blobToText: (container: string, blob: string) => Promise<string>;
6
- createAppendBlobFromText: (container: string, blob: string, text: string | Buffer) => Promise<BlobService.BlobResult>;
7
- appendBlockFromText: (container: string, blob: string, text: string | Buffer) => Promise<BlobService.BlobResult>;
8
- deleteBlobIfExists: (container: string, blob: string) => Promise<unknown>;
9
- constructor(blobService?: BlobService);
10
- }
11
- //# sourceMappingURL=BlobServiceAsPromised.d.ts.map
@@ -1,13 +0,0 @@
1
- import { createBlobService } from 'azure-storage';
2
- import { promisify } from 'util';
3
- export class BlobServiceAsPromised {
4
- constructor(blobService = createBlobService()) {
5
- this.createContainerIfNotExists = promisify(blobService.createContainerIfNotExists).bind(blobService);
6
- this.createBlockBlobFromText = promisify(blobService.createBlockBlobFromText).bind(blobService);
7
- this.blobToText = promisify(blobService.getBlobToText).bind(blobService);
8
- this.createAppendBlobFromText = promisify(blobService.createAppendBlobFromText).bind(blobService);
9
- this.appendBlockFromText = promisify(blobService.appendBlockFromText).bind(blobService);
10
- this.deleteBlobIfExists = promisify(blobService.deleteBlobIfExists).bind(blobService);
11
- }
12
- }
13
- //# sourceMappingURL=BlobServiceAsPromised.js.map
@@ -1,32 +0,0 @@
1
- import { TableService, TableQuery, common } from 'azure-storage';
2
- export type Entity<T, TKeyFields extends keyof T> = {
3
- [K in Exclude<keyof T, TKeyFields>]: {
4
- $: string;
5
- _: T[K];
6
- };
7
- } & EntityKey & EntityMetadata;
8
- export interface EntityKey {
9
- PartitionKey: {
10
- $: 'Edm.String';
11
- _: string;
12
- };
13
- RowKey: {
14
- $: 'Edm.String';
15
- _: string;
16
- };
17
- }
18
- export interface EntityMetadata {
19
- ['.metadata']: {
20
- etag: string;
21
- };
22
- }
23
- export default class TableServiceAsPromised {
24
- constructor(tableService?: TableService);
25
- insertEntity: (table: string, entityDescriptor: unknown, options: common.RequestOptions) => Promise<TableService.EntityMetadata>;
26
- replaceEntity: (table: string, entityDescriptor: unknown, options: common.RequestOptions) => Promise<TableService.EntityMetadata>;
27
- createTableIfNotExists: (name: string) => Promise<TableService.TableResult>;
28
- queryEntities: <T, Keys extends keyof T>(table: string, tableQuery: TableQuery, cancellationToken: TableService.TableContinuationToken | undefined) => Promise<TableService.QueryEntitiesResult<Entity<T, Keys> & EntityKey>>;
29
- insertOrMergeEntity: (table: string, entity: any) => Promise<TableService.EntityMetadata>;
30
- retrieveEntity: <TResult>(table: string, partitionKey: string, rowKey: string, options?: TableService.TableEntityRequestOptions) => Promise<TResult>;
31
- }
32
- //# sourceMappingURL=TableServiceAsPromised.d.ts.map
@@ -1,13 +0,0 @@
1
- import { promisify } from 'util';
2
- import { createTableService } from 'azure-storage';
3
- export default class TableServiceAsPromised {
4
- constructor(tableService = createTableService()) {
5
- this.createTableIfNotExists = promisify(tableService.createTableIfNotExists).bind(tableService);
6
- this.queryEntities = promisify(tableService.queryEntities).bind(tableService);
7
- this.insertOrMergeEntity = promisify(tableService.insertOrMergeEntity).bind(tableService);
8
- this.retrieveEntity = promisify(tableService.retrieveEntity).bind(tableService);
9
- this.replaceEntity = promisify(tableService.replaceEntity).bind(tableService);
10
- this.insertEntity = promisify(tableService.insertEntity).bind(tableService);
11
- }
12
- }
13
- //# sourceMappingURL=TableServiceAsPromised.js.map