Skip to content
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

Issue #132: Added Module for Product Images #143

Merged
merged 9 commits into from
Feb 12, 2025
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
-- CreateTable
CREATE TABLE "productImages" (
"id" TEXT NOT NULL,
"image_url" TEXT NOT NULL,
"productId" TEXT NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL,

CONSTRAINT "productImages_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "products" (
"id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL,

CONSTRAINT "products_pkey" PRIMARY KEY ("id")
);

-- AddForeignKey
ALTER TABLE "productImages" ADD CONSTRAINT "productImages_productId_fkey" FOREIGN KEY ("productId") REFERENCES "products"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
2 changes: 1 addition & 1 deletion apps/backend/prisma/migrations/migration_lock.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "postgresql"
provider = "postgresql"
19 changes: 19 additions & 0 deletions apps/backend/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,22 @@ model Category {
updatedAt DateTime @updatedAt @map("updated_at")
@@map("categories")
}

model ProductImage {
id String @id @default(uuid())
imageUrl String @map("image_url")
productId String @map("productId")
derianrddev marked this conversation as resolved.
Show resolved Hide resolved
product Product @relation(fields: [productId], references: [id])
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("productImages")
derianrddev marked this conversation as resolved.
Show resolved Hide resolved
}

model Product {
id String @id @default(uuid())
name String
images ProductImage[]
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("products")
}
derianrddev marked this conversation as resolved.
Show resolved Hide resolved
4 changes: 4 additions & 0 deletions apps/backend/src/core/core.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { CategoryModule } from "src/modules/categories/category.module";
import { IS_DEV_ENV } from "src/shared/utils/is-dev.util";
import { getGraphQLConfig } from "./config/graphql.config";
import { PrismaModule } from "./prisma/prisma.module";
import { ProductModule } from "src/modules/product/product.module";
import { ProductImageModule } from "src/modules/product-image/product-image.module";

