Merge pull request #3402 from omnivore-app/fix/unique-constraint

fix: ignore error when saving existing library item in db
This commit is contained in:
Jackson Harper 2024-01-22 12:38:09 +08:00 committed by GitHub
commit 4da93cbd2d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 71 additions and 56 deletions

View file

@ -5,7 +5,6 @@ import {
PageType,
PreparedDocumentInput,
} from '../../generated/graphql'
import { isUniqueViolation } from '../../repository'
import { createAndSaveLabelsInLibraryItem } from '../../services/labels'
import { createLibraryItem } from '../../services/library_item'
import { parsedContentToLibraryItem } from '../../services/save_page'
@ -126,29 +125,18 @@ export function followingServiceRouter() {
state: ArticleSavingRequestStatus.ContentNotFetched,
})
try {
const newItem = await createLibraryItem(itemToSave, userId)
logger.info('feed item saved in following')
const newItem = await createLibraryItem(itemToSave, userId)
logger.info('feed item saved in following')
// save RSS label in the item
await createAndSaveLabelsInLibraryItem(
newItem.id,
userId,
[{ name: 'RSS' }],
feedUrl
)
// save RSS label in the item
await createAndSaveLabelsInLibraryItem(
newItem.id,
userId,
[{ name: 'RSS' }],
feedUrl
)
logger.info('RSS label added to the item')
} catch (error) {
if (isUniqueViolation(error)) {
logger.info('feed item already saved')
return res.sendStatus(200)
}
logger.error('error saving feed item', error)
return res.sendStatus(500)
}
logger.info('RSS label added to the item')
return res.sendStatus(200)
}

View file

@ -8,16 +8,18 @@ import { Label } from '../entity/label'
import { LibraryItem, LibraryItemState } from '../entity/library_item'
import { BulkActionType, InputMaybe, SortParams } from '../generated/graphql'
import { createPubSubClient, EntityType } from '../pubsub'
import { redisDataSource } from '../redis_data_source'
import {
authTrx,
getColumns,
isUniqueViolation,
queryBuilderToRawSql,
valuesToRawSql,
} from '../repository'
import { libraryItemRepository } from '../repository/library_item'
import { setRecentlySavedItemInRedis, wordsCount } from '../utils/helpers'
import { logger } from '../utils/logger'
import { parseSearchQuery } from '../utils/search'
import { redisDataSource } from '../redis_data_source'
enum ReadFilter {
ALL = 'all',
@ -811,43 +813,68 @@ export const createLibraryItem = async (
pubsub = createPubSubClient(),
skipPubSub = false
): Promise<LibraryItem> => {
const newLibraryItem = await authTrx(
async (tx) =>
tx.withRepository(libraryItemRepository).save({
...libraryItem,
wordCount:
libraryItem.wordCount ??
wordsCount(libraryItem.readableContent || ''),
}),
undefined,
userId
)
if (!libraryItem.originalUrl) {
throw new Error('Original url is required')
}
// set recently saved item in redis if redis is enabled
if (redisDataSource.redisClient) {
await setRecentlySavedItemInRedis(
redisDataSource.redisClient,
userId,
newLibraryItem.originalUrl
try {
const newLibraryItem = await authTrx(
async (tx) =>
tx.withRepository(libraryItemRepository).save({
...libraryItem,
wordCount:
libraryItem.wordCount ??
wordsCount(libraryItem.readableContent || ''),
}),
undefined,
userId
)
logger.info('item created', { url: libraryItem.originalUrl })
// set recently saved item in redis if redis is enabled
if (redisDataSource.redisClient) {
await setRecentlySavedItemInRedis(
redisDataSource.redisClient,
userId,
newLibraryItem.originalUrl
)
}
if (skipPubSub) {
return newLibraryItem
}
await pubsub.entityCreated<DeepPartial<LibraryItem>>(
EntityType.PAGE,
{
...newLibraryItem,
// don't send original content and readable content
originalContent: undefined,
readableContent: undefined,
},
userId
)
}
if (skipPubSub) {
return newLibraryItem
} catch (error) {
if (isUniqueViolation(error)) {
logger.info('item already created', { url: libraryItem.originalUrl })
const existingItem = await findLibraryItemByUrl(
libraryItem.originalUrl,
userId
)
if (!existingItem) {
throw new Error(`Item not found for url: ${libraryItem.originalUrl}`)
}
return existingItem
}
logger.error('error creating item', error)
throw error
}
await pubsub.entityCreated<DeepPartial<LibraryItem>>(
EntityType.PAGE,
{
...newLibraryItem,
// don't send original content and readable content
originalContent: undefined,
readableContent: undefined,
},
userId
)
return newLibraryItem
}
export const findLibraryItemsByPrefix = async (

View file

@ -106,7 +106,7 @@ export const createTestLibraryItem = async (
userId: string,
labels?: Label[]
): Promise<LibraryItem> => {
const item: DeepPartial<LibraryItem> = {
const item = {
user: { id: userId },
title: 'test title',
originalContent: '<p>test content</p>',