diff --git a/app/Controllers/Http/ProductsController.ts b/app/Controllers/Http/ProductsController.ts index f85159d..a1ebdd6 100644 --- a/app/Controllers/Http/ProductsController.ts +++ b/app/Controllers/Http/ProductsController.ts @@ -1,38 +1,27 @@ import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext' -import products from 'App/Resourses/ProductsDummyData' - +import Product from 'App/Models/Product' export default class ProductsController { - public async index(ctx: HttpContextContract) { - const query = ctx.request.qs(); - const page: number = query.page || 1; - const search: string = query.search || ''; - const sortBy: string = query.sortBy || ''; - const sortType: string = query.sortType || '' - let searchedProducts = products.filter((item) => { - return item.category.toLowerCase().includes(search.toLowerCase()); - }); - if (sortBy.toLowerCase() === "price") { - if (sortType.toLowerCase() === 'ascending') { - searchedProducts.sort(function (x, y) { - return x.price - y.price; - }); - } else if (sortType.toLowerCase() === 'descending') { - searchedProducts.sort(function (x, y) { - return y.price - x.price; - }); - } - } else if (sortBy.toLowerCase() === "title") { - if (sortType.toLowerCase() === 'ascending') { - searchedProducts.sort(function (x, y) { - return x.title < y.title ? -1 : 1; - }) - } else if (sortType.toLowerCase() === 'descending') { - searchedProducts.sort(function (x, y) { - return x.title > y.title ? -1 : 1; - }) - } + public async index({ request, response }: HttpContextContract) { + const { sortBy, sortType, page, search } = request.qs() as { + sortBy?: string + sortType?: string + page?: string + search?: string + } + if (sortType !== 'asc' && sortType !== 'desc' && sortType !== undefined) { + return response.badRequest('Try again') + } + let produsctsQuery = Product.query() + if (search) { + produsctsQuery = produsctsQuery.where((query) => + query.where('Lower(title)', 'Like', `[%${search.toLowerCase}%]`) + ) + } + if (sortBy) { + produsctsQuery = produsctsQuery.orderBy(sortBy, sortType ? sortType : 'asc') } - return searchedProducts.slice((page - 1) * 20, (page * 20)); + const products = produsctsQuery.paginate(page ? +page : 1, 20) + return products } -} \ No newline at end of file +} diff --git a/app/Models/Product.ts b/app/Models/Product.ts new file mode 100644 index 0000000..d2c1737 --- /dev/null +++ b/app/Models/Product.ts @@ -0,0 +1,50 @@ +import { DateTime } from 'luxon' +import { BaseModel, BelongsTo, belongsTo, column } from '@ioc:Adonis/Lucid/Orm' +import User from './User' + +export default class Product extends BaseModel { + @column({ isPrimary: true }) + public id: number + + @column() + public title: string + + @column() + public brand: string + + @column() + public category: string + + @column() + public description: string + + @column() + public discountPercentage: string + + @column() + public price: number + + @column() + public rating: string + + @column() + public stock: number + + @column() + public image: string[] + + @column() + public quantityId: number + + @column() + public userId: number + + @belongsTo(() => User) + public user: BelongsTo + + @column.dateTime({ autoCreate: true }) + public createdAt: DateTime + + @column.dateTime({ autoCreate: true, autoUpdate: true }) + public updatedAt: DateTime +} diff --git a/database/migrations/1665368585403_products.ts b/database/migrations/1665368585403_products.ts new file mode 100644 index 0000000..b2e69a8 --- /dev/null +++ b/database/migrations/1665368585403_products.ts @@ -0,0 +1,30 @@ +import BaseSchema from '@ioc:Adonis/Lucid/Schema' + +export default class extends BaseSchema { + protected tableName = 'products' + + public async up() { + this.schema.createTable(this.tableName, (table) => { + table.increments('id').unique() + table.string('title').notNullable() + table.string('description').notNullable() + table.string('brand').notNullable() + table.string('category').notNullable() + table.string('rating').nullable() + table.integer('price').notNullable() + table.integer('stock').nullable() + table.string('image').nullable() + table.integer('user_id').notNullable() + + /** + * Uses timestamptz for PostgreSQL and DATETIME2 for MSSQL + */ + table.timestamp('created_at', { useTz: true }) + table.timestamp('updated_at', { useTz: true }) + }) + } + + public async down() { + this.schema.dropTable(this.tableName) + } +} diff --git a/database/seeders/Product.ts b/database/seeders/Product.ts new file mode 100644 index 0000000..e627c6e --- /dev/null +++ b/database/seeders/Product.ts @@ -0,0 +1,58 @@ +import BaseSeeder from '@ioc:Adonis/Lucid/Seeder' +import Product from 'App/Models/Product' + +export default class extends BaseSeeder { + public async run() { + await Product.updateOrCreateMany( + ['title', 'category'], + [ + { + title: 'Apple Iphone 14', + id: 1, + brand: 'Apple', + userId: 2, + category: 'Mobile', + price: 100000, + description: `Longest battery life ever. A new Main camera and improved image processing let you capture even more sensational shots in all kinds of light — especially low light. Whether you’re filming while hiking up a rocky trail or chasing your kids through the park, try Action mode for smooth handheld videos. Safety features including emergency SOS via satellite, crash detection call for help when you can't. + `, + }, + { + title: 'Samsung Galaxy S22', + id: 2, + brand: 'Samsung', + userId: 1, + category: 'Mobile', + price: 120000, + description: `Comes with Voice Focus, Vapour Cooling Chamber, Auto Data Switching and up to 16GB RAM. 6nm Dimensity 900 processor, Voice Focus, Vapour Cooling Chamber and up to 16GB RAM. 120Hz refresh rate. 5000mAh Battery. 6nm Octa-core processor. 6000mAh Battery.`, + }, + { + title: 'Refrigrator', + id: 3, + brand: 'Samsung', + userId: 3, + category: 'Home Appliances', + price: 220000, + description: `Comes with Voice Focus, cbv nbxckmslm cvhdbcjdcnslkmz 5000mAh Battery. 6nm Octa-core processor. 6000mAh Battery.`, + }, + { + title: 'Philips Iron', + id: 4, + brand: 'Philips', + userId: 5, + category: 'Appliances', + price: 2000, + description: 'cvhdghjclksjakx,mnsxb nmzxxlsdiwoeugfusiislxvb cgvhsdksjaswk xhcjskdj', + }, + { + title: 'Television', + id: 5, + userId: 3, + brand: 'Sony', + category: 'Home Appliances', + price: 320000, + description: `Comes with Voice Focus, vchsbdkjsldk;sx vcgdhcjksksl 6000mAh Battery.`, + }, + ] + ) + } +} diff --git a/database/sqlite/db.sqlite3 b/database/sqlite/db.sqlite3 index 988ad2d..89c5190 100644 Binary files a/database/sqlite/db.sqlite3 and b/database/sqlite/db.sqlite3 differ diff --git a/package-lock.json b/package-lock.json index 35fc77e..9f3db70 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "@adonisjs/auth": "^8.2.2", "@adonisjs/core": "^5.8.6", - "@adonisjs/lucid": "^18.1.1", + "@adonisjs/lucid": "^18.2.0", "@adonisjs/repl": "^3.1.11", "luxon": "^3.0.4", "phc-argon2": "^1.1.3", @@ -644,9 +644,9 @@ } }, "node_modules/@adonisjs/lucid": { - "version": "18.1.1", - "resolved": "https://registry.npmjs.org/@adonisjs/lucid/-/lucid-18.1.1.tgz", - "integrity": "sha512-muGbRawOp14Uiuos0WAGCi/WapTfVov5YNpPb3AnIdgqvJQ5c886WVHO08gOcvuocTaNsnFoNCnc8E+/KD8lKQ==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@adonisjs/lucid/-/lucid-18.2.0.tgz", + "integrity": "sha512-lF6+euwM5sOvpaUy+de+lfMKWjzpRFCvTbko+36bOz9IbUilQtnO3pzPNf7uTj5XUalFTICpVAzw8b8beQtb3g==", "dependencies": { "@faker-js/faker": "^7.5.0", "@poppinss/hooks": "^5.0.3", @@ -10363,9 +10363,9 @@ } }, "@adonisjs/lucid": { - "version": "18.1.1", - "resolved": "https://registry.npmjs.org/@adonisjs/lucid/-/lucid-18.1.1.tgz", - "integrity": "sha512-muGbRawOp14Uiuos0WAGCi/WapTfVov5YNpPb3AnIdgqvJQ5c886WVHO08gOcvuocTaNsnFoNCnc8E+/KD8lKQ==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@adonisjs/lucid/-/lucid-18.2.0.tgz", + "integrity": "sha512-lF6+euwM5sOvpaUy+de+lfMKWjzpRFCvTbko+36bOz9IbUilQtnO3pzPNf7uTj5XUalFTICpVAzw8b8beQtb3g==", "requires": { "@faker-js/faker": "^7.5.0", "@poppinss/hooks": "^5.0.3", diff --git a/package.json b/package.json index 9234ef3..930cf0f 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "dependencies": { "@adonisjs/auth": "^8.2.2", "@adonisjs/core": "^5.8.6", - "@adonisjs/lucid": "^18.1.1", + "@adonisjs/lucid": "^18.2.0", "@adonisjs/repl": "^3.1.11", "luxon": "^3.0.4", "phc-argon2": "^1.1.3", diff --git a/start/routes.ts b/start/routes.ts index 7ed16c0..392c78b 100644 --- a/start/routes.ts +++ b/start/routes.ts @@ -29,4 +29,4 @@ Route.get('/', async () => { Route.post('signup', 'AuthController.signup') Route.post('login', 'AuthController.login') Route.get('me', 'AuthController.me') -Route.get("/products", "ProductsController.index") \ No newline at end of file +Route.get('/products', 'ProductsController.index')