diff --git a/src/database/constants.ts b/src/database/constants.ts index e5d9b315..d44ef0c5 100644 --- a/src/database/constants.ts +++ b/src/database/constants.ts @@ -28,3 +28,8 @@ export const CHAPTER_FILTER = { export type ChapterFilterPositiveKey = keyof typeof CHAPTER_FILTER_POSITIVE; export type ChapterFilterKey = keyof typeof CHAPTER_FILTER; export type ChapterFilter = (typeof CHAPTER_FILTER)[ChapterFilterKey]; + +export const BUILT_IN_CATEGORY_IDS = { + default: 1, + local: 2, +} as const; diff --git a/src/database/queries/CategoryQueries.ts b/src/database/queries/CategoryQueries.ts index c802cedf..fd97998a 100644 --- a/src/database/queries/CategoryQueries.ts +++ b/src/database/queries/CategoryQueries.ts @@ -186,10 +186,10 @@ export const updateCategoryOrderInDb = async ( } await dbManager.write(async tx => { - for (const category of categories) { + for (const [index, category] of categories.entries()) { await tx .update(categorySchema) - .set({ sort: category.sort }) + .set({ sort: index + 1 }) .where(eq(categorySchema.id, category.id)) .run(); } diff --git a/src/database/queries/NovelQueries.ts b/src/database/queries/NovelQueries.ts index 00d9a5f4..91681dc0 100644 --- a/src/database/queries/NovelQueries.ts +++ b/src/database/queries/NovelQueries.ts @@ -21,6 +21,7 @@ import { import type { TransactionParameter } from '@database/manager/manager.d'; import { getLibraryDefaultCategoryId } from '@hooks/persisted/useSettings'; import NativeFile from '@modules/native-file'; +import { BUILT_IN_CATEGORY_IDS } from '@database/constants'; const getCategoryForNewNovel = async (tx: TransactionParameter) => { const preferredCategoryId = getLibraryDefaultCategoryId(); @@ -40,7 +41,7 @@ const getCategoryForNewNovel = async (tx: TransactionParameter) => { return tx .select({ id: categorySchema.id }) .from(categorySchema) - .where(eq(categorySchema.sort, 1)) + .where(eq(categorySchema.id, BUILT_IN_CATEGORY_IDS.default)) .get(); }; @@ -174,7 +175,7 @@ export const switchNovelToLibraryQuery = async ( .insert(novelCategorySchema) .values({ novelId: novel.id, - categoryId: 2, + categoryId: BUILT_IN_CATEGORY_IDS.local, }) .onConflictDoNothing() .run(); @@ -386,7 +387,7 @@ export const updateNovelCategories = async ( .where( and( inArray(novelCategorySchema.novelId, novelIds), - ne(novelCategorySchema.categoryId, 2), + ne(novelCategorySchema.categoryId, BUILT_IN_CATEGORY_IDS.local), ), ) .run(); diff --git a/src/database/queries/__tests__/CategoryQueries.test.ts b/src/database/queries/__tests__/CategoryQueries.test.ts index 5e49d6e0..1a13ae9c 100644 --- a/src/database/queries/__tests__/CategoryQueries.test.ts +++ b/src/database/queries/__tests__/CategoryQueries.test.ts @@ -212,7 +212,7 @@ describe('CategoryQueries', () => { }); describe('updateCategoryOrderInDb', () => { - it('should update sort order for multiple categories', async () => { + it('should persist categories using one-based display order', async () => { const testDb = getTestDb(); const cat1 = await insertTestCategory(testDb, { name: 'Cat 1', @@ -231,8 +231,8 @@ describe('CategoryQueries', () => { const categories = await getCategoriesFromDb(); const updated1 = categories.find(c => c.id === cat1); const updated2 = categories.find(c => c.id === cat2); - expect(updated1?.sort).toBe(30); - expect(updated2?.sort).toBe(40); + expect(updated1?.sort).toBe(1); + expect(updated2?.sort).toBe(2); }); it('should handle empty array', async () => { diff --git a/src/database/queries/__tests__/NovelQueries.test.ts b/src/database/queries/__tests__/NovelQueries.test.ts index 3aaba46f..5bd3b41f 100644 --- a/src/database/queries/__tests__/NovelQueries.test.ts +++ b/src/database/queries/__tests__/NovelQueries.test.ts @@ -13,7 +13,8 @@ import { clearAllTables, } from './testData'; import { categorySchema, novelCategorySchema } from '@database/schema'; -import { eq, sql } from 'drizzle-orm'; +import { eq } from 'drizzle-orm'; +import { BUILT_IN_CATEGORY_IDS } from '@database/constants'; import { getAllNovels, @@ -178,7 +179,7 @@ describe('NovelQueries', () => { expect(Boolean(novel?.inLibrary)).toBe(false); }); - it('should assign default category when adding to library', async () => { + it('should fall back to the built-in default category by ID', async () => { const testDb = getTestDb(); const novelId = await insertTestNovel(testDb, { inLibrary: false, @@ -186,12 +187,16 @@ describe('NovelQueries', () => { pluginId: 'test-plugin', }); - // Get default category (sort = 1) - const defaultCategory = await testDb.drizzleDb - .select() - .from(categorySchema) - .where(sql`${categorySchema.sort} = 1`) - .get(); + await testDb.drizzleDb + .update(categorySchema) + .set({ sort: 0 }) + .where(eq(categorySchema.id, BUILT_IN_CATEGORY_IDS.default)) + .run(); + await testDb.drizzleDb + .update(categorySchema) + .set({ sort: 1 }) + .where(eq(categorySchema.id, BUILT_IN_CATEGORY_IDS.local)) + .run(); await switchNovelToLibraryQuery('/test/novel', 'test-plugin'); @@ -202,10 +207,17 @@ describe('NovelQueries', () => { .all(); expect(associations.length).toBeGreaterThan(0); - expect( - associations.some(a => a.categoryId === (defaultCategory?.id ?? -1)), - ).toBe(!!defaultCategory); + associations.some( + association => + association.categoryId === BUILT_IN_CATEGORY_IDS.default, + ), + ).toBe(true); + expect( + associations.some( + association => association.categoryId === BUILT_IN_CATEGORY_IDS.local, + ), + ).toBe(false); }); it('should assign the user-selected default category', async () => { @@ -257,7 +269,10 @@ describe('NovelQueries', () => { .all(); expect( - associations.some(association => association.categoryId === 1), + associations.some( + association => + association.categoryId === BUILT_IN_CATEGORY_IDS.default, + ), ).toBe(true); }); }); diff --git a/src/screens/Categories/CategoriesScreen.tsx b/src/screens/Categories/CategoriesScreen.tsx index ea45ab5f..2561c575 100644 --- a/src/screens/Categories/CategoriesScreen.tsx +++ b/src/screens/Categories/CategoriesScreen.tsx @@ -51,13 +51,8 @@ const CategoriesScreen = () => { return; } - const updatedOrderCategories = data.map((category, index) => ({ - ...category, - sort: index, - })); - - setCategories(updatedOrderCategories); - updateCategoryOrderInDb(updatedOrderCategories); + setCategories(data); + updateCategoryOrderInDb(data); }; const renderItem = ({