mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
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:
commit
4da93cbd2d
3 changed files with 71 additions and 56 deletions
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
|
|
|
|||
|
|
@ -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>',
|
||||
|
|
|
|||
Loading…
Reference in a new issue