Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/db/generated/kysely.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ export interface Component {
description: string;
extra: string | null;
flag: Generated<number>;
is_extended_promotional: Generated<number>;
joints: number;
last_on_stock: Generated<number>;
last_update: number;
Expand Down Expand Up @@ -802,6 +803,7 @@ export interface VComponent {
datasheet: string | null;
description: string | null;
extra: string | null;
is_extended_promotional: number | null;
joints: number | null;
last_on_stock: number | null;
lcsc: number | null;
Expand Down
52 changes: 52 additions & 0 deletions lib/db/optimizations/component-extended-promotional.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { sql } from "kysely"
import type { DbOptimizationSpec } from "./types"
import type { KyselyDatabaseInstance } from "../kysely-types"

export const componentExtendedPromotionalColumn: DbOptimizationSpec = {
name: "col_components_is_extended_promotional",
description:
"Add is_extended_promotional column to components table for extended promotional parts",

async checkIfAdded(db: KyselyDatabaseInstance) {
const result = await sql`
SELECT name FROM pragma_table_info('components')
WHERE name = 'is_extended_promotional'
`.execute(db)

return result.rows.length > 0
},

async execute(db: KyselyDatabaseInstance) {
// Add the column to the components table
await sql`
ALTER TABLE components ADD COLUMN is_extended_promotional INTEGER NOT NULL DEFAULT 0
`.execute(db)

// Create an index for efficient filtering
await sql`
CREATE INDEX IF NOT EXISTS idx_components_is_extended_promotional
ON components(is_extended_promotional)
`.execute(db)

// Recreate the v_components view to include the new column
const viewResult = await sql`
SELECT sql FROM sqlite_master WHERE type='view' AND name='v_components'
`.execute(db)

if (viewResult.rows.length > 0) {
const originalSql = (viewResult.rows[0] as any).sql as string

await sql`DROP VIEW IF EXISTS v_components`.execute(db)

// Insert the new column reference before the FROM clause
const fromIndex = originalSql.toUpperCase().indexOf("\nFROM")
if (fromIndex > -1) {
const newSql = `${originalSql.slice(0, fromIndex)},\n components.is_extended_promotional${originalSql.slice(fromIndex)}`
await sql.raw(newSql).execute(db)
} else {
// Fallback: just re-execute original if we can't parse it
await sql.raw(originalSql).execute(db)
}
}
},
}
5 changes: 5 additions & 0 deletions routes/api/search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export default withWinterSpec({
limit: z.string().optional(),
is_basic: z.boolean().optional(),
is_preferred: z.boolean().optional(),
is_extended_promotional: z.boolean().optional(),
}),
jsonResponse: z.any(),
} as const)(async (req, ctx) => {
Expand All @@ -48,6 +49,9 @@ export default withWinterSpec({
if (req.query.is_preferred) {
query = query.where("preferred", "=", 1)
}
if (req.query.is_extended_promotional) {
query = query.where("is_extended_promotional", "=", 1)
}

if (req.query.q) {
const rawSearchTerm = req.query.q.trim()
Expand Down Expand Up @@ -80,6 +84,7 @@ export default withWinterSpec({
package: c.package,
is_basic: Boolean(c.basic),
is_preferred: Boolean(c.preferred),
is_extended_promotional: Boolean(c.is_extended_promotional),
description: c.description,
stock: c.stock,
price: extractSmallQuantityPrice(c.price),
Expand Down
17 changes: 17 additions & 0 deletions routes/components/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export default withWinterSpec({
search: z.string().optional(),
is_basic: z.boolean().optional(),
is_preferred: z.boolean().optional(),
is_extended_promotional: z.boolean().optional(),
}),
jsonResponse: z.any(),
} as const)(async (req, ctx) => {
Expand All @@ -39,6 +40,7 @@ export default withWinterSpec({
"price",
"extra",
"basic",
"is_extended_promotional",
])
.limit(limit)
.orderBy("stock", "desc")
Expand All @@ -58,6 +60,9 @@ export default withWinterSpec({
if (req.query.is_preferred) {
query = query.where("preferred", "=", 1)
}
if (req.query.is_extended_promotional) {
query = query.where("is_extended_promotional", "=", 1)
}

if (req.query.search) {
const search = req.query.search // TypeScript now knows this is defined within this block
Expand All @@ -82,6 +87,7 @@ export default withWinterSpec({
package: c.package,
is_basic: Boolean(c.basic),
is_preferred: Boolean(c.preferred),
is_extended_promotional: Boolean(c.is_extended_promotional),
description: c.description,
stock: c.stock,
price: extractSmallQuantityPrice(c.price),
Expand Down Expand Up @@ -126,6 +132,17 @@ export default withWinterSpec({
/>
</label>
</div>
<div>
<label>
Extended Promotional:
<input
type="checkbox"
name="is_extended_promotional"
value="true"
checked={req.query.is_extended_promotional}
/>
</label>
</div>
<button type="submit">Filter</button>
</form>

Expand Down
2 changes: 2 additions & 0 deletions scripts/setup-db-optimizations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ import { componentSearchFTS } from "lib/db/optimizations/component-search-fts"
import { componentPackageIndex } from "lib/db/optimizations/component-indexes"
import { componentBasicIndex } from "lib/db/optimizations/component-basic-index"
import { componentPreferredIndex } from "lib/db/optimizations/component-preferred-index"
import { componentExtendedPromotionalColumn } from "lib/db/optimizations/component-extended-promotional"

const OPTIMIZATIONS: DbOptimizationSpec[] = [
componentSearchFTS,
componentPackageIndex,
componentBasicIndex,
componentPreferredIndex,
componentExtendedPromotionalColumn,
removeStaleComponents,
componentStockIndex,
componentInStockColumn,
Expand Down
22 changes: 22 additions & 0 deletions tests/routes/api/search.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,25 @@ test("GET /api/search with . in query", async () => {
expect(res.data).toHaveProperty("components")
expect(Array.isArray(res.data.components)).toBe(true)
})

test("GET /api/search returns is_extended_promotional field", async () => {
const { axios } = await getTestServer()
const res = await axios.get("/api/search?q=resistor&limit=1")

expect(res.data).toHaveProperty("components")
expect(Array.isArray(res.data.components)).toBe(true)

if (res.data.components.length > 0) {
const component = res.data.components[0]
expect(component).toHaveProperty("is_extended_promotional")
expect(typeof component.is_extended_promotional).toBe("boolean")
}
})

test("GET /api/search with is_extended_promotional filter", async () => {
const { axios } = await getTestServer()
const res = await axios.get("/api/search?is_extended_promotional=true")

expect(res.data).toHaveProperty("components")
expect(Array.isArray(res.data.components)).toBe(true)
})
Comment on lines +82 to +102
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test file violates the rule that a *.test.ts file may have AT MOST one test(...) function. The file now contains multiple test() functions (the original tests plus the two new ones added in lines 82-94 and 96-102). The file should be split into multiple numbered files like search1.test.ts, search2.test.ts, etc., with each file containing only one test() function.

Spotted by Graphite (based on custom rule: Custom rule)

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

22 changes: 22 additions & 0 deletions tests/routes/components/list.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,25 @@ test("GET /components/list with json param returns component data", async () =>
expect(res.data).toHaveProperty("components")
expect(Array.isArray(res.data.components)).toBe(true)
})

test("GET /components/list returns is_extended_promotional field", async () => {
const { axios } = await getTestServer()
const res = await axios.get("/components/list?json=true")
expect(res.data).toHaveProperty("components")
expect(Array.isArray(res.data.components)).toBe(true)

if (res.data.components.length > 0) {
const component = res.data.components[0]
expect(component).toHaveProperty("is_extended_promotional")
expect(typeof component.is_extended_promotional).toBe("boolean")
}
})

test("GET /components/list with is_extended_promotional filter", async () => {
const { axios } = await getTestServer()
const res = await axios.get(
"/components/list?json=true&is_extended_promotional=true",
)
expect(res.data).toHaveProperty("components")
expect(Array.isArray(res.data.components)).toBe(true)
})
Comment on lines +11 to +31
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test file violates the rule that a *.test.ts file may have AT MOST one test(...) function. The file now contains multiple test() functions (the original test plus the two new ones added in lines 11-22 and 24-31). The file should be split into multiple numbered files like list1.test.ts, list2.test.ts, etc., with each file containing only one test() function.

Spotted by Graphite (based on custom rule: Custom rule)

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

Loading