Skip to content

Commit

Permalink
Fix trending tags (#143)
Browse files Browse the repository at this point in the history
* Fix trending tags

* Fix tests build
  • Loading branch information
mczachurski authored Oct 14, 2024
1 parent d5da271 commit 79a9888
Show file tree
Hide file tree
Showing 14 changed files with 92 additions and 25 deletions.
4 changes: 4 additions & 0 deletions Sources/VernissageServer/Application+Configure.swift
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,10 @@ extension Application {
self.migrations.add(Exif.AddSoftware())
self.migrations.add(FeaturedUser.CreateFeaturedUsers())

self.migrations.add(TrendingHashtag.AddAmountField())
self.migrations.add(TrendingStatus.AddAmountField())
self.migrations.add(TrendingUser.AddAmountField())

try await self.autoMigrate()
}

Expand Down
6 changes: 3 additions & 3 deletions Sources/VernissageServer/Controllers/TrendingController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -349,9 +349,9 @@ struct TrendingController {
let baseAddress = request.application.settings.cached?.baseAddress ?? ""

let trending = try await trendingService.hashtags(on: request.db, linkableParams: linkableParams, period: period.translate())
let hashtagDtos = await trending.data.asyncMap({
HashtagDto(url: "\(baseAddress)/tags/\($0.hashtag)", name: $0.hashtag)
})
let hashtagDtos = await trending.data.asyncMap {
HashtagDto(url: "\(baseAddress)/tags/\($0.hashtag)", name: $0.hashtag, amount: $0.amount)
}

return LinkableResultDto(
maxId: trending.maxId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Vapor
struct HashtagDto {
var url: String
var name: String
var amount: Int?
}

extension HashtagDto: Content { }
16 changes: 16 additions & 0 deletions Sources/VernissageServer/Migrations/CreateTrendingHashtags.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,20 @@ extension TrendingHashtag {
try await database.schema(TrendingHashtag.schema).delete()
}
}

struct AddAmountField: AsyncMigration {
func prepare(on database: Database) async throws {
try await database
.schema(TrendingHashtag.schema)
.field("amount", .int, .required, .sql(.default(0)))
.update()
}

func revert(on database: Database) async throws {
try await database
.schema(TrendingHashtag.schema)
.deleteField("amount")
.update()
}
}
}
16 changes: 16 additions & 0 deletions Sources/VernissageServer/Migrations/CreateTrendingStatuses.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,20 @@ extension TrendingStatus {
try await database.schema(TrendingStatus.schema).delete()
}
}

struct AddAmountField: AsyncMigration {
func prepare(on database: Database) async throws {
try await database
.schema(TrendingStatus.schema)
.field("amount", .int, .required, .sql(.default(0)))
.update()
}

func revert(on database: Database) async throws {
try await database
.schema(TrendingStatus.schema)
.deleteField("amount")
.update()
}
}
}
16 changes: 16 additions & 0 deletions Sources/VernissageServer/Migrations/CreateTrendingUsers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,20 @@ extension TrendingUser {
try await database.schema(TrendingUser.schema).delete()
}
}

