Skip to content

Commit db25722

Browse files
committed
implemented synchronus novel and chapter fetch
1 parent 354c638 commit db25722

33 files changed

Lines changed: 443 additions & 354 deletions

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@
118118
"react-native-worklets": "^0.8.1",
119119
"react-native-zip-archive": "^7.0.2",
120120
"sanitize-html": "^2.17.2",
121-
"urlencode": "^2.0.0"
121+
"urlencode": "^2.0.0",
122122
"zustand": "^5.0.12"
123123
},
124124
"devDependencies": {

pnpm-lock.yaml

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/database/queries/ChapterQueries.ts

Lines changed: 69 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -300,23 +300,61 @@ export const clearUpdates = async (): Promise<void> => {
300300
// #endregion
301301
// #region Selectors
302302

303-
export const getCustomPages = async (novelId: number) => {
304-
return await dbManager
305-
.selectDistinct({ page: chapterSchema.page })
306-
.from(chapterSchema)
307-
.where(eq(chapterSchema.novelId, novelId))
308-
.orderBy(asc(castInt(chapterSchema.page)))
309-
.all();
303+
export const getCustomPages = (novelId: number) => {
304+
return dbManager.allSync(
305+
dbManager
306+
.selectDistinct({ page: chapterSchema.page })
307+
.from(chapterSchema)
308+
.where(eq(chapterSchema.novelId, novelId))
309+
.orderBy(asc(castInt(chapterSchema.page))),
310+
);
310311
};
311312

312313
export const getNovelChapters = async (
313314
novelId: number,
315+
sort?: ChapterOrderKey,
316+
filter?: ChapterFilterKey[],
317+
page?: string,
318+
limit: number = 1000,
314319
): Promise<ChapterInfo[]> =>
315320
dbManager
316321
.select()
317322
.from(chapterSchema)
318-
.where(eq(chapterSchema.novelId, novelId));
323+
.where(
324+
and(
325+
eq(chapterSchema.novelId, novelId),
326+
!page ? sql.raw('true') : eq(chapterSchema.page, page),
327+
chapterFilterToSQL(filter),
328+
),
329+
)
330+
.orderBy(chapterOrderToSQL(sort))
331+
.limit(limit)
332+
.all();
319333

334+
export const getNovelChaptersSync = (
335+
novelId: number,
336+
sort?: ChapterOrderKey,
337+
filter?: ChapterFilterKey[],
338+
page?: string,
339+
limit: number = 1000,
340+
): ChapterInfo[] =>
341+
dbManager.allSync(
342+
dbManager
343+
.select()
344+
.from(chapterSchema)
345+
.where(
346+
and(
347+
eq(chapterSchema.novelId, novelId),
348+
!page ? sql.raw('true') : eq(chapterSchema.page, page),
349+
chapterFilterToSQL(filter),
350+
),
351+
)
352+
.orderBy(chapterOrderToSQL(sort))
353+
.limit(limit), // Adding a limit to prevent potential performance issues with large datasets
354+
);
355+
/**
356+
* @deprecated, use getNovelChapters with whereConditions instead
357+
*/
320358
export const getUnreadNovelChapters = async (
321359
novelId: number,
322360
): Promise<ChapterInfo[]> =>
@@ -326,7 +364,9 @@ export const getUnreadNovelChapters = async (
326364
.where(
327365
and(eq(chapterSchema.novelId, novelId), eq(chapterSchema.unread, true)),
328366
);
329-
367+
/**
368+
* @deprecated, use getNovelChapters with whereConditions instead
369+
*/
330370
export const getAllUndownloadedChapters = async (
331371
novelId: number,
332372
): Promise<ChapterInfo[]> =>
@@ -339,7 +379,9 @@ export const getAllUndownloadedChapters = async (
339379
eq(chapterSchema.isDownloaded, false),
340380
),
341381
);
342-
382+
/**
383+
* @deprecated, use getNovelChapters with whereConditions instead
384+
*/
343385
export const getAllUndownloadedAndUnreadChapters = async (
344386
novelId: number,
345387
): Promise<ChapterInfo[]> =>
@@ -408,8 +450,8 @@ export const getPageChaptersBatched = async (
408450
page?: string,
409451
batch: number = 0,
410452
) => {
411-
const limit = 300;
412-
const offset = 300 * batch;
453+
const limit = 1000;
454+
const offset = 1000 * batch;
413455
const query = dbManager
414456
.select()
415457
.from(chapterSchema)
@@ -451,20 +493,21 @@ export const getFirstUnreadChapter = (
451493
filter?: ChapterFilterKey[],
452494
page?: string,
453495
) =>
454-
dbManager
455-
.select()
456-
.from(chapterSchema)
457-
.where(
458-
and(
459-
eq(chapterSchema.novelId, novelId),
460-
eq(chapterSchema.page, page || '1'),
461-
eq(chapterSchema.unread, true),
462-
chapterFilterToSQL(filter),
463-
),
464-
)
465-
.orderBy(asc(chapterSchema.position))
466-
.limit(1)
467-
.get();
496+
dbManager.getSync(
497+
dbManager
498+
.select()
499+
.from(chapterSchema)
500+
.where(
501+
and(
502+
eq(chapterSchema.novelId, novelId),
503+
eq(chapterSchema.page, page || '1'),
504+
eq(chapterSchema.unread, true),
505+
chapterFilterToSQL(filter),
506+
),
507+
)
508+
.orderBy(asc(chapterSchema.position))
509+
.limit(1),
510+
);
468511

469512
export const getNovelChaptersByName = async (
470513
novelId: number,

src/database/queries/NovelQueries.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { insertChapters } from './ChapterQueries';
66

77
import { showToast } from '@utils/showToast';
88
import { getString } from '@strings/translations';
9-
import { BackupNovel, NovelInfo } from '../types';
9+
import { BackupNovel, DBNovelInfo, NovelInfo } from '../types';
1010
import { SourceNovel } from '@plugins/types';
1111
import { NOVEL_STORAGE } from '@utils/Storages';
1212
import { downloadFile } from '@plugins/helpers/fetch';
@@ -82,7 +82,7 @@ export const getAllNovels = async (): Promise<NovelInfo[]> => {
8282
return dbManager.select().from(novelSchema).all();
8383
};
8484

85-
export const getNovelById = (novelId: number): NovelInfo | undefined => {
85+
export const getNovelById = (novelId: number): DBNovelInfo | undefined => {
8686
return dbManager.getSync(
8787
dbManager.select().from(novelSchema).where(eq(novelSchema.id, novelId)),
8888
);
@@ -91,7 +91,7 @@ export const getNovelById = (novelId: number): NovelInfo | undefined => {
9191
export const getNovelByPath = (
9292
novelPath: string,
9393
pluginId: string,
94-
): NovelInfo | undefined => {
94+
): DBNovelInfo | undefined => {
9595
const res = dbManager.getSync(
9696
dbManager
9797
.select()

src/database/utils/filter.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ const FILTER_STATES = {
1010
} as const;
1111
export type FilterStates = typeof FILTER_STATES;
1212

13+
export type FilterObject = {
14+
unread?: boolean;
15+
isDownloaded?: boolean;
16+
bookmark?: boolean;
17+
};
18+
1319
export class ChapterFilterObject {
1420
private filter: Map<
1521
ChapterFilterPositiveKey,
@@ -51,6 +57,26 @@ export class ChapterFilterObject {
5157
return res as ChapterFilterKey[];
5258
}
5359

60+
toFilterObject(): FilterObject {
61+
const result: FilterObject = {};
62+
for (const [key, value] of this.filter.entries()) {
63+
if (value === FILTER_STATES.OFF) continue;
64+
65+
switch (key) {
66+
case 'read':
67+
result.unread = value !== FILTER_STATES.ON;
68+
break;
69+
case 'downloaded':
70+
result.isDownloaded = value === FILTER_STATES.ON;
71+
break;
72+
case 'bookmarked':
73+
result.bookmark = value === FILTER_STATES.ON;
74+
break;
75+
}
76+
}
77+
return result;
78+
}
79+
5480
set(key: ChapterFilterPositiveKey, value: keyof typeof FILTER_STATES) {
5581
this.filter.set(key, FILTER_STATES[value]);
5682
this.setState([...this.toArray()]);

src/database/utils/parser.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import {
66
} from '@database/constants';
77
import { SQL, sql } from 'drizzle-orm';
88

9-
export function chapterOrderToSQL(order: ChapterOrderKey) {
9+
export function chapterOrderToSQL(order?: ChapterOrderKey) {
10+
if (!order) return sql.raw(CHAPTER_ORDER.positionAsc);
1011
const o = CHAPTER_ORDER[order] ?? CHAPTER_ORDER.positionAsc;
1112
return sql.raw(o);
1213
}

src/hooks/__tests__/useNovelStore.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import './mocks';
22
import { ChapterInfo, NovelInfo } from '@database/types';
3-
import { createNovelStore } from '@hooks/persisted/useNovel/novelStore';
3+
import { createNovelStore } from '@hooks/persisted/useNovel/__tests__/novelStore';
44
import { ChapterActionsDependencies } from '@hooks/persisted/useNovel/chapterActions';
55

66
const PLUGIN_ID = 'test-plugin';

src/hooks/persisted/useNovel.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
keyContract,
1616
type NovelPersistenceInput,
1717
novelPersistence,
18-
} from './useNovel/contracts';
18+
} from './useNovel/store-helper/contracts';
1919
import type { BatchInfo, NovelSettings } from './useNovel/types';
2020

2121
export { NOVEL_PAGE_INDEX_PREFIX, NOVEL_SETTINGS_PREFIX, LAST_READ_PREFIX };

src/hooks/persisted/useNovel/__tests__/bootstrapService.test.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { ChapterInfo, NovelInfo } from '@database/types';
44
import {
55
createBootstrapService,
66
BootstrapServiceDependencies,
7-
} from '../bootstrapService';
7+
} from '../store-helper/bootstrapService';
88

99
const PLUGIN_ID = 'test-plugin';
1010
const NOVEL_PATH = '/novels/test';
@@ -68,9 +68,9 @@ describe('bootstrapService', () => {
6868

6969
it('returns success payload from db-first branch', async () => {
7070
const deps = createDeps();
71-
const service = createBootstrapService(deps);
71+
const service = createBootstrapService();
7272

73-
const result = await service.bootstrapNovel({
73+
const result = await service.bootstrapNovelAsync({
7474
novel: undefined,
7575
novelPath: NOVEL_PATH,
7676
pluginId: PLUGIN_ID,
@@ -103,9 +103,9 @@ describe('bootstrapService', () => {
103103
deps.fetchPage.mockResolvedValue({
104104
chapters: mockChapters.map(ch => ({ ...ch, page: null })),
105105
} as never);
106-
const service = createBootstrapService(deps);
106+
const service = createBootstrapService();
107107

108-
const result = await service.bootstrapNovel({
108+
const result = await service.bootstrapNovelAsync({
109109
novel: mockNovel,
110110
novelPath: NOVEL_PATH,
111111
pluginId: PLUGIN_ID,
@@ -132,9 +132,9 @@ describe('bootstrapService', () => {
132132
const deps = createDeps();
133133
deps.getNovelByPath.mockReturnValue(undefined);
134134
deps.fetchNovel.mockResolvedValue({ ...mockNovel, chapters: [] } as never);
135-
const service = createBootstrapService(deps);
135+
const service = createBootstrapService();
136136

137-
const result = await service.bootstrapNovel({
137+
const result = await service.bootstrapNovelAsync({
138138
novel: undefined,
139139
novelPath: NOVEL_PATH,
140140
pluginId: PLUGIN_ID,
@@ -149,9 +149,9 @@ describe('bootstrapService', () => {
149149
it('returns error result when underlying data operation throws', async () => {
150150
const deps = createDeps();
151151
deps.getChapterCount.mockRejectedValue(new Error('db failed'));
152-
const service = createBootstrapService(deps);
152+
const service = createBootstrapService();
153153

154-
const result = await service.bootstrapNovel({
154+
const result = await service.bootstrapNovelAsync({
155155
novel: mockNovel,
156156
novelPath: NOVEL_PATH,
157157
pluginId: PLUGIN_ID,
@@ -167,18 +167,18 @@ describe('bootstrapService', () => {
167167

168168
it('dedupes in-flight bootstrap per ${pluginId}_${novelPath}', async () => {
169169
const deps = createDeps();
170-
const service = createBootstrapService(deps);
170+
const service = createBootstrapService();
171171

172172
const [result1, result2] = await Promise.all([
173-
service.bootstrapNovel({
173+
service.bootstrapNovelAsync({
174174
novel: mockNovel,
175175
novelPath: NOVEL_PATH,
176176
pluginId: PLUGIN_ID,
177177
pageIndex: 0,
178178
settingsSort,
179179
settingsFilter,
180180
}),
181-
service.bootstrapNovel({
181+
service.bootstrapNovelAsync({
182182
novel: mockNovel,
183183
novelPath: NOVEL_PATH,
184184
pluginId: PLUGIN_ID,

src/hooks/persisted/useNovel/__tests__/chapterActions.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
markPreviousChaptersUnreadAction,
1313
refreshChaptersAction,
1414
updateChapterProgressAction,
15-
} from '../chapterActions';
15+
} from '../store/chapterActions';
1616

1717
const makeChapter = (id: number, overrides: Partial<ChapterInfo> = {}) => ({
1818
id,

0 commit comments

Comments
 (0)