-
Notifications
You must be signed in to change notification settings - Fork 0
refactor(get-ahblines): Get ahblines from sqlite instead from json files #416
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
f7fe517
d3a9e18
0ab5d67
e835315
4698ec8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { Entity, Column, PrimaryColumn, Index } from 'typeorm'; | ||
|
||
@Entity({ name: 'ahbline', synchronize: false }) | ||
export class AhbLine { | ||
@PrimaryColumn({ type: 'varchar', length: 32 }) | ||
id!: string; | ||
|
||
@Column({ type: 'integer' }) | ||
@Index('ix_ahbline_position_inside_ahb') | ||
position_inside_ahb!: number; | ||
|
||
@Column({ type: 'varchar', nullable: true }) | ||
segment_group_key?: string; | ||
|
||
@Column({ type: 'varchar', nullable: true }) | ||
segment_code?: string; | ||
|
||
@Column({ type: 'varchar', nullable: true }) | ||
data_element?: string; | ||
|
||
@Column({ type: 'varchar', nullable: true }) | ||
segment_id?: string; | ||
|
||
@Column({ type: 'varchar', nullable: true }) | ||
value_pool_entry?: string; | ||
|
||
@Column({ type: 'varchar', nullable: true }) | ||
name?: string; | ||
|
||
@Column({ type: 'varchar', nullable: true }) | ||
ahb_expression?: string; | ||
|
||
@Column({ type: 'varchar', nullable: true }) | ||
conditions?: string; | ||
|
||
@Column({ type: 'varchar', nullable: true }) | ||
section_name?: string; | ||
|
||
@Column({ type: 'integer', nullable: true }) | ||
index?: number; | ||
|
||
@Column({ type: 'varchar', length: 32, nullable: true }) | ||
ahb_id?: string; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,47 +2,117 @@ import { BlobServiceClient } from '@azure/storage-blob'; | |
import { Readable } from 'stream'; | ||
import { Ahb } from '../../app/core/api/models'; | ||
import { NotFoundError } from '../infrastructure/errors'; | ||
import BlobStorageBacked from './abstract/blobStorageBacked'; | ||
import { AppDataSource } from '../infrastructure/database'; | ||
import { AhbMetaInformation } from '../entities/ahb-meta-information.entity'; | ||
import { AhbLine } from '../entities/ahb-line.entity'; | ||
|
||
export enum FileType { | ||
CSV = 'csv', | ||
JSON = 'json', | ||
XLSX = 'xlsx', | ||
} | ||
|
||
export default class AHBRepository extends BlobStorageBacked { | ||
private ahbContainerName: string; | ||
export default class AHBRepository { | ||
private blobClient?: BlobServiceClient; | ||
private ahbContainerName?: string; | ||
|
||
constructor(client?: BlobServiceClient) { | ||
super(client); | ||
if (!process.env['AHB_CONTAINER_NAME']) { | ||
throw new Error('AHB_CONTAINER_NAME is not set'); | ||
if (client) { | ||
this.blobClient = client; | ||
this.ahbContainerName = process.env['AHB_CONTAINER_NAME']; | ||
} | ||
this.ahbContainerName = process.env['AHB_CONTAINER_NAME']; | ||
} | ||
|
||
// Retrieve a single AHB from the blob storage | ||
// 1. Get the container client (all AHB blobs are stored in the same container) | ||
// 2. Get the blob name based on the pruefi, formatVersion and file type | ||
// 3. Get the block blob client | ||
// 4. Download the blob | ||
// 5. Convert the blob content to a string | ||
// 6. Parse the string to an Ahb object | ||
// Retrieve a single AHB from either database (JSON) or blob storage (XLSX/CSV) | ||
public async get(pruefi: string, formatVersion: string, type: FileType): Promise<Ahb | Buffer> { | ||
const containerClient = this.client.getContainerClient(this.ahbContainerName); | ||
const blobName = await this.getBlobName(pruefi, formatVersion, type); | ||
const blockBlobClient = containerClient.getBlockBlobClient(blobName); | ||
const downloadBlockBlobResponse = await blockBlobClient.download(0); | ||
if (type === FileType.JSON) { | ||
return this.getFromDatabase(pruefi, formatVersion); | ||
} else { | ||
return this.getFromBlobStorage(pruefi, formatVersion, type); | ||
} | ||
Comment on lines
+28
to
+32
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. das ist aber langfristig schwer zu maintainen, oder? vermute mal, das wird in einem folge-pr geändert. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wollte das feature mit den excel-files noch weiter anbieten. |
||
} | ||
|
||
const content = await this.streamToBuffer( | ||
downloadBlockBlobResponse.readableStreamBody as Readable | ||
); | ||
private async getFromDatabase(pruefi: string, formatVersion: string): Promise<Ahb> { | ||
// Initialize the database connection if not already initialized | ||
if (!AppDataSource.isInitialized) { | ||
await AppDataSource.initialize(); | ||
} | ||
|
||
if (type === FileType.JSON) { | ||
const jsonString = content.toString('utf-8'); | ||
return JSON.parse(jsonString) as Ahb; | ||
// Get the meta information and lines from the database | ||
const metaInfo = await AppDataSource.getRepository(AhbMetaInformation) | ||
.createQueryBuilder('ami') | ||
.where('ami.edifact_format_version = :formatVersion', { formatVersion }) | ||
.andWhere('ami.pruefidentifikator = :pruefi', { pruefi }) | ||
.getOne(); | ||
|
||
if (!metaInfo) { | ||
throw new NotFoundError( | ||
`AHB not found for pruefi ${pruefi} and format version ${formatVersion}` | ||
); | ||
} | ||
|
||
const lines = await AppDataSource.getRepository(AhbLine) | ||
.createQueryBuilder('al') | ||
.where('al.ahb_id = :ahbId', { ahbId: metaInfo.ahb_id }) | ||
.orderBy('al.position_inside_ahb', 'ASC') | ||
.getMany(); | ||
|
||
// Transform the data to match the API schema | ||
return { | ||
meta: { | ||
description: metaInfo.description || '', | ||
direction: metaInfo.direction || '', | ||
maus_version: '0.3.1', // TODO: Add this to the database schema | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. braucht das der lcient oder irgendwer? Ich würde das einfach auslassen There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nö brauchen wir nicht There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done in 4698ec8 |
||
pruefidentifikator: metaInfo.pruefidentifikator, | ||
}, | ||
lines: lines.map(line => ({ | ||
ahb_expression: line.ahb_expression || '', | ||
conditions: line.conditions || '', | ||
data_element: line.data_element || '', | ||
guid: line.id, | ||
index: line.index || 0, | ||
name: line.name || '', | ||
section_name: line.section_name || '', | ||
segment_code: line.segment_code || '', | ||
segment_group_key: line.segment_group_key || '', | ||
value_pool_entry: line.value_pool_entry || '', | ||
})), | ||
}; | ||
} | ||
|
||
private async getFromBlobStorage( | ||
pruefi: string, | ||
formatVersion: string, | ||
type: FileType | ||
): Promise<Buffer> { | ||
if (!this.blobClient || !this.ahbContainerName) { | ||
// Initialize blob client if not already done | ||
if (!process.env['AZURE_BLOB_STORAGE_CONNECTION_STRING']) { | ||
throw new NotFoundError( | ||
'Azure Blob Storage connection string is not configured (AZURE_BLOB_STORAGE_CONNECTION_STRING)' | ||
); | ||
} | ||
if (!process.env['AHB_CONTAINER_NAME']) { | ||
throw new NotFoundError('AHB container name is not configured (AHB_CONTAINER_NAME)'); | ||
} | ||
this.blobClient = BlobServiceClient.fromConnectionString( | ||
process.env['AZURE_BLOB_STORAGE_CONNECTION_STRING'] | ||
); | ||
this.ahbContainerName = process.env['AHB_CONTAINER_NAME']; | ||
} | ||
|
||
return content; | ||
const containerClient = this.blobClient.getContainerClient(this.ahbContainerName); | ||
const blobName = await this.getBlobName(pruefi, formatVersion, type); | ||
const blockBlobClient = containerClient.getBlockBlobClient(blobName); | ||
|
||
try { | ||
const downloadBlockBlobResponse = await blockBlobClient.download(0); | ||
return await this.streamToBuffer(downloadBlockBlobResponse.readableStreamBody as Readable); | ||
} catch (error) { | ||
throw new NotFoundError( | ||
`File not found for pruefi ${pruefi} and format version ${formatVersion}` | ||
); | ||
} | ||
} | ||
|
||
private async streamToBuffer(readableStream: Readable): Promise<Buffer> { | ||
|
@@ -58,9 +128,6 @@ export default class AHBRepository extends BlobStorageBacked { | |
}); | ||
} | ||
|
||
// Get the blob name based on the pruefi, formatVersion and file type. | ||
// Structure of a blob name: {formatVersion}/{format}/{fileTypeDirectory}/{pruefi}.{fileType} | ||
// This method needs to further to find {format} and {fileTypeDirectory}. | ||
private async getBlobName( | ||
pruefi: string, | ||
formatVersion: string, | ||
|
@@ -71,7 +138,6 @@ export default class AHBRepository extends BlobStorageBacked { | |
return `${formatVersion}/${format}/${fileFormatDirectoryName}/${pruefi}.${type.toString()}`; | ||
} | ||
|
||
// Get the directory name for a specified file type | ||
private getFileTypeDirectoryName(fileType: FileType): string { | ||
switch (fileType) { | ||
case FileType.CSV: | ||
|
@@ -85,8 +151,6 @@ export default class AHBRepository extends BlobStorageBacked { | |
} | ||
} | ||
|
||
// Retrieve the format name by looking at the blobs names in the container. | ||
// Assuming each pruefi is unique for a formatVersion. | ||
private getFormatName(pruefi: string): string { | ||
const mapping: { [key: string]: string } = { | ||
'99': 'APERAK', | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
vllt schreibst du , nur als kommentar für uns, noch rein, wo diese spalten in dieser form herkommen. das ist janur der prototypische stand mit dem ich es gestern einmal reingehackt habe. ich würde ich der vollständigkeit und reproduzierbarkeit einfach zumindest referenzieren: https://github.com/Hochfrequenz/ahb-mig-backend/releases/tag/v0.0.1 ganz unabhängig davon ob es in diesem repo bleibt oder nicht oder wo es in zukunft herkommt: so hat man die chance die DB reproduzierbar nachzubauen, zumindest als jemand mit zugriff auf private HF repos.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done in e835315