Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Concurrency updates and database logging APIs #775

Merged
merged 6 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
version: 2
enable-beta-ecosystems: true
updates:
- package-ecosystem: "github-actions"
directory: "/"
Expand All @@ -11,14 +10,3 @@ updates:
dependencies:
patterns:
- "*"
- package-ecosystem: "swift"
directory: "/"
schedule:
interval: "daily"
open-pull-requests-limit: 6
allow:
- dependency-type: all
groups:
all-dependencies:
patterns:
- "*"
10 changes: 2 additions & 8 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ let package = Package(
.library(name: "Fluent", targets: ["Fluent"]),
],
dependencies: [
.package(url: "https://github.com/vapor/fluent-kit.git", from: "1.48.0"),
.package(url: "https://github.com/vapor/vapor.git", from: "4.94.1"),
.package(url: "https://github.com/vapor/fluent-kit.git", from: "1.48.4"),
.package(url: "https://github.com/vapor/vapor.git", from: "4.101.0"),
],
targets: [
.target(
Expand All @@ -40,10 +40,4 @@ let package = Package(
var swiftSettings: [SwiftSetting] { [
.enableUpcomingFeature("ConciseMagicFile"),
.enableUpcomingFeature("ForwardTrailingClosures"),
.enableUpcomingFeature("ImportObjcForwardDeclarations"),
.enableUpcomingFeature("DisableOutwardActorInference"),
.enableUpcomingFeature("IsolatedDefaultValues"),
.enableUpcomingFeature("GlobalConcurrency"),
.enableUpcomingFeature("StrictConcurrency"),
.enableExperimentalFeature("StrictConcurrency=complete"),
] }
7 changes: 2 additions & 5 deletions [email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ let package = Package(
.library(name: "Fluent", targets: ["Fluent"]),
],
dependencies: [
.package(url: "https://github.com/vapor/fluent-kit.git", from: "1.48.0"),
.package(url: "https://github.com/vapor/vapor.git", from: "4.94.1"),
.package(url: "https://github.com/vapor/fluent-kit.git", from: "1.48.4"),
.package(url: "https://github.com/vapor/vapor.git", from: "4.101.0"),
],
targets: [
.target(
Expand Down Expand Up @@ -43,8 +43,5 @@ var swiftSettings: [SwiftSetting] { [
.enableUpcomingFeature("ForwardTrailingClosures"),
.enableUpcomingFeature("ImportObjcForwardDeclarations"),
.enableUpcomingFeature("DisableOutwardActorInference"),
.enableUpcomingFeature("IsolatedDefaultValues"),
.enableUpcomingFeature("GlobalConcurrency"),
.enableUpcomingFeature("StrictConcurrency"),
.enableExperimentalFeature("StrictConcurrency=complete"),
] }
95 changes: 50 additions & 45 deletions Sources/Fluent/FluentProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,20 @@ extension Request {
}

public func db(_ id: DatabaseID?) -> any Database {
self.application
.databases
.database(
id,
logger: self.logger,
on: self.eventLoop,
history: self.fluent.history.historyEnabled ? self.fluent.history.history : nil,
pageSizeLimit: self.fluent.pagination.pageSizeLimit != nil ? self.fluent.pagination.pageSizeLimit?.value : self.application.fluent.pagination.pageSizeLimit
)!
self.db(id, logger: self.logger)
}

public func db(_ id: DatabaseID?, logger: Logger) -> any Database {
self.application.databases.database(
id,
logger: logger,
on: self.eventLoop,
history: self.fluent.history.historyEnabled ? self.fluent.history.history : nil,
// Use map() (not flatMap()) so if pageSizeLimit is non-nil but the value is nil
// the request's "no limit" setting overrides the app's setting.
pageSizeLimit: self.fluent.pagination.pageSizeLimit.map(\.value) ??
self.application.fluent.pagination.pageSizeLimit
)!
}

public var fluent: Fluent {
Expand All @@ -34,14 +39,17 @@ extension Application {
}

public func db(_ id: DatabaseID?) -> any Database {
self.databases
.database(
id,
logger: self.logger,
on: self.eventLoopGroup.any(),
history: self.fluent.history.historyEnabled ? self.fluent.history.history : nil,
pageSizeLimit: self.fluent.pagination.pageSizeLimit
)!
self.db(id, logger: self.logger)
}

public func db(_ id: DatabaseID?, logger: Logger) -> any Database {
self.databases.database(
id,
logger: logger,
on: self.eventLoopGroup.any(),
history: self.fluent.history.historyEnabled ? self.fluent.history.history : nil,
pageSizeLimit: self.fluent.pagination.pageSizeLimit
)!
}

public var databases: Databases {
Expand All @@ -53,7 +61,7 @@ extension Application {
}

public var migrator: Migrator {
Migrator(
.init(
databases: self.databases,
migrations: self.migrations,
logger: self.logger,
Expand Down Expand Up @@ -85,10 +93,7 @@ extension Application {
let migrationLogLevel: NIOLockedValueBox<Logger.Level>

init(threadPool: NIOThreadPool, on eventLoopGroup: any EventLoopGroup, migrationLogLevel: Logger.Level) {
self.databases = Databases(
threadPool: threadPool,
on: eventLoopGroup
)
self.databases = Databases(threadPool: threadPool, on: eventLoopGroup)
self.migrations = .init()
self.migrationLogLevel = .init(migrationLogLevel)
}
Expand All @@ -99,25 +104,35 @@ extension Application {
}

struct Lifecycle: LifecycleHandler {
func willBoot(_ application: Application) throws {
struct Signature: CommandSignature {
@Flag(name: "auto-migrate", help: "If true, Fluent will automatically migrate your database on boot")
var autoMigrate: Bool

@Flag(name: "auto-revert", help: "If true, Fluent will automatically revert your database on boot")
var autoRevert: Bool
struct Signature: CommandSignature {
@Flag(name: "auto-migrate", help: "If true, Fluent will automatically migrate your database on boot")
var autoMigrate: Bool

init() {}
}
@Flag(name: "auto-revert", help: "If true, Fluent will automatically revert your database on boot")
var autoRevert: Bool
}

func willBoot(_ application: Application) throws {
let signature = try Signature(from: &application.environment.commandInput)

if signature.autoRevert {
try application.autoRevert().wait()
}
if signature.autoMigrate {
try application.autoMigrate().wait()
}
}

func willBootAsync(_ application: Application) async throws {
let signature = try Signature(from: &application.environment.commandInput)

if signature.autoRevert {
try await application.autoRevert()
}
if signature.autoMigrate {
try await application.autoMigrate()
}
}

func shutdown(_ application: Application) {
application.databases.shutdown()
Expand Down Expand Up @@ -148,21 +163,11 @@ extension Application {
nonmutating set { self.storage.migrationLogLevel.withLockedValue { $0 = newValue } }
}

public var history: History {
.init(fluent: self)
}

public struct History {
let fluent: Fluent
}
public struct History { let fluent: Fluent }
public var history: History { .init(fluent: self) }

public var pagination: Pagination {
.init(fluent: self)
}

public struct Pagination {
let fluent: Fluent
}
public struct Pagination { let fluent: Fluent }
public var pagination: Pagination { .init(fluent: self) }
}

public var fluent: Fluent {
Expand Down
20 changes: 6 additions & 14 deletions Sources/Fluent/MigrateCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,12 @@ public final class MigrateCommand: AsyncCommand {

private func revert(using context: CommandContext) async throws {
let migrations = try await context.application.migrator.previewRevertLastBatch().get()
guard migrations.count > 0 else {
context.console.print("No migrations to revert.")
return
guard !migrations.isEmpty else {
return context.console.print("No migrations to revert.")
}
context.console.print("The following migration(s) will be reverted:")
for (migration, dbid) in migrations {
context.console.print("- ", newLine: false)
context.console.error(migration.name, newLine: false)
context.console.print(" on ", newLine: false)
context.console.print(dbid?.string ?? "default")
context.console.output("- \(migration.name, color: .red) on \(dbid?.string ?? "<default>", style: .info)")
}
if context.console.confirm("Would you like to continue?".consoleText(.warning)) {
try await context.application.migrator.revertLastBatch().get()
Expand All @@ -51,16 +47,12 @@ public final class MigrateCommand: AsyncCommand {

private func prepare(using context: CommandContext) async throws {
let migrations = try await context.application.migrator.previewPrepareBatch().get()
guard migrations.count > 0 else {
context.console.print("No new migrations.")
return
guard !migrations.isEmpty else {
return context.console.print("No new migrations.")
}
context.console.print("The following migration(s) will be prepared:")
for (migration, dbid) in migrations {
context.console.print("+ ", newLine: false)
context.console.success(migration.name, newLine: false)
context.console.print(" on ", newLine: false)
context.console.print(dbid?.string ?? "default")
context.console.output("+ \(migration.name, color: .green) on \(dbid?.string ?? "<default>", style: .info)")
}
if context.console.confirm("Would you like to continue?".consoleText(.warning)) {
try await context.application.migrator.prepareBatch().get()
Expand Down
40 changes: 21 additions & 19 deletions Tests/FluentTests/CacheTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,34 @@ import Fluent
import Vapor

final class CacheTests: XCTestCase {
var app: Application!

override func setUp() async throws {
self.app = try await Application.make(.testing)
}

override func tearDown() async throws {
try await self.app.asyncShutdown()
self.app = nil
}

func testCacheMigrationName() {
XCTAssertEqual(CacheEntry.migration.name, "Fluent.CacheEntry.Create")
}

func testCacheGet() async throws {
let app = Application(.testing)
defer { app.shutdown() }

// Setup test db.
let test = ArrayTestDatabase()
app.databases.use(test.configuration, as: .test)
app.migrations.add(CacheEntry.migration)
self.app.databases.use(test.configuration, as: .test)
self.app.migrations.add(CacheEntry.migration)

// Configure cache.
app.caches.use(.fluent)
self.app.caches.use(.fluent)

// simulate cache miss
test.append([])
do {
let foo = try await app.cache.get("foo", as: String.self)
let foo = try await self.app.cache.get("foo", as: String.self)
XCTAssertNil(foo)
}

Expand All @@ -33,15 +41,12 @@ final class CacheTests: XCTestCase {
"value": "\"bar\""
])])
do {
let foo = try await app.cache.get("foo", as: String.self)
let foo = try await self.app.cache.get("foo", as: String.self)
XCTAssertEqual(foo, "bar")
}
}

func testCacheSet() async throws {
let app = Application(.testing)
defer { app.shutdown() }

// Setup test db.
let test = CallbackTestDatabase { query in
switch query.input[0] {
Expand All @@ -51,19 +56,16 @@ final class CacheTests: XCTestCase {
XCTAssertEqual(value, "\"bar\"")
default: XCTFail("unexpected value")
}

default: XCTFail("unexpected input")
}
return [
TestOutput(["id": UUID()])
]
return [TestOutput(["id": UUID()])]
}
app.databases.use(test.configuration, as: .test)
app.migrations.add(CacheEntry.migration)
self.app.databases.use(test.configuration, as: .test)
self.app.migrations.add(CacheEntry.migration)

// Configure cache.
app.caches.use(.fluent)
self.app.caches.use(.fluent)

try await app.cache.set("foo", to: "bar")
try await self.app.cache.set("foo", to: "bar")
}
}
Loading