struct AddAmountField: AsyncMigration {
func prepare(on database: Database) async throws {
try await database
.schema(TrendingUser.schema)
.field("amount", .int, .required, .sql(.default(0)))
.update()
}

func revert(on database: Database) async throws {
try await database
.schema(TrendingUser.schema)
.deleteField("amount")
.update()
}
}
}
6 changes: 5 additions & 1 deletion Sources/VernissageServer/Models/TrendingHashtag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ final class TrendingHashtag: Model, @unchecked Sendable {
@Field(key: "hashtagNormalized")
var hashtagNormalized: String

@Field(key: "amount")
var amount: Int

@Timestamp(key: "createdAt", on: .create)
var createdAt: Date?

Expand All @@ -32,13 +35,14 @@ final class TrendingHashtag: Model, @unchecked Sendable {

init() { }

convenience init(id: Int64, trendingPeriod: TrendingPeriod, hashtag: String, hashtagNormalized: String) {
convenience init(id: Int64, trendingPeriod: TrendingPeriod, hashtag: String, hashtagNormalized: String, amount: Int) {
self.init()

self.id = id
self.trendingPeriod = trendingPeriod
self.hashtag = hashtag
self.hashtagNormalized = hashtagNormalized
self.amount = amount
}
}

Expand Down
6 changes: 5 additions & 1 deletion Sources/VernissageServer/Models/TrendingStatus.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ final class TrendingStatus: Model, @unchecked Sendable {

@Parent(key: "statusId")
var status: Status

@Field(key: "amount")
var amount: Int

@Timestamp(key: "createdAt", on: .create)
var createdAt: Date?
Expand All @@ -29,12 +32,13 @@ final class TrendingStatus: Model, @unchecked Sendable {

init() { }

convenience init(id: Int64, trendingPeriod: TrendingPeriod, statusId: Int64) {
convenience init(id: Int64, trendingPeriod: TrendingPeriod, statusId: Int64, amount: Int) {
self.init()

self.id = id
self.trendingPeriod = trendingPeriod
self.$status.id = statusId
self.amount = amount
}
}

Expand Down
6 changes: 5 additions & 1 deletion Sources/VernissageServer/Models/TrendingUser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ final class TrendingUser: Model, @unchecked Sendable {
@Parent(key: "userId")
var user: User

@Field(key: "amount")
var amount: Int

@Timestamp(key: "createdAt", on: .create)
var createdAt: Date?

Expand All @@ -29,12 +32,13 @@ final class TrendingUser: Model, @unchecked Sendable {

init() { }

convenience init(id: Int64, trendingPeriod: TrendingPeriod, userId: Int64) {
convenience init(id: Int64, trendingPeriod: TrendingPeriod, userId: Int64, amount: Int) {
self.init()

self.id = id
self.trendingPeriod = trendingPeriod
self.$user.id = userId
self.amount = amount
}
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/VernissageServer/Services/SearchService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ final class SearchService: SearchServiceType {

let baseAddress = request.application.settings.cached?.baseAddress ?? ""
let hashtagDtos = await hashtags.items.asyncMap { hashtag in
HashtagDto(url: "\(baseAddress)/tags/\(hashtag.hashtag)", name: hashtag.hashtag)
HashtagDto(url: "\(baseAddress)/tags/\(hashtag.hashtag)", name: hashtag.hashtag, amount: hashtag.amount)
}

return SearchResultDto(hashtags: hashtagDtos)
Expand Down
32 changes: 17 additions & 15 deletions Sources/VernissageServer/Services/TrendingService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,19 @@ final class TrendingService: TrendingServiceType {

try await dailyTrendingStatuses.reversed().asyncForEach { amount in
let newTrendingStatusId = context.application.services.snowflakeService.generate()
let item = TrendingStatus(id: newTrendingStatusId, trendingPeriod: .daily, statusId: amount.id)
let item = TrendingStatus(id: newTrendingStatusId, trendingPeriod: .daily, statusId: amount.id, amount: amount.amount)
try await item.create(on: database)
}

try await montlyTrendingStatuses.reversed().asyncForEach { amount in
let newTrendingStatusId = context.application.services.snowflakeService.generate()
let item = TrendingStatus(id: newTrendingStatusId, trendingPeriod: .monthly, statusId: amount.id)
let item = TrendingStatus(id: newTrendingStatusId, trendingPeriod: .monthly, statusId: amount.id, amount: amount.amount)
try await item.create(on: database)
}

try await yearlyTrendingStatuses.reversed().asyncForEach { amount in
let newTrendingStatusId = context.application.services.snowflakeService.generate()
let item = TrendingStatus(id: newTrendingStatusId, trendingPeriod: .yearly, statusId: amount.id)
let item = TrendingStatus(id: newTrendingStatusId, trendingPeriod: .yearly, statusId: amount.id, amount: amount.amount)
try await item.create(on: database)
}
}
Expand Down Expand Up @@ -104,19 +104,19 @@ final class TrendingService: TrendingServiceType {

try await dailyTrendingAccounts.reversed().asyncForEach { amount in
let newTrendingUserId = context.application.services.snowflakeService.generate()
let item = TrendingUser(id: newTrendingUserId, trendingPeriod: .daily, userId: amount.id)
let item = TrendingUser(id: newTrendingUserId, trendingPeriod: .daily, userId: amount.id, amount: amount.amount)
try await item.create(on: database)
}

try await montlyTrendingAccounts.reversed().asyncForEach { amount in
let newTrendingUserId = context.application.services.snowflakeService.generate()
let item = TrendingUser(id: newTrendingUserId, trendingPeriod: .monthly, userId: amount.id)
let item = TrendingUser(id: newTrendingUserId, trendingPeriod: .monthly, userId: amount.id, amount: amount.amount)
try await item.create(on: database)
}

try await yearlyTrendingAccounts.reversed().asyncForEach { amount in
let newTrendingUserId = context.application.services.snowflakeService.generate()
let item = TrendingUser(id: newTrendingUserId, trendingPeriod: .yearly, userId: amount.id)
let item = TrendingUser(id: newTrendingUserId, trendingPeriod: .yearly, userId: amount.id, amount: amount.amount)
try await item.create(on: database)
}
}
Expand Down Expand Up @@ -147,7 +147,8 @@ final class TrendingService: TrendingServiceType {
let item = TrendingHashtag(id: newTrendingHashtagId,
trendingPeriod: .daily,
hashtag: amount.hashtag,
hashtagNormalized: amount.hashtagNormalized)
hashtagNormalized: amount.hashtagNormalized,
amount: amount.amount)
try await item.create(on: database)
}

Expand All @@ -156,7 +157,8 @@ final class TrendingService: TrendingServiceType {
let item = TrendingHashtag(id: newTrendingHashtagId,
trendingPeriod: .monthly,
hashtag: amount.hashtag,
hashtagNormalized: amount.hashtagNormalized)
hashtagNormalized: amount.hashtagNormalized,
amount: amount.amount)
try await item.create(on: database)
}

Expand All @@ -165,7 +167,8 @@ final class TrendingService: TrendingServiceType {
let item = TrendingHashtag(id: newTrendingHashtagId,
trendingPeriod: .yearly,
hashtag: amount.hashtag,
hashtagNormalized: amount.hashtagNormalized)
hashtagNormalized: amount.hashtagNormalized,
amount: amount.amount)
try await item.create(on: database)
}
}
Expand Down Expand Up @@ -321,7 +324,7 @@ final class TrendingService: TrendingServiceType {
AND \(ident: "s").\(ident: "replyToStatusId") IS NULL
GROUP BY \(ident: "sf").\(ident: "statusId"), \(ident: "s").\(ident: "createdAt")
ORDER BY COUNT(\(ident: "sf").\(ident: "statusId")), \(ident: "s").\(ident: "createdAt") DESC
LIMIT 1000
LIMIT 10000
""").all(decoding: TrendingAmount.self)

return trendingAmounts
Expand All @@ -342,7 +345,7 @@ final class TrendingService: TrendingServiceType {
AND \(ident: "s").\(ident: "replyToStatusId") IS NULL
GROUP BY \(ident: "s").\(ident: "userId")
ORDER BY COUNT(\(ident: "s").\(ident: "userId")) DESC
LIMIT 1000
LIMIT 10000
""").all(decoding: TrendingAmount.self)

return trendingAmounts
Expand All @@ -356,16 +359,15 @@ final class TrendingService: TrendingServiceType {
\(ident: "st").\(ident: "hashtagNormalized") AS \(ident: "hashtagNormalized"),
(SELECT \(ident: "hashtag") FROM \(ident: StatusHashtag.schema) WHERE \(ident: "hashtagNormalized") = \(ident: "st").\(ident: "hashtagNormalized") LIMIT 1) AS \(ident: "hashtag"),
COUNT(\(ident: "st").\(ident: "hashtagNormalized")) AS \(ident: "amount")
FROM \(ident: StatusFavourite.schema) \(ident: "sf")
INNER JOIN \(ident: Status.schema) \(ident: "s") ON \(ident: "sf").\(ident: "statusId") = \(ident: "s").\(ident: "id")
FROM \(ident: Status.schema) \(ident: "s")
INNER JOIN \(ident: StatusHashtag.schema) \(ident: "st") ON \(ident: "st").\(ident: "statusId") = \(ident: "s").\(ident: "id")
WHERE
\(ident: "sf").\(ident: "createdAt") > \(bind: past)
\(ident: "s").\(ident: "createdAt") > \(bind: past)
AND \(ident: "s").\(ident: "reblogId") IS NULL
AND \(ident: "s").\(ident: "replyToStatusId") IS NULL
GROUP BY \(ident: "st").\(ident: "hashtagNormalized")
ORDER BY COUNT(\(ident: "st").\(ident: "hashtagNormalized")) DESC
LIMIT 1000
LIMIT 10000
""").all(decoding: TrendingHashtagAmount.self)

return trendingHashtag
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Fluent
extension Application {
func createTrendingHashtag(trendingPeriod: TrendingPeriod, hashtag: String) async throws {
let id = await ApplicationManager.shared.generateId()
let trendingHashtag = TrendingHashtag(id: id, trendingPeriod: trendingPeriod, hashtag: hashtag, hashtagNormalized: hashtag.uppercased())
let trendingHashtag = TrendingHashtag(id: id, trendingPeriod: trendingPeriod, hashtag: hashtag, hashtagNormalized: hashtag.uppercased(), amount: 1)
_ = try await trendingHashtag.save(on: self.db)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Fluent
extension Application {
func createTrendingStatus(trendingPeriod: TrendingPeriod, statusId: Int64) async throws {
let id = await ApplicationManager.shared.generateId()
let trendingStatus = TrendingStatus(id: id, trendingPeriod: trendingPeriod, statusId: statusId)
let trendingStatus = TrendingStatus(id: id, trendingPeriod: trendingPeriod, statusId: statusId, amount: 1)
_ = try await trendingStatus.save(on: self.db)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Fluent
extension Application {
func createTrendingUser(trendingPeriod: TrendingPeriod, userId: Int64) async throws {
let id = await ApplicationManager.shared.generateId()
let trendingUser = TrendingUser(id: id, trendingPeriod: trendingPeriod, userId: userId)
let trendingUser = TrendingUser(id: id, trendingPeriod: trendingPeriod, userId: userId, amount: 1)
_ = try await trendingUser.save(on: self.db)
}
}

0 comments on commit 79a9888

Please sign in to comment.