Skip to content

Commit

Permalink
feat(helper): ✨ always assign date to book update
Browse files Browse the repository at this point in the history
removes need for custom updatetimestamp implementation; also return findOneWithProjection properly instead of always casting as Book which could fail null assertions
  • Loading branch information
djdembeck committed Aug 26, 2022
1 parent 30e769e commit abde31d
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 66 deletions.
20 changes: 14 additions & 6 deletions src/helpers/database/papr/audible/PaprAudibleBookHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ export default class PaprAudibleBookHelper {
}

async findOneWithProjection() {
const findOneBook = (await BookModel.findOne(
const findOneBook = await BookModel.findOne(
{
asin: this.asin
},
{ projection: projectionWithoutDbFields }
)) as unknown as Book
)
return {
data: findOneBook,
modified: false
Expand All @@ -78,18 +78,19 @@ export default class PaprAudibleBookHelper {

// Update
if (this.options.update === '1' && findInDb.data) {
const data = findInDb.data as BookDocument
// If the objects are the exact same return right away
const equality = commonHelpers.checkDataEquality(findInDb.data, this.bookData)
const equality = commonHelpers.checkDataEquality(data, this.bookData)
if (equality) {
return {
data: findInDb.data,
data: data,
modified: false
}
}
// Check state of existing book
// Only update if either genres exist and can be checked
// -or if genres exist on new item but not old
if (findInDb.data.genres || (!findInDb.data.genres && this.bookData.genres)) {
if (data.genres || (!data.genres && this.bookData.genres)) {
// Only update if it's not nuked data
if (this.bookData.genres?.length) {
console.log(`Updating book asin ${this.asin}`)
Expand All @@ -107,7 +108,14 @@ export default class PaprAudibleBookHelper {

async update() {
try {
await BookModel.updateOne({ asin: this.asin }, { $set: { ...this.bookData } })
const found = await this.findOne()
await BookModel.updateOne(
{ asin: this.asin },
{
$set: { ...this.bookData, createdAt: found.data?._id.getTimestamp() },
$currentDate: { updatedAt: true }
}
)
// After updating, return with specific projection
const updatedBook = await this.findOneWithProjection()
// Set modified to true to indicate that the data has been updated
Expand Down
48 changes: 17 additions & 31 deletions src/helpers/routes/BookShowHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { Book } from '#config/typing/books'
import { RequestGenericWithSeed } from '#config/typing/requests'
import SeedHelper from '#helpers/authors/audible/SeedHelper'
import StitchHelper from '#helpers/books/audible/StitchHelper'
import addTimestamps from '#helpers/database/papr/addTimestamps'
import PaprAudibleBookHelper from '#helpers/database/papr/audible/PaprAudibleBookHelper'
import RedisHelper from '#helpers/database/redis/RedisHelper'
import SharedHelper from '#helpers/shared'
Expand Down Expand Up @@ -45,8 +44,12 @@ export default class BookShowHelper {
this.paprHelper.setBookData(await this.getNewBookData())
// Create or update the book
const bookToReturn = await this.paprHelper.createOrUpdate()
if (!bookToReturn.data) throw new Error(`Book ${this.asin} not found`)
const data = bookToReturn.data as BookDocument

// Update or create the book in cache
await this.redisHelper.findOrCreate(bookToReturn.data)
await this.redisHelper.findOrCreate(data)

// Return the book
return bookToReturn
}
Expand All @@ -61,50 +64,31 @@ export default class BookShowHelper {
return this.commonHelpers.checkIfRecentlyUpdated(this.originalBook)
}

/**
* Update the timestamps of the book when they are missing
*/
async updateBookTimestamps(): Promise<Book> {
// Return if not present or already has timestamps
if (!this.originalBook || this.originalBook.createdAt)
return (await this.paprHelper.findOneWithProjection()).data

// Add timestamps
this.paprHelper.bookData = addTimestamps(this.originalBook) as BookDocument
// Update book in DB
try {
this.bookInternal = (await this.paprHelper.update()).data
} catch (err) {
throw new Error(
`An error occurred while adding timestamps to book ${this.asin} in the DB. Try updating the book manually with 'update=1'.`
)
}
return this.bookInternal
}

/**
* Actions to run when an update is requested
*/
async updateActions(): Promise<Book> {
// 1. Check if it is updated recently
if (this.isUpdatedRecently()) return this.originalBook as Book
// if (this.isUpdatedRecently()) return this.originalBook as Book

// 2. Get the new book and create or update it
const bookToReturn = await this.createOrUpdateBook()
if (!bookToReturn.data) throw new Error(`Book ${this.asin} not found`)
const data = bookToReturn.data as BookDocument

// 3. Update book in cache
if (bookToReturn.modified) {
this.redisHelper.setOne(bookToReturn.data)
this.redisHelper.setOne(data)
}

// 4. Seed authors in the background
if (this.options.seedAuthors !== '0' && bookToReturn.modified) {
const authorSeeder = new SeedHelper(bookToReturn.data)
const authorSeeder = new SeedHelper(data)
authorSeeder.seedAll()
}

// 5. Return the book
return bookToReturn.data
return data
}

/**
Expand All @@ -119,13 +103,15 @@ export default class BookShowHelper {
if (this.options.update === '1') {
return this.updateActions()
}
// 1. Make sure it has timestamps
await this.updateBookTimestamps()
// 1. Get the book with projections
const bookToReturn = await this.paprHelper.findOneWithProjection()
if (!bookToReturn.data) throw new Error(`Book ${this.asin} not found`)
const data = bookToReturn.data as BookDocument
// 2. Check it it is cached
const redisBook = await this.redisHelper.findOrCreate(this.originalBook)
const redisBook = await this.redisHelper.findOrCreate(data)
if (redisBook) return redisBook as Book
// 3. Return the book from DB
return this.originalBook as Book
return data
}

// If the book is not present
Expand Down
29 changes: 0 additions & 29 deletions tests/helpers/routes/BookShowHelper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ jest.mock('#helpers/database/papr/audible/PaprAudibleBookHelper')
jest.mock('#helpers/books/audible/StitchHelper')
jest.mock('#helpers/database/redis/RedisHelper')

import { BookDocument } from '#config/models/Book'
import BookShowHelper from '#helpers/routes/BookShowHelper'
import {
bookWithId,
bookWithoutProjection,
bookWithoutProjectionUpdatedNow,
parsedBook
Expand Down Expand Up @@ -51,19 +49,6 @@ describe('BookShowHelper should', () => {
})
})

test('update book with timestamps returns original book', async () => {
helper.originalBook = bookWithoutProjection
await expect(helper.updateBookTimestamps()).resolves.toBe(bookWithoutProjection)
})

test('update book without timestamps returns updated book', async () => {
helper.originalBook = bookWithId() as BookDocument
jest
.spyOn(helper.paprHelper, 'update')
.mockResolvedValue({ data: bookWithoutProjection, modified: true })
await expect(helper.updateBookTimestamps()).resolves.toBe(bookWithoutProjection)
})

test('returns original book if it was updated recently when trying to update', async () => {
helper.originalBook = bookWithoutProjectionUpdatedNow
await expect(helper.updateActions()).resolves.toBe(bookWithoutProjectionUpdatedNow)
Expand Down Expand Up @@ -104,17 +89,3 @@ describe('BookShowHelper should', () => {
await expect(helper.handler()).resolves.toBe(bookWithoutProjection)
})
})

describe('BookShowHelper should throw an error when', () => {
test('adding timestamps to a book fails', async () => {
helper.originalBook = bookWithId() as BookDocument
jest
.spyOn(helper.paprHelper, 'update')
.mockRejectedValue(
new Error(`An error occurred while adding timestamps to book ${asin} in the DB. Try updating the book manually with 'update=1'.`)
)
await expect(helper.updateBookTimestamps()).rejects.toThrowError(
`An error occurred while adding timestamps to book ${asin} in the DB. Try updating the book manually with 'update=1'.`
)
})
})

0 comments on commit abde31d

Please sign in to comment.