fix: ILIKE operator not supported in sqlite (#393)

* fix: replace ILIKE operator with ILike function where possible

* remove: unused import

* fix: remove alias from test case as it is not needed

* fix: product variant query

* add: integration tests + fallback to original query for all queries searching on the display_id field

* remove: console.log
This commit is contained in:
Zakaria El Asri authored and GitHub committed 2021-09-21 11:15:33 +02:00
1 parent 00ab03f3a2
commit 49a132976d
12 files changed
+793 -448

No files matched your search

@@ -1,50 +1,50 @@
const { dropDatabase } = require("pg-god"); const { dropDatabase } = require("pg-god")
const path = require("path"); const path = require("path")
const setupServer = require("../../../helpers/setup-server"); const setupServer = require("../../../helpers/setup-server")
const { useApi } = require("../../../helpers/use-api"); const { useApi } = require("../../../helpers/use-api")
const { useDb, initDb } = require("../../../helpers/use-db"); const { useDb, initDb } = require("../../../helpers/use-db")
const customerSeeder = require("../../helpers/customer-seeder"); const customerSeeder = require("../../helpers/customer-seeder")
const adminSeeder = require("../../helpers/admin-seeder"); const adminSeeder = require("../../helpers/admin-seeder")
jest.setTimeout(30000); jest.setTimeout(30000)
describe("/admin/customers", () => { describe("/admin/customers", () => {
let medusaProcess; let medusaProcess
let dbConnection; let dbConnection
beforeAll(async () => { beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..")); const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd }); dbConnection = await initDb({ cwd })
medusaProcess = await setupServer({ cwd }); medusaProcess = await setupServer({ cwd })
}); })
afterAll(async () => { afterAll(async () => {
const db = useDb(); const db = useDb()
await db.shutdown(); await db.shutdown()
medusaProcess.kill(); medusaProcess.kill()
}); })
describe("GET /admin/customers", () => { describe("GET /admin/customers", () => {
beforeEach(async () => { beforeEach(async () => {
try { try {
await adminSeeder(dbConnection); await adminSeeder(dbConnection)
await customerSeeder(dbConnection); await customerSeeder(dbConnection)
} catch (err) { } catch (err) {
console.log(err); console.log(err)
throw err; throw err
} }
}); })
afterEach(async () => { afterEach(async () => {
const db = useDb(); const db = useDb()
await db.teardown(); await db.teardown()
}); })
it("lists customers and query count", async () => { it("lists customers and query count", async () => {
const api = useApi(); const api = useApi()
const response = await api const response = await api
.get("/admin/customers", { .get("/admin/customers", {
@@ -53,11 +53,11 @@ describe("/admin/customers", () => {
}, },
}) })
.catch((err) => { .catch((err) => {
console.log(err); console.log(err)
}); })
expect(response.status).toEqual(200); expect(response.status).toEqual(200)
expect(response.data.count).toEqual(3); expect(response.data.count).toEqual(3)
expect(response.data.customers).toEqual( expect(response.data.customers).toEqual(
expect.arrayContaining([ expect.arrayContaining([
expect.objectContaining({ expect.objectContaining({
@@ -70,24 +70,24 @@ describe("/admin/customers", () => {
id: "test-customer-3", id: "test-customer-3",
}), }),
]) ])
); )
}); })
it("lists customers with specific query", async () => { it("lists customers with specific query", async () => {
const api = useApi(); const api = useApi()
const response = await api const response = await api
.get("/admin/customers?q=test2@email.com", { .get("/admin/customers?q=est2@", {
headers: { headers: {
Authorization: "Bearer test_token", Authorization: "Bearer test_token",
}, },
}) })
.catch((err) => { .catch((err) => {
console.log(err); console.log(err)
}); })
expect(response.status).toEqual(200); expect(response.status).toEqual(200)
expect(response.data.count).toEqual(1); expect(response.data.count).toEqual(1)
expect(response.data.customers).toEqual( expect(response.data.customers).toEqual(
expect.arrayContaining([ expect.arrayContaining([
expect.objectContaining({ expect.objectContaining({
@@ -95,11 +95,11 @@ describe("/admin/customers", () => {
email: "test2@email.com", email: "test2@email.com",
}), }),
]) ])
); )
}); })
it("lists customers with expand query", async () => { it("lists customers with expand query", async () => {
const api = useApi(); const api = useApi()
const response = await api const response = await api
.get("/admin/customers?q=test1@email.com&expand=shipping_addresses", { .get("/admin/customers?q=test1@email.com&expand=shipping_addresses", {
@@ -108,11 +108,11 @@ describe("/admin/customers", () => {
}, },
}) })
.catch((err) => { .catch((err) => {
console.log(err); console.log(err)
}); })
expect(response.status).toEqual(200); expect(response.status).toEqual(200)
expect(response.data.count).toEqual(1); expect(response.data.count).toEqual(1)
expect(response.data.customers).toEqual( expect(response.data.customers).toEqual(
expect.arrayContaining([ expect.arrayContaining([
expect.objectContaining({ expect.objectContaining({
@@ -126,7 +126,7 @@ describe("/admin/customers", () => {
]), ]),
}), }),
]) ])
); )
}); })
}); })
}); })
@@ -24,6 +24,67 @@ describe("/admin/discounts", () => {
medusaProcess.kill() medusaProcess.kill()
}) })
describe("GET /admin/discounts", () => {
beforeEach(async () => {
const manager = dbConnection.manager
try {
await adminSeeder(dbConnection)
await manager.insert(DiscountRule, {
id: "test-discount-rule",
description: "Test discount rule",
type: "percentage",
value: 10,
allocation: "total",
})
await manager.insert(Discount, {
id: "test-discount",
code: "TESTING",
rule_id: "test-discount-rule",
is_dynamic: false,
is_disabled: false,
})
await manager.insert(Discount, {
id: "messi-discount",
code: "BARCA100",
rule_id: "test-discount-rule",
is_dynamic: false,
is_disabled: false,
})
} catch (err) {
throw err
}
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should list discounts that match a specific query in a case insensitive manner", async () => {
const api = useApi()
const response = await api
.get("/admin/discounts?q=barca", {
headers: {
Authorization: "Bearer test_token",
},
})
.catch((err) => {
console.log(err)
})
expect(response.status).toEqual(200)
expect(response.data.count).toEqual(1)
expect(response.data.discounts).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: "messi-discount",
code: "BARCA100",
}),
])
)
})
})
describe("POST /admin/discounts", () => { describe("POST /admin/discounts", () => {
beforeEach(async () => { beforeEach(async () => {
try { try {
@@ -1,54 +1,162 @@
const path = require("path"); const path = require("path")
const { Region } = require("@medusajs/medusa"); const { Region, GiftCard } = require("@medusajs/medusa")
const setupServer = require("../../../helpers/setup-server"); const setupServer = require("../../../helpers/setup-server")
const { useApi } = require("../../../helpers/use-api"); const { useApi } = require("../../../helpers/use-api")
const { initDb, useDb } = require("../../../helpers/use-db"); const { initDb, useDb } = require("../../../helpers/use-db")
const adminSeeder = require("../../helpers/admin-seeder"); const adminSeeder = require("../../helpers/admin-seeder")
jest.setTimeout(30000); jest.setTimeout(30000)
describe("/admin/gift-cards", () => { describe("/admin/gift-cards", () => {
let medusaProcess; let medusaProcess
let dbConnection; let dbConnection
beforeAll(async () => { beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..")); const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd }); dbConnection = await initDb({ cwd })
medusaProcess = await setupServer({ cwd }); medusaProcess = await setupServer({ cwd })
}); })
afterAll(async () => { afterAll(async () => {
const db = useDb(); const db = useDb()
await db.shutdown(); await db.shutdown()
medusaProcess.kill(); medusaProcess.kill()
}); })
describe("GET /admin/gift-cards", () => {
beforeEach(async () => {
const manager = dbConnection.manager
try {
await adminSeeder(dbConnection)
await manager.insert(Region, {
id: "test-region",
name: "Test Region",
currency_code: "usd",
tax_rate: 0,
})
await manager.insert(GiftCard, {
id: "gift_test",
code: "GC_TEST",
value: 20000,
balance: 20000,
region_id: "test-region",
})
await manager.insert(GiftCard, {
id: "another_gift_test",
code: "CARD_TEST",
value: 200000,
balance: 200000,
region_id: "test-region",
})
} catch (err) {
console.log(err)
throw err
}
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("lists gift cards and query count", async () => {
const api = useApi()
const response = await api
.get("/admin/gift-cards", {
headers: {
Authorization: "Bearer test_token",
},
})
.catch((err) => {
console.log(err)
})
expect(response.status).toEqual(200)
expect(response.data.gift_cards).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: "gift_test",
code: "GC_TEST",
}),
expect.objectContaining({
id: "another_gift_test",
code: "CARD_TEST",
}),
])
)
})
it("lists gift cards with specific query", async () => {
const api = useApi()
const response = await api
.get("/admin/gift-cards?q=gc", {
headers: {
Authorization: "Bearer test_token",
},
})
.catch((err) => {
console.log(err)
})
expect(response.status).toEqual(200)
expect(response.data.gift_cards.length).toEqual(1)
expect(response.data.gift_cards).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: "gift_test",
code: "GC_TEST",
}),
])
)
})
it("lists no gift cards on query for non-existing gift card code", async () => {
const api = useApi()
const response = await api
.get("/admin/gift-cards?q=bla", {
headers: {
Authorization: "Bearer test_token",
},
})
.catch((err) => {
console.log(err)
})
expect(response.status).toEqual(200)
expect(response.data.gift_cards.length).toEqual(0)
expect(response.data.gift_cards).toEqual([])
})
})
describe("POST /admin/gift-cards", () => { describe("POST /admin/gift-cards", () => {
beforeEach(async () => { beforeEach(async () => {
const manager = dbConnection.manager; const manager = dbConnection.manager
try { try {
await adminSeeder(dbConnection); await adminSeeder(dbConnection)
await manager.insert(Region, { await manager.insert(Region, {
id: "region", id: "region",
name: "Test Region", name: "Test Region",
currency_code: "usd", currency_code: "usd",
tax_rate: 0, tax_rate: 0,
}); })
} catch (err) { } catch (err) {
console.log(err); console.log(err)
throw err; throw err
} }
}); })
afterEach(async () => { afterEach(async () => {
const db = useDb(); const db = useDb()
await db.teardown(); await db.teardown()
}); })
it("creates a gift card", async () => { it("creates a gift card", async () => {
const api = useApi(); const api = useApi()
const response = await api const response = await api
.post( .post(
@@ -64,13 +172,13 @@ describe("/admin/gift-cards", () => {
} }
) )
.catch((err) => { .catch((err) => {
console.log(err); console.log(err)
}); })
expect(response.status).toEqual(200); expect(response.status).toEqual(200)
expect(response.data.gift_card.value).toEqual(1000); expect(response.data.gift_card.value).toEqual(1000)
expect(response.data.gift_card.balance).toEqual(1000); expect(response.data.gift_card.balance).toEqual(1000)
expect(response.data.gift_card.region_id).toEqual("region"); expect(response.data.gift_card.region_id).toEqual("region")
}); })
}); })
}); })
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,153 @@
const path = require("path")
const setupServer = require("../../../helpers/setup-server")
const { useApi } = require("../../../helpers/use-api")
const { initDb, useDb } = require("../../../helpers/use-db")
const adminSeeder = require("../../helpers/admin-seeder")
const productSeeder = require("../../helpers/product-seeder")
jest.setTimeout(30000)
describe("/admin/products", () => {
let medusaProcess
let dbConnection
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd })
medusaProcess = await setupServer({ cwd })
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
medusaProcess.kill()
})
describe("GET /admin/product-variants", () => {
beforeEach(async () => {
try {
await productSeeder(dbConnection)
await adminSeeder(dbConnection)
} catch (err) {
console.log(err)
throw err
}
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("lists all product variants", async () => {
const api = useApi()
const response = await api
.get("/admin/variants/", {
headers: {
Authorization: "Bearer test_token",
},
})
.catch((err) => {
console.log(err)
})
expect(response.status).toEqual(200)
expect(response.data.variants).toEqual(
expect.arrayContaining([
expect.objectContaining(
{
id: "test-variant",
},
{
id: "test-variant_2",
},
{
id: "test-variant_1",
}
),
])
)
})
it("lists all product variants matching a specific sku", async () => {
const api = useApi()
const response = await api
.get("/admin/variants?q=sku2", {
headers: {
Authorization: "Bearer test_token",
},
})
.catch((err) => {
console.log(err)
})
expect(response.status).toEqual(200)
expect(response.data.variants.length).toEqual(1)
expect(response.data.variants).toEqual(
expect.arrayContaining([
expect.objectContaining({
sku: "test-sku2",
}),
])
)
})
it("lists all product variants matching a specific variant title", async () => {
const api = useApi()
const response = await api
.get("/admin/variants?q=rank (1)", {
headers: {
Authorization: "Bearer test_token",
},
})
.catch((err) => {
console.log(err)
})
expect(response.status).toEqual(200)
expect(response.data.variants.length).toEqual(1)
expect(response.data.variants).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: "test-variant_1",
sku: "test-sku1",
}),
])
)
})
it("lists all product variants matching a specific product title", async () => {
const api = useApi()
const response = await api
.get("/admin/variants?q=Test product1", {
headers: {
Authorization: "Bearer test_token",
},
})
.catch((err) => {
console.log(err)
})
expect(response.status).toEqual(200)
expect(response.data.variants.length).toEqual(2)
expect(response.data.variants).toEqual(
expect.arrayContaining([
expect.objectContaining({
product_id: "test-product1",
id: "test-variant_3",
sku: "test-sku3",
}),
expect.objectContaining({
product_id: "test-product1",
id: "test-variant_4",
sku: "test-sku4",
}),
])
)
})
})
})
@@ -494,9 +494,6 @@ describe("DiscountService", () => {
expect(discountRepository.findAndCount).toHaveBeenCalledTimes(1) expect(discountRepository.findAndCount).toHaveBeenCalledTimes(1)
expect(discountRepository.findAndCount).toHaveBeenCalledWith({ expect(discountRepository.findAndCount).toHaveBeenCalledWith({
join: {
alias: "discount",
},
where: expect.anything(), where: expect.anything(),
skip: 0, skip: 0,
take: 50, take: 50,
+7 -11
View File
@@ -3,7 +3,7 @@ import Scrypt from "scrypt-kdf"
import _ from "lodash" import _ from "lodash"
import { Validator, MedusaError } from "medusa-core-utils" import { Validator, MedusaError } from "medusa-core-utils"
import { BaseService } from "medusa-interfaces" import { BaseService } from "medusa-interfaces"
import { Brackets } from "typeorm" import { Brackets, ILike } from "typeorm"
/** /**
* Provides layer to manipulate customers. * Provides layer to manipulate customers.
@@ -149,9 +149,9 @@ class CustomerService extends BaseService {
qb.andWhere( qb.andWhere(
new Brackets(qb => { new Brackets(qb => {
qb.where(`email ILIKE :q`, { q: `%${q}%` }) qb.where({ email: ILike(`%${q}%`) })
.orWhere(`first_name ILIKE :q`, { q: `%${q}%` }) .orWhere({ first_name: ILike(`%${q}%`) })
.orWhere(`last_name ILIKE :q`, { q: `%${q}%` }) .orWhere({ last_name: ILike(`%${q}%`) })
}) })
) )
} }
@@ -183,18 +183,14 @@ class CustomerService extends BaseService {
delete where.first_name delete where.first_name
delete where.last_name delete where.last_name
query.join = {
alias: "customer",
}
query.where = qb => { query.where = qb => {
qb.where(where) qb.where(where)
qb.andWhere( qb.andWhere(
new Brackets(qb => { new Brackets(qb => {
qb.where(`customer.first_name ILIKE :q`, { q: `%${q}%` }) qb.where({ email: ILike(`%${q}%`) })
.orWhere(`customer.last_name ILIKE :q`, { q: `%${q}%` }) .orWhere({ first_name: ILike(`%${q}%`) })
.orWhere(`customer.email ILIKE :q`, { q: `%${q}%` }) .orWhere({ last_name: ILike(`%${q}%`) })
}) })
) )
} }
+2 -6
View File
@@ -2,7 +2,7 @@ import _ from "lodash"
import randomize from "randomatic" import randomize from "randomatic"
import { BaseService } from "medusa-interfaces" import { BaseService } from "medusa-interfaces"
import { Validator, MedusaError } from "medusa-core-utils" import { Validator, MedusaError } from "medusa-core-utils"
import { Brackets } from "typeorm" import { Brackets, ILike } from "typeorm"
/** /**
* Provides layer to manipulate discounts. * Provides layer to manipulate discounts.
@@ -151,16 +151,12 @@ class DiscountService extends BaseService {
delete where.code delete where.code
query.join = {
alias: "discount",
}
query.where = qb => { query.where = qb => {
qb.where(where) qb.where(where)
qb.andWhere( qb.andWhere(
new Brackets(qb => { new Brackets(qb => {
qb.where(`discount.code ILIKE :q`, { q: `%${q}%` }) qb.where({ code: ILike(`%${q}%`) })
}) })
) )
} }
+1 -1
View File
@@ -1,7 +1,7 @@
import _ from "lodash" import _ from "lodash"
import { BaseService } from "medusa-interfaces" import { BaseService } from "medusa-interfaces"
import { MedusaError } from "medusa-core-utils" import { MedusaError } from "medusa-core-utils"
import { Brackets } from "typeorm" import { Brackets, ILike } from "typeorm"
/** /**
* Handles draft orders * Handles draft orders
+3 -4
View File
@@ -1,8 +1,7 @@
import _ from "lodash"
import randomize from "randomatic"
import { BaseService } from "medusa-interfaces"
import { Brackets } from "typeorm"
import { MedusaError } from "medusa-core-utils" import { MedusaError } from "medusa-core-utils"
import { BaseService } from "medusa-interfaces"
import randomize from "randomatic"
import { Brackets } from "typeorm"
/** /**
* Provides layer to manipulate gift cards. * Provides layer to manipulate gift cards.
+4 -3
View File
@@ -1,5 +1,4 @@
import _ from "lodash" import { MedusaError, Validator } from "medusa-core-utils"
import { Validator, MedusaError } from "medusa-core-utils"
import { BaseService } from "medusa-interfaces" import { BaseService } from "medusa-interfaces"
import { Brackets } from "typeorm" import { Brackets } from "typeorm"
@@ -237,7 +236,9 @@ class OrderService extends BaseService {
qb.andWhere( qb.andWhere(
new Brackets(qb => { new Brackets(qb => {
qb.where(`shipping_address.first_name ILIKE :q`, { q: `%${q}%` }) qb.where(`shipping_address.first_name ILIKE :qfn`, {
qfn: `%${q}%`,
})
.orWhere(`order.email ILIKE :q`, { q: `%${q}%` }) .orWhere(`order.email ILIKE :q`, { q: `%${q}%` })
.orWhere(`display_id::varchar(255) ILIKE :dId`, { dId: `${q}` }) .orWhere(`display_id::varchar(255) ILIKE :dId`, { dId: `${q}` })
}) })
@@ -1,6 +1,6 @@
import _ from "lodash" import _ from "lodash"
import { BaseService } from "medusa-interfaces" import { BaseService } from "medusa-interfaces"
import { Brackets, Raw, IsNull } from "typeorm" import { Brackets, Raw, IsNull, ILike } from "typeorm"
import { Validator, MedusaError } from "medusa-core-utils" import { Validator, MedusaError } from "medusa-core-utils"
/** /**
@@ -558,14 +558,11 @@ class ProductVariantService extends BaseService {
} }
query.where = qb => { query.where = qb => {
qb.where(where).andWhere( qb.where(where).andWhere([
new Brackets(qb => { { sku: ILike(`%${q}%`) },
qb.where([ { title: ILike(`%${q}%`) },
{ sku: Raw(a => `${a} ILIKE :q`, { q: `%${q}%` }) }, { product: { title: ILike(`%${q}%`) } },
{ title: Raw(a => `${a} ILIKE :q`, { q: `%${q}%` }) }, ])
]).orWhere(`product.title ILIKE :q`, { q: `%${q}%` })
})
)
} }
} }