Skip to content

Commit

Permalink
Issue #132: Added Module for Product Images (#143)
Browse files Browse the repository at this point in the history
* Issue #132: Added Prisma Model For ProductImages

* Issue #132: Added provisional product object, service and resolver

* Added Product Image Object entity

* Added product Image dto

* Added a service to add product image to the database

* added service and resolver to query and fetch all product images

* service ad resolver for getting a single product image by its ID

* feat: PR changes effected

* feat: prisma model and migration updated
  • Loading branch information
Shukazuby authored Feb 12, 2025
1 parent 4544a7a commit 78b5d8d
Show file tree
Hide file tree
Showing 24 changed files with 384 additions and 49 deletions.
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,
"product_id" 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_product_id_fkey" FOREIGN KEY ("product_id") 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("product_id")
product Product @relation(fields: [productId], references: [id])
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("productImages")
}

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")
}
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 @@ -4,6 +4,8 @@ import { ConfigModule, ConfigService } from "@nestjs/config";
import { GraphQLModule } from "@nestjs/graphql";

import { CategoryModule } from "src/modules/categories/category.module";
import { ProductImageModule } from "src/modules/product-image/product-image.module";
import { ProductModule } from "src/modules/product/product.module";
import { IS_DEV_ENV } from "src/shared/utils/is-dev.util";
import { getGraphQLConfig } from "./config/graphql.config";
import { PrismaModule } from "./prisma/prisma.module";
Expand All @@ -22,6 +24,8 @@ import { PrismaModule } from "./prisma/prisma.module";
}),
PrismaModule,
CategoryModule,
ProductModule,
ProductImageModule,
],
controllers: [],
providers: [],
Expand Down
47 changes: 39 additions & 8 deletions apps/backend/src/core/graphql/schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,50 @@
# ------------------------------------------------------

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

"""
A date-time string at UTC, such as 2019-12-03T09:54:33Z, compliant with the date-time format.
"""
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 {
categories: [Category!]!
category(id: String!): Category
}
categories: [Category!]!
category(id: String!): Category
productImage(id: String!): ProductImage
productImages: [ProductImage!]!
}
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/product-image.input.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Field, InputType } from "@nestjs/graphql";

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

@Field(() => String)
productId: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Field, ID, ObjectType } 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;
}
28 changes: 28 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,28 @@
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 { ProductImageResolver } from "./product-image.resolver";
import { ProductImageService } from "./product-image.service";

@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();
});
});
26 changes: 26 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,26 @@
import { Args, Mutation, Query, Resolver } from "@nestjs/graphql";
import { ProductImageDTO } from "./dto/product-image.input";
import { ProductImage } from "./entities/product-image.entity";
import { ProductImageService } from "./product-image.service";

@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() {
return await this.productImageService.getAllProductImages();
}

@Query(() => ProductImage, { nullable: true })
async productImage(@Args("id") id: string) {
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 { PrismaService } from "src/core/prisma/prisma.service";
import { ProductImageDTO } from "./dto/product-image.input";

@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;
}
}
7 changes: 7 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,7 @@
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 { Field, ID, ObjectType } 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 { ProductResolver } from "./product.resolver";
import { ProductService } from "./product.service";

@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();
});
});
Loading

0 comments on commit 78b5d8d

Please sign in to comment.