@Module({
imports: [
Expand All @@ -22,6 +24,8 @@ import { PrismaModule } from "./prisma/prisma.module";
}),
PrismaModule,
CategoryModule,
ProductModule,
ProductImageModule
],
controllers: [],
providers: [],
Expand Down
31 changes: 31 additions & 0 deletions apps/backend/src/core/graphql/schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,38 @@ A date-time string at UTC, such as 2019-12-03T09:54:33Z, compliant with the date
"""
scalar DateTime

type Mutation {
createProduct(createProduct: ProductDTO!): Product!
createProductImage(createProductImage: ProductImageDTO!): ProductImage!
}

type Product {
createdAt: DateTime!
id: ID!
name: String!
updatedAt: DateTime!
}

input ProductDTO {
name: String!
}

type ProductImage {
createdAt: DateTime!
id: ID!
imageUrl: String!
productId: String!
updatedAt: DateTime!
}

input ProductImageDTO {
imageUrl: String!
productId: String!
}

type Query {
ProductImage(id: String!): ProductImage
ProductImages: [ProductImage!]!
categories: [Category!]!
category(id: String!): Category
}
12 changes: 6 additions & 6 deletions apps/backend/src/modules/categories/category.resolver.spec.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { Test, TestingModule } from "@nestjs/testing";
import { CategoriesResolver } from "./category.resolver";
import { CategoriesService } from "./category.service";
import { CategoryResolver } from "./category.resolver";
import { CategoryService } from "./category.service";

describe("CategoriesResolver", () => {
let resolver: CategoriesResolver;
describe("CategoryResolver", () => {
let resolver: CategoryResolver;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [CategoriesResolver, CategoriesService],
providers: [CategoryResolver, CategoryService],
}).compile();

resolver = module.get<CategoriesResolver>(CategoriesResolver);
resolver = module.get<CategoryResolver>(CategoryResolver);
});

it("should be defined", () => {
Expand Down
10 changes: 5 additions & 5 deletions apps/backend/src/modules/categories/category.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { Test, TestingModule } from "@nestjs/testing";
import { CategoriesService } from "./category.service";
import { CategoryService } from "./category.service";

describe("CategoriesService", () => {
let service: CategoriesService;
describe("CategoryService", () => {
let service: CategoryService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [CategoriesService],
providers: [CategoryService],
}).compile();

service = module.get<CategoriesService>(CategoriesService);
service = module.get<CategoryService>(CategoryService);
});

it("should be defined", () => {
Expand Down
10 changes: 10 additions & 0 deletions apps/backend/src/modules/product-image/dto/productimage.input.ts
derianrddev marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { InputType, Field } from '@nestjs/graphql';

@InputType()
export class ProductImageDTO {
@Field(() => String)
imageUrl: string;

@Field(() => String)
productId: string;
}
derianrddev marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { ObjectType, Field, ID } from '@nestjs/graphql';
import { Product } from '../../product/entities/product.entity';

@ObjectType()
export class ProductImage {
@Field(() => ID)
id: string;

@Field(() => String)
imageUrl: string;

@Field(() => String)
productId: string;

@Field(() => Date)
createdAt: Date;

@Field(() => Date)
updatedAt: Date;
}
24 changes: 24 additions & 0 deletions apps/backend/src/modules/product-image/product-image.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
type ProductImage {
# Example field (placeholder)
exampleField: Int
}

input CreateProductImageInput {
# Example field (placeholder)
exampleField: Int
}

input UpdateProductImageInput {
id: Int!
}

type Query {
productImage: [ProductImage]!
productImage(id: Int!): ProductImage
}

type Mutation {
createProductImage(createProductImageInput: CreateProductImageInput!): ProductImage!
updateProductImage(updateProductImageInput: UpdateProductImageInput!): ProductImage!
removeProductImage(id: Int!): ProductImage
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Module } from '@nestjs/common';
import { ProductImageService } from './product-image.service';
import { ProductImageResolver } from './product-image.resolver';

@Module({
providers: [ProductImageResolver, ProductImageService],
})
export class ProductImageModule {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Test, TestingModule } from '@nestjs/testing';
import { ProductImageResolver } from './product-image.resolver';
import { ProductImageService } from './product-image.service';

describe('ProductImageResolver', () => {
let resolver: ProductImageResolver;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [ProductImageResolver, ProductImageService],
}).compile();

resolver = module.get<ProductImageResolver>(ProductImageResolver);
});

it('should be defined', () => {
expect(resolver).toBeDefined();
});
});
27 changes: 27 additions & 0 deletions apps/backend/src/modules/product-image/product-image.resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Resolver, Query, Mutation, Args } from "@nestjs/graphql";
import { ProductImageService } from "./product-image.service";
import { ProductImageDTO } from "./dto/productimage.input";
import { ProductImage } from "./entities/productimage.entity";

@Resolver("ProductImage")
export class ProductImageResolver {
constructor(private readonly productImageService: ProductImageService) {}

@Mutation(() => ProductImage)
async createProductImage(
@Args('createProductImage') payload: ProductImageDTO
): Promise<ProductImage> {
return await this.productImageService.createProductImage(payload);
}

@Query(() => [ProductImage])
async ProductImages() {
derianrddev marked this conversation as resolved.
Show resolved Hide resolved
return await this.productImageService.getAllProductImages();
}

@Query(() => ProductImage, { nullable: true })
async ProductImage(@Args("id") id: string) {
derianrddev marked this conversation as resolved.
Show resolved Hide resolved
return await this.productImageService.getAProductImage(id);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { ProductImageService } from './product-image.service';

describe('ProductImageService', () => {
let service: ProductImageService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [ProductImageService],
}).compile();

service = module.get<ProductImageService>(ProductImageService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});
});
33 changes: 33 additions & 0 deletions apps/backend/src/modules/product-image/product-image.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Injectable } from "@nestjs/common";
import { ProductImageDTO } from "./dto/productimage.input";
import { PrismaService } from "src/core/prisma/prisma.service";

@Injectable()
export class ProductImageService {
constructor(private readonly prisma: PrismaService) {}

// Service to create product Image
async createProductImage(data: ProductImageDTO) {
return await this.prisma.productImage.create({ data });
}

async getAllProductImages() {
const productImages = await this.prisma.productImage.findMany();
if(productImages.length === 0){
return []
}
return productImages
}

async getAProductImage(id: string) {
const productImage = await this.prisma.productImage.findUnique({ where: { id } });

if (!productImage) {
throw new Error(`Product image not found.`);
}

return productImage;

}

}
8 changes: 8 additions & 0 deletions apps/backend/src/modules/product/dto/create-product.input.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Field, InputType } from '@nestjs/graphql';

@InputType()
export class ProductDTO {
@Field(() => String)
name: string;

}
16 changes: 16 additions & 0 deletions apps/backend/src/modules/product/entities/product.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ObjectType, Field, ID } from '@nestjs/graphql';

@ObjectType()
export class Product {
@Field(() => ID)
id: string;

@Field(() => String)
name: string;

@Field(() => Date)
createdAt: Date;

@Field(() => Date)
updatedAt: Date;
}
8 changes: 8 additions & 0 deletions apps/backend/src/modules/product/product.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Module } from '@nestjs/common';
import { ProductService } from './product.service';
import { ProductResolver } from './product.resolver';

@Module({
providers: [ProductResolver, ProductService],
})
export class ProductModule {}
19 changes: 19 additions & 0 deletions apps/backend/src/modules/product/product.resolver.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Test, TestingModule } from '@nestjs/testing';
import { ProductResolver } from './product.resolver';
import { ProductService } from './product.service';

describe('ProductResolver', () => {
let resolver: ProductResolver;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [ProductResolver, ProductService],
}).compile();

resolver = module.get<ProductResolver>(ProductResolver);
});

it('should be defined', () => {
expect(resolver).toBeDefined();
});
});
17 changes: 17 additions & 0 deletions apps/backend/src/modules/product/product.resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Resolver, Mutation, Args, Int } from '@nestjs/graphql';
import { ProductService } from './product.service';
import { Product } from './entities/product.entity';
import { ProductDTO } from './dto/create-product.input';

@Resolver(() => Product)
export class ProductResolver {
constructor(private readonly productService: ProductService) {}

@Mutation(() => Product)
async createProduct(
@Args('createProduct') payload: ProductDTO
): Promise<Product> {
return await this.productService.createProduct(payload);
}

}
Loading
Loading