-
Notifications
You must be signed in to change notification settings - Fork 0
Add Link Resolver Module with CRUD functionality and DTOs #1
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
base: staging
Are you sure you want to change the base?
Changes from 6 commits
3ce6f2d
c893dd6
5d4a025
45e1297
2a41046
da16d1d
ba34577
ed34a58
953ee86
4396f10
a164dd2
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,17 @@ | ||
version: '3.7' | ||
|
||
services: | ||
minio: | ||
image: minio/minio | ||
ports: | ||
- "9000:9000" | ||
- "9001:9001" | ||
environment: | ||
MINIO_ROOT_USER: minioadmin | ||
MINIO_ROOT_PASSWORD: minioadmin | ||
volumes: | ||
- minio-data:/data | ||
command: server --console-address ":9001" /data | ||
|
||
volumes: | ||
minio-data: |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
#!/bin/bash | ||
|
||
# Start MinIO in the background using Docker Compose | ||
echo "Starting MinIO..." | ||
docker-compose -f docker-compose.minio.yml up -d | ||
|
||
# Wait a moment for MinIO to fully initialize | ||
echo "Waiting for MinIO to start..." | ||
sleep 5 | ||
|
||
# Run the GS1 initialization command | ||
echo "Initializing GS1 identity resolver with sample data..." | ||
yarn ts-node src/cli.ts --gs1 initialize-gs1 | ||
|
||
echo "" | ||
echo "GS1 Identity Resolver has been initialized!" | ||
echo "You can access MinIO console at: http://localhost:9001" | ||
echo "Login with: minioadmin / minioadmin" | ||
echo "Check the gs1-identity-resolver bucket for your data" | ||
echo "" | ||
echo "To test the API, try these endpoints:" | ||
echo "- http://localhost:3000/gs1/products/01/12345678901234" | ||
echo "- http://localhost:3000/gs1/products/01/12345678901235/10/ABC123" | ||
echo "- http://localhost:3000/gs1/01/12345678901234 (Digital Link)" | ||
echo "" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#!/bin/bash | ||
|
||
# Start MinIO in the background | ||
echo "Starting MinIO..." | ||
docker-compose -f docker-compose.minio.yml up -d | ||
|
||
# Wait for MinIO to start | ||
echo "Waiting for MinIO to start..." | ||
sleep 5 | ||
|
||
# Save the sample data | ||
echo "Saving sample data to MinIO..." | ||
yarn save-sample | ||
|
||
echo "Done!" | ||
echo "The MinIO console is available at http://localhost:9001 (login with minioadmin/minioadmin)" | ||
echo "The link resolver data is saved to the 'link-resolvers' bucket" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { CommandFactory } from 'nest-commander'; | ||
import { LinkResolverCommandsModule } from './link-resolver/commands/commands.module'; | ||
import { GS1CommandsModule } from './gs1/commands/gs1-commands.module'; | ||
|
||
Comment on lines
+1
to
+4
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. 💡 Verification agent 🧩 Analysis chainClean imports, but LinkResolverCommandsModule is imported but never used. The imports are well-structured, but If the 🏁 Script executed: #!/bin/bash
# Checking if LinkResolverCommandsModule is used elsewhere
rg -A 3 "LinkResolverCommandsModule" --type ts Length of output: 372 Action: Address Unused Import in The grep results confirm that
|
||
async function bootstrap() { | ||
// To run LinkResolver commands | ||
if (process.argv.includes('--link-resolver')) { | ||
await CommandFactory.run(LinkResolverCommandsModule, { | ||
logger: ['error', 'warn'], | ||
}); | ||
} | ||
// To run GS1 commands | ||
else if (process.argv.includes('--gs1')) { | ||
await CommandFactory.run(GS1CommandsModule, { | ||
logger: ['error', 'warn'], | ||
}); | ||
} | ||
// Default to LinkResolver commands for backward compatibility | ||
else { | ||
await CommandFactory.run(LinkResolverCommandsModule, { | ||
logger: ['error', 'warn'], | ||
}); | ||
} | ||
} | ||
|
||
bootstrap(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/** | ||
* Common Barrel File | ||
* | ||
* This file exports all common elements from the common directory, | ||
* making them easier to import elsewhere in the application. | ||
*/ | ||
|
||
export * from './interfaces'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/** | ||
* Interfaces Barrel File | ||
* | ||
* This file exports all interfaces from the interfaces directory, | ||
* making them easier to import elsewhere in the application. | ||
*/ | ||
|
||
export * from './repository.interface'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
/** | ||
* Repository Provider Interface | ||
* | ||
* This file defines a TypeScript interface for a repository provider, | ||
* which is a common pattern in software architecture for abstracting data access operations. | ||
*/ | ||
|
||
/** | ||
* Defines the structure for data being saved | ||
* Requires an id property as a string | ||
* Allows any additional properties | ||
*/ | ||
export type SaveParams = { | ||
id: string; | ||
[k: string]: any; | ||
}; | ||
|
||
/** | ||
* Repository Provider Interface | ||
* | ||
* Defines four standard CRUD operations: | ||
* - save: Stores data with the given parameters | ||
* - one: Retrieves a single item by ID | ||
* - all: Retrieves all items of a specific category | ||
* - delete: Removes an item by ID | ||
*/ | ||
export interface IRepositoryProvider { | ||
/** | ||
* Stores data with the given parameters | ||
* @param data The data to be saved | ||
* @returns A promise resolving to void | ||
*/ | ||
save(data: SaveParams): Promise<void>; | ||
|
||
/** | ||
* Retrieves a single item by ID | ||
* @param id The unique identifier of the item | ||
* @returns A promise resolving to the requested item or null if not found | ||
*/ | ||
one<T>(id: string): Promise<T | null>; | ||
|
||
/** | ||
* Retrieves all items of a specific category | ||
* @param filter Optional filtering criteria | ||
* @returns A promise resolving to an array of items | ||
*/ | ||
all<T>(filter?: object): Promise<T[]>; | ||
|
||
/** | ||
* Removes an item by ID | ||
* @param id The unique identifier of the item to delete | ||
* @returns A promise resolving to void | ||
*/ | ||
delete(id: string): Promise<void>; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { Module } from '@nestjs/common'; | ||
import { GS1Module } from '../gs1.module'; | ||
import { InitializeGS1Command } from './initialize-gs1.command'; | ||
|
||
@Module({ | ||
imports: [GS1Module], | ||
providers: [InitializeGS1Command], | ||
exports: [InitializeGS1Command] | ||
}) | ||
export class GS1CommandsModule {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import { Command, CommandRunner } from 'nest-commander'; | ||
import { Injectable, Logger } from '@nestjs/common'; | ||
import { GS1ResolverService } from '../gs1-resolver.service'; | ||
|
||
@Command({ | ||
name: 'initialize-gs1', | ||
description: 'Initialize GS1 identity resolver with sample data', | ||
}) | ||
@Injectable() | ||
export class InitializeGS1Command extends CommandRunner { | ||
private readonly logger = new Logger(InitializeGS1Command.name); | ||
|
||
constructor(private readonly gs1Service: GS1ResolverService) { | ||
super(); | ||
} | ||
|
||
async run(): Promise<void> { | ||
try { | ||
this.logger.log('Initializing GS1 identity resolver structure...'); | ||
const initialized = await this.gs1Service.initialize(); | ||
|
||
if (!initialized) { | ||
this.logger.error('Failed to initialize GS1 structure'); | ||
return; | ||
} | ||
|
||
this.logger.log('GS1 structure initialized. Adding sample data...'); | ||
|
||
// Add sample company | ||
const sampleCompanyId = 'company-12345'; | ||
const sampleCompany = { | ||
name: 'Sample Manufacturing Co.', | ||
address: '123 Industry Way, Manufacturing City', | ||
contactEmail: '[email protected]', | ||
website: 'https://www.samplemanufacturing.com', | ||
gs1MembershipId: 'GS1-12345-XYZ' | ||
}; | ||
|
||
await this.gs1Service.upsertCompany(sampleCompanyId, sampleCompany); | ||
this.logger.log(`Added sample company: ${sampleCompanyId}`); | ||
|
||
// Add sample products with GS1 Digital Link format IDs | ||
const sampleProducts = [ | ||
{ | ||
id: '01/12345678901234', // GTIN format | ||
name: 'Organic Apple Juice', | ||
description: 'Pure organic apple juice, 100% natural ingredients', | ||
companyId: sampleCompanyId, | ||
category: 'Beverages', | ||
attributes: { | ||
organic: true, | ||
servingSize: '250ml', | ||
ingredients: ['organic apple juice', 'vitamin c'] | ||
} | ||
}, | ||
{ | ||
id: '01/12345678901235/10/ABC123', // GTIN with batch/lot | ||
name: 'Whole Grain Bread', | ||
description: 'Nutritious whole grain bread, freshly baked', | ||
companyId: sampleCompanyId, | ||
category: 'Bakery', | ||
attributes: { | ||
wholeGrain: true, | ||
weight: '500g', | ||
ingredients: ['whole grain flour', 'water', 'salt', 'yeast'] | ||
} | ||
}, | ||
{ | ||
id: '01/12345678901236/21/SERIAL9876', // GTIN with serial | ||
name: 'Premium Coffee Maker', | ||
description: 'Smart coffee maker with programmable features', | ||
companyId: sampleCompanyId, | ||
category: 'Appliances', | ||
attributes: { | ||
powerConsumption: '1200W', | ||
warranty: '2 years', | ||
color: 'stainless steel', | ||
dimensions: '30x25x40cm' | ||
} | ||
} | ||
]; | ||
|
||
for (const product of sampleProducts) { | ||
await this.gs1Service.upsertProduct(product.id, product); | ||
this.logger.log(`Added sample product: ${product.id}`); | ||
|
||
// Add a sample certificate to the last product | ||
if (product.id === '01/12345678901236/21/SERIAL9876') { | ||
const sampleCertificate = { | ||
id: 'cert-123456', | ||
name: 'Energy Efficiency Certificate', | ||
issuer: 'Energy Rating Authority', | ||
issuedDate: '2023-01-15', | ||
expiryDate: '2025-01-15', | ||
rating: 'A+', | ||
documentUrl: 'https://example.com/certificates/energy-123456.pdf' | ||
}; | ||
|
||
await this.gs1Service.addProductCertificate(product.id, sampleCertificate); | ||
this.logger.log(`Added sample certificate to product: ${product.id}`); | ||
} | ||
} | ||
|
||
this.logger.log('Sample data initialization completed successfully!'); | ||
this.logger.log('GS1 identity resolver is ready for use.'); | ||
|
||
} catch (error: unknown) { | ||
const errorMessage = error instanceof Error ? error.message : String(error); | ||
this.logger.error(`Failed to initialize GS1 with sample data: ${errorMessage}`); | ||
} | ||
} | ||
} |
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.
💡 Verification agent
🧩 Analysis chain
Verify compatibility with NestJS.
The
@nestjs/config
version has been updated to^4.0.2
. Verify that this version is compatible with the other NestJS packages still at version^9.0.0
.🌐 Web query:
💡 Result:
The compatibility between
@nestjs/[email protected]
and@nestjs/[email protected]
poses potential issues due to breaking changes introduced in@nestjs/config
versions beyond v3.x. Here's the analysis:Breaking Changes in
@nestjs/[email protected]
Version 4.0.0 introduced significant adjustments to environment variable handling:
process.env
) [3][7]ignoreEnvVars
option in favor ofskipProcessEnv
[3][7]These changes were designed for NestJS v11+ infrastructure.
Core Version Context
@nestjs/[email protected]
is part of the NestJS v9 ecosystem (released in 2023), while@nestjs/[email protected]
targets NestJS v11 (released January 2025) [6][8]. The major version mismatch suggests incompatibility.Version Compatibility Guidance
NestJS follows semantic versioning where major versions indicate breaking changes. The
@nestjs/config
package at v4.x requires:@nestjs/[email protected]
Recommendation
For
@nestjs/[email protected]
projects:@nestjs/[email protected]
(last v3 release was 3.2.0)@nestjs/[email protected]
featuresThe configuration module's v4.x release notes explicitly require NestJS v11+ core dependencies [3][7], making it incompatible with older core versions like 9.0.0.
Citations:
Action: Resolve incompatibility between @nestjs/config and NestJS core
The analysis confirms that using
@nestjs/[email protected]
with@nestjs/[email protected]
is incompatible. Version 4.x of@nestjs/config
introduces breaking changes (such as changes in environment variable handling and deprecation of certain options) and explicitly requires a minimum of@nestjs/[email protected]
. You’ll need to either:@nestjs/config
to version^3.x
(for example,3.2.0
) to maintain compatibility with NestJS v9or
@nestjs/[email protected]
.Please update the dependency in your
package.json
accordingly.