Skip to content

Commit

Permalink
Merge pull request #80 from IQSS/77-files-display-data-use-cases
Browse files Browse the repository at this point in the history
Add use cases for file tab data visualization
  • Loading branch information
kcondon authored Aug 25, 2023
2 parents a1e6709 + 3e0c21e commit 01f9e16
Show file tree
Hide file tree
Showing 42 changed files with 1,859 additions and 294 deletions.
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ module.exports = {
moduleFileExtensions: ['ts', 'js', 'json', 'node'],
coveragePathIgnorePatterns: ['node_modules', 'testHelpers'],
globalSetup: '<rootDir>/test/integration/environment/setup.js',
testTimeout: 15000,
};
1 change: 1 addition & 0 deletions jest.config.unit.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
var config = require('./jest.config');
config.modulePathIgnorePatterns = ['<rootDir>/test/integration'];
delete config.globalSetup;
delete config.testTimeout;
console.log('RUNNING UNIT TESTS');
module.exports = config;
13 changes: 8 additions & 5 deletions src/core/infra/repositories/ApiRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import { ReadError } from '../../domain/repositories/ReadError';
import { WriteError } from '../../domain/repositories/WriteError';

export abstract class ApiRepository {
public async doGet(apiEndpoint: string, authRequired = false): Promise<AxiosResponse> {
DATASET_VERSION_LATEST = ':latest';

public async doGet(apiEndpoint: string, authRequired = false, queryParams: object = {}): Promise<AxiosResponse> {
return await axios
.get(this.buildRequestUrl(apiEndpoint), this.buildRequestConfig(authRequired))
.get(this.buildRequestUrl(apiEndpoint), this.buildRequestConfig(authRequired, queryParams))
.then((response) => response)
.catch((error) => {
throw new ReadError(
Expand All @@ -15,9 +17,9 @@ export abstract class ApiRepository {
});
}

public async doPost(apiEndpoint: string, data: string | object): Promise<AxiosResponse> {
public async doPost(apiEndpoint: string, data: string | object, queryParams: object = {}): Promise<AxiosResponse> {
return await axios
.post(this.buildRequestUrl(apiEndpoint), JSON.stringify(data), this.buildRequestConfig(true))
.post(this.buildRequestUrl(apiEndpoint), JSON.stringify(data), this.buildRequestConfig(true, queryParams))
.then((response) => response)
.catch((error) => {
throw new WriteError(
Expand All @@ -26,8 +28,9 @@ export abstract class ApiRepository {
});
}

private buildRequestConfig(authRequired: boolean): AxiosRequestConfig {
private buildRequestConfig(authRequired: boolean, queryParams: object): AxiosRequestConfig {
const requestConfig: AxiosRequestConfig = {
params: queryParams,
headers: { 'Content-Type': 'application/json' },
};
if (!authRequired) {
Expand Down
3 changes: 1 addition & 2 deletions src/datasets/domain/repositories/IDatasetsRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { Dataset } from '../models/Dataset';

export interface IDatasetsRepository {
getDatasetSummaryFieldNames(): Promise<string[]>;
getDatasetById(datasetId: number, datasetVersionId?: string): Promise<Dataset>;
getDatasetByPersistentId(datasetPersistentId: string, datasetVersionId?: string): Promise<Dataset>;
getDataset(datasetId: number | string, datasetVersionId?: string): Promise<Dataset>;
getPrivateUrlDataset(token: string): Promise<Dataset>;
getDatasetCitation(datasetId: number, datasetVersionId?: string): Promise<string>;
getPrivateUrlDatasetCitation(token: string): Promise<string>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import { UseCase } from '../../../core/domain/useCases/UseCase';
import { IDatasetsRepository } from '../repositories/IDatasetsRepository';
import { Dataset } from '../models/Dataset';

export class GetDatasetById implements UseCase<Dataset> {
export class GetDataset implements UseCase<Dataset> {
private datasetsRepository: IDatasetsRepository;

constructor(datasetsRepository: IDatasetsRepository) {
this.datasetsRepository = datasetsRepository;
}

async execute(datasetId: number, datasetVersionId?: string): Promise<Dataset> {
return await this.datasetsRepository.getDatasetById(datasetId, datasetVersionId);
async execute(datasetId: number | string, datasetVersionId?: string): Promise<Dataset> {
return await this.datasetsRepository.getDataset(datasetId, datasetVersionId);
}
}
15 changes: 0 additions & 15 deletions src/datasets/domain/useCases/GetDatasetByPersistentId.ts

This file was deleted.

9 changes: 3 additions & 6 deletions src/datasets/index.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
import { DatasetsRepository } from './infra/repositories/DatasetsRepository';
import { GetDatasetSummaryFieldNames } from './domain/useCases/GetDatasetSummaryFieldNames';
import { GetDatasetById } from './domain/useCases/GetDatasetById';
import { GetDatasetByPersistentId } from './domain/useCases/GetDatasetByPersistentId';
import { GetDataset } from './domain/useCases/GetDataset';
import { GetPrivateUrlDataset } from './domain/useCases/GetPrivateUrlDataset';
import { GetDatasetCitation } from './domain/useCases/GetDatasetCitation';
import { GetPrivateUrlDatasetCitation } from './domain/useCases/GetPrivateUrlDatasetCitation';

const datasetsRepository = new DatasetsRepository();

const getDatasetSummaryFieldNames = new GetDatasetSummaryFieldNames(datasetsRepository);
const getDatasetById = new GetDatasetById(datasetsRepository);
const getDatasetByPersistentId = new GetDatasetByPersistentId(datasetsRepository);
const getDataset = new GetDataset(datasetsRepository);
const getPrivateUrlDataset = new GetPrivateUrlDataset(datasetsRepository);
const getDatasetCitation = new GetDatasetCitation(datasetsRepository);
const getPrivateUrlDatasetCitation = new GetPrivateUrlDatasetCitation(datasetsRepository);

export {
getDatasetSummaryFieldNames,
getDatasetById,
getDatasetByPersistentId,
getDataset,
getPrivateUrlDataset,
getDatasetCitation,
getPrivateUrlDatasetCitation,
Expand Down
31 changes: 11 additions & 20 deletions src/datasets/infra/repositories/DatasetsRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import { Dataset } from '../../domain/models/Dataset';
import { transformVersionResponseToDataset } from './transformers/datasetTransformers';

export class DatasetsRepository extends ApiRepository implements IDatasetsRepository {
DATASET_VERSION_LATEST = ':latest';

public async getDatasetSummaryFieldNames(): Promise<string[]> {
return this.doGet('/datasets/summaryFieldNames')
.then((response) => response.data.data)
Expand All @@ -22,20 +20,21 @@ export class DatasetsRepository extends ApiRepository implements IDatasetsReposi
});
}

public async getDatasetById(datasetId: number, datasetVersionId?: string): Promise<Dataset> {
public async getDataset(datasetId: number | string, datasetVersionId?: string): Promise<Dataset> {
if (datasetVersionId === undefined) {
datasetVersionId = this.DATASET_VERSION_LATEST;
}
return this.getDatasetVersion(`/datasets/${datasetId}/versions/${datasetVersionId}`);
}

public async getDatasetByPersistentId(datasetPersistentId: string, datasetVersionId?: string): Promise<Dataset> {
if (datasetVersionId === undefined) {
datasetVersionId = this.DATASET_VERSION_LATEST;
let endpoint;
if (typeof datasetId === 'number') {
endpoint = `/datasets/${datasetId}/versions/${datasetVersionId}`;
} else {
endpoint = `/datasets/:persistentId/versions/${datasetVersionId}?persistentId=${datasetId}`;
}
return this.getDatasetVersion(
`/datasets/:persistentId/versions/${datasetVersionId}?persistentId=${datasetPersistentId}`,
);
return this.doGet(endpoint, true)
.then((response) => transformVersionResponseToDataset(response))
.catch((error) => {
throw error;
});
}

public async getDatasetCitation(datasetId: number, datasetVersionId?: string): Promise<string> {
Expand All @@ -49,14 +48,6 @@ export class DatasetsRepository extends ApiRepository implements IDatasetsReposi
});
}

private async getDatasetVersion(endpoint: string): Promise<Dataset> {
return this.doGet(endpoint, true)
.then((response) => transformVersionResponseToDataset(response))
.catch((error) => {
throw error;
});
}

public async getPrivateUrlDatasetCitation(token: string): Promise<string> {
return this.doGet(`/datasets/privateUrlDatasetVersion/${token}/citation`)
.then((response) => response.data.data.message)
Expand Down
39 changes: 39 additions & 0 deletions src/files/domain/models/File.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
export interface File {
id: number;
persistentId: string;
name: string;
pidURL?: string;
sizeBytes: number;
version: number;
description?: string;
restricted: boolean;
directoryLabel?: string;
datasetVersionId?: number;
categories?: string[];
contentType: string;
embargo?: FileEmbargo;
storageIdentifier?: string;
originalFormat?: string;
originalFormatLabel?: string;
originalSize?: number;
originalName?: string;
UNF?: string;
rootDataFileId?: number;
previousDataFileId?: number;
md5?: string;
checksum?: FileChecksum;
metadataId?: number;
tabularTags?: string[];
creationDate?: Date;
publicationDate?: Date;
}

export interface FileEmbargo {
dateAvailable: Date;
reason?: string;
}

export interface FileChecksum {
type: string;
value: string;
}
82 changes: 82 additions & 0 deletions src/files/domain/models/FileDataTable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
export interface FileDataTable {
varQuantity?: number;
caseQuantity?: number;
recordsPerCase?: number;
UNF: string;
dataVariables: FileDataVariable[];
}

export interface FileDataVariable {
id: number;
name: string;
label?: string;
weighted: boolean;
variableIntervalType?: FileDataVariableIntervalType;
variableFormatType?: FileDataVariableFormatType;
formatCategory?: string;
format?: string;
isOrderedCategorical: boolean;
fileOrder: number;
UNF: string;
fileStartPosition?: number;
fileEndPosition?: number;
recordSegmentNumber?: number;
numberOfDecimalPoints?: number;
variableMetadata?: FileDataVariableMetadata[];
invalidRanges?: FileDataVariableInvalidRanges[];
summaryStatistics?: object;
variableCategories?: FileDataVariableCategory[];
}

export interface FileDataVariableMetadata {
id: number;
metadataId: number;
label?: string;
isWeightVar: boolean;
isWeighted: boolean;
weightVariableId?: number;
literalQuestion?: string;
interviewInstruction?: string;
postQuestion?: string;
universe?: string;
notes?: string;
categoryMetadatas: FileDataVariableCategoryMetadata[];
}

export interface FileDataVariableCategoryMetadata {
wFreq?: number;
categoryValue?: string;
}

export interface FileDataVariableInvalidRanges {
beginValue?: string;
hasBeginValueType: boolean;
isBeginValueTypePoint: boolean;
isBeginValueTypeMin: boolean;
isBeginValueTypeMinExcl: boolean;
isBeginValueTypeMax: boolean;
isBeginValueTypeMaxExcl: boolean;
endValue?: string;
hasEndValueType: boolean;
endValueTypeMax: boolean;
endValueTypeMaxExcl: boolean;
}

export interface FileDataVariableCategory {
label?: string;
value?: string;
isMissing: boolean;
frequency?: number;
}

export enum FileDataVariableIntervalType {
DISCRETE = 'discrete',
CONTIN = 'contin',
NOMINAL = 'nominal',
DICHOTOMOUS = 'dichotomous',
}

export enum FileDataVariableFormatType {
NUMERIC = 'NUMERIC',
CHARACTER = 'CHARACTER',
}
8 changes: 8 additions & 0 deletions src/files/domain/models/FileOrderCriteria.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export enum FileOrderCriteria {
NAME_AZ = 'NameAZ',
NAME_ZA = 'NameZA',
NEWEST = 'Newest',
OLDEST = 'Oldest',
SIZE = 'Size',
TYPE = 'Type',
}
4 changes: 4 additions & 0 deletions src/files/domain/models/FileUserPermissions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface FileUserPermissions {
canDownloadFile: boolean;
canEditOwnerDataset: boolean;
}
20 changes: 20 additions & 0 deletions src/files/domain/repositories/IFilesRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { FileOrderCriteria } from '../models/FileOrderCriteria';
import { File } from '../models/File';
import { FileDataTable } from '../models/FileDataTable';
import { FileUserPermissions } from '../models/FileUserPermissions';

export interface IFilesRepository {
getDatasetFiles(
datasetId: number | string,
datasetVersionId?: string,
limit?: number,
offset?: number,
orderCriteria?: FileOrderCriteria,
): Promise<File[]>;

getFileDownloadCount(fileId: number | string): Promise<number>;

getFileUserPermissions(fileId: number | string): Promise<FileUserPermissions>;

getFileDataTables(fileId: number | string): Promise<FileDataTable[]>;
}
22 changes: 22 additions & 0 deletions src/files/domain/useCases/GetDatasetFiles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { UseCase } from '../../../core/domain/useCases/UseCase';
import { FileOrderCriteria } from '../models/FileOrderCriteria';
import { IFilesRepository } from '../repositories/IFilesRepository';
import { File } from '../models/File';

export class GetDatasetFiles implements UseCase<File[]> {
private filesRepository: IFilesRepository;

constructor(filesRepository: IFilesRepository) {
this.filesRepository = filesRepository;
}

async execute(
datasetId: number | string,
datasetVersionId?: string,
limit?: number,
offset?: number,
orderCriteria?: FileOrderCriteria,
): Promise<File[]> {
return await this.filesRepository.getDatasetFiles(datasetId, datasetVersionId, limit, offset, orderCriteria);
}
}
15 changes: 15 additions & 0 deletions src/files/domain/useCases/GetFileDataTables.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { UseCase } from '../../../core/domain/useCases/UseCase';
import { IFilesRepository } from '../repositories/IFilesRepository';
import { FileDataTable } from '../models/FileDataTable';

export class GetFileDataTables implements UseCase<FileDataTable[]> {
private filesRepository: IFilesRepository;

constructor(filesRepository: IFilesRepository) {
this.filesRepository = filesRepository;
}

async execute(fileId: number | string): Promise<FileDataTable[]> {
return await this.filesRepository.getFileDataTables(fileId);
}
}
14 changes: 14 additions & 0 deletions src/files/domain/useCases/GetFileDownloadCount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { UseCase } from '../../../core/domain/useCases/UseCase';
import { IFilesRepository } from '../repositories/IFilesRepository';

export class GetFileDownloadCount implements UseCase<number> {
private filesRepository: IFilesRepository;

constructor(filesRepository: IFilesRepository) {
this.filesRepository = filesRepository;
}

async execute(fileId: number | string): Promise<number> {
return await this.filesRepository.getFileDownloadCount(fileId);
}
}
Loading

0 comments on commit 01f9e16

Please sign in to comment.