diff --git a/Package.swift b/Package.swift
index 6f6e922..d546ba8 100644
--- a/Package.swift
+++ b/Package.swift
@@ -1,24 +1,17 @@
-// swift-tools-version:4.0
+// swift-tools-version:5.0
import PackageDescription
let package = Package(
- name: "FluentPostgreSQL",
+ name: "fluent-postgres-driver",
products: [
- // Swift ORM for PostgreSQL (built on top of Fluent ORM framework)
- .library(name: "FluentPostgreSQL", targets: ["FluentPostgreSQL"]),
+ .library(name: "FluentPostgresDriver", targets: ["FluentPostgresDriver"]),
],
dependencies: [
- // 🌎 Utility package containing tools for byte manipulation, Codable, OS APIs, and debugging.
- .package(url: "https://github.com/vapor/core.git", from: "3.0.0"),
-
- // Swift ORM framework (queries, models, and relations) for building NoSQL and SQL database integrations.
- .package(url: "https://github.com/vapor/fluent.git", from: "3.0.0"),
-
- // 🐘 Non-blocking, event-driven Swift client for PostgreSQL.
- .package(url: "https://github.com/vapor/postgresql.git", from: "1.0.0"),
+ .package(url: "https://github.com/vapor/fluent-kit.git", .branch("master")),
+ .package(url: "https://github.com/vapor/postgresql.git", .branch("master")),
],
targets: [
- .target(name: "FluentPostgreSQL", dependencies: ["Async", "FluentSQL", "PostgreSQL"]),
- .testTarget(name: "FluentPostgreSQLTests", dependencies: ["FluentBenchmark", "FluentPostgreSQL"]),
+ .target(name: "FluentPostgresDriver", dependencies: ["FluentKit", "FluentSQL", "PostgresKit"]),
+ .testTarget(name: "FluentPostgresDriverTests", dependencies: ["FluentBenchmark", "FluentPostgresDriver"]),
]
)
diff --git a/README.md b/README.md
index acd1243..4e63d78 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,6 @@
-
+
diff --git a/Sources/FluentPostgreSQL/Deprecated.swift b/Sources/FluentPostgreSQL/Deprecated.swift
deleted file mode 100644
index 637118d..0000000
--- a/Sources/FluentPostgreSQL/Deprecated.swift
+++ /dev/null
@@ -1 +0,0 @@
-/// Nothing here yet...
diff --git a/Sources/FluentPostgreSQL/Exports.swift b/Sources/FluentPostgreSQL/Exports.swift
deleted file mode 100644
index ad305f2..0000000
--- a/Sources/FluentPostgreSQL/Exports.swift
+++ /dev/null
@@ -1,2 +0,0 @@
-@_exported import FluentSQL
-@_exported import PostgreSQL
diff --git a/Sources/FluentPostgreSQL/Fluent+PostgreSQLUpsert.swift b/Sources/FluentPostgreSQL/Fluent+PostgreSQLUpsert.swift
deleted file mode 100644
index 15a1b81..0000000
--- a/Sources/FluentPostgreSQL/Fluent+PostgreSQLUpsert.swift
+++ /dev/null
@@ -1,21 +0,0 @@
-extension _PostgreSQLModel {
- /// Creates the model or updates it depending on whether a model with the same ID already exists.
- public func create(orUpdate: Bool, on conn: DatabaseConnectable) -> Future {
- return Self.query(on: conn).create(orUpdate: orUpdate, self)
- }
-}
-
-extension QueryBuilder where Result: _PostgreSQLModel, Result.Database == Database {
- /// Creates the model or updates it depending on whether a model with the same ID already exists.
- public func create(orUpdate: Bool, _ model: Result) -> Future {
- if orUpdate {
- let row = SQLQueryEncoder(PostgreSQLExpression.self).encode(model)
- let values = row.map { row -> (PostgreSQLIdentifier, PostgreSQLExpression) in
- return (.identifier(row.key), row.value)
- }
- self.query.upsert = .upsert([.keyPath(Result.idKey)], values)
- }
- return create(model)
- }
-
-}
diff --git a/Sources/FluentPostgreSQL/FluentPostgreSQLProvider.swift b/Sources/FluentPostgreSQL/FluentPostgreSQLProvider.swift
deleted file mode 100644
index d7eda61..0000000
--- a/Sources/FluentPostgreSQL/FluentPostgreSQLProvider.swift
+++ /dev/null
@@ -1,52 +0,0 @@
-/// Adds Fluent PostgreSQL's services to your project.
-public final class FluentPostgreSQLProvider: Provider {
- /// Creates a new `FluentPostgreSQLProvider`
- ///
- /// - enableIdentityColumns: If true, `GENERATED BY DEFAULT AS IDENTITY` will be used.
- /// `true` by default.
- public init(enableIdentityColumns: Bool? = nil) {
- if let enableIdentityColumns = enableIdentityColumns {
- _globalEnableIdentityColumns = enableIdentityColumns
- }
- }
-
- /// See `Provider`.
- public func register(_ services: inout Services) throws {
- try services.register(FluentProvider())
- try services.register(PostgreSQLProvider())
- }
-
- /// See `Provider`.
- public func willBoot(_ worker: Container) throws -> Future {
-
- return worker.withPooledConnection(to: .psql) { conn in
- return FluentPostgreSQLProvider._setup(on: conn)
- }
- }
-
- public static func _setup(on conn: PostgreSQLConnection) -> Future {
- struct Setting: Codable {
- var version: String
- }
- return conn.select().column(.function("current_setting", [.expression(.literal(.string("server_version")))], as: .identifier("version"))).all(decoding: Setting.self).map { rows in
- _serverVersion = rows[0].version
- if let versionString = _serverVersion {
- let pointIndex = versionString.index(of: ".") ?? versionString.endIndex
- let majorVersion = versionString[.. Future {
- return .done(on: worker)
- }
-}
-
-/// server version string
-internal var _serverVersion: String?
-/// Enabled by default
-internal var _globalEnableIdentityColumns: Bool = true
diff --git a/Sources/FluentPostgreSQL/FluentPostgreSQLQuery.swift b/Sources/FluentPostgreSQL/FluentPostgreSQLQuery.swift
deleted file mode 100644
index 12bbd90..0000000
--- a/Sources/FluentPostgreSQL/FluentPostgreSQLQuery.swift
+++ /dev/null
@@ -1,59 +0,0 @@
-public enum FluentPostgreSQLQueryStatement: FluentSQLQueryStatement {
- public static var insert: FluentPostgreSQLQueryStatement { return ._insert }
- public static var select: FluentPostgreSQLQueryStatement { return ._select }
- public static var update: FluentPostgreSQLQueryStatement { return ._update }
- public static var delete: FluentPostgreSQLQueryStatement { return ._delete }
-
- public var isInsert: Bool {
- switch self {
- case ._insert: return true
- default: return false
- }
- }
-
- case _insert
- case _select
- case _update
- case _delete
-}
-
-public struct FluentPostgreSQLQuery: FluentSQLQuery {
- public typealias Statement = FluentPostgreSQLQueryStatement
- public typealias TableIdentifier = PostgreSQLTableIdentifier
- public typealias Expression = PostgreSQLExpression
- public typealias SelectExpression = PostgreSQLSelectExpression
- public typealias Join = PostgreSQLJoin
- public typealias OrderBy = PostgreSQLOrderBy
- public typealias GroupBy = PostgreSQLGroupBy
- public typealias Upsert = PostgreSQLUpsert
-
- public var statement: Statement
- public var table: TableIdentifier
- public var keys: [SelectExpression]
- public var values: [String : Expression]
- public var joins: [Join]
- public var predicate: Expression?
- public var orderBy: [OrderBy]
- public var groupBy: [GroupBy]
- public var limit: Int?
- public var offset: Int?
- public var upsert: PostgreSQLUpsert?
- public var defaultBinaryOperator: PostgreSQLBinaryOperator
-
- public static func query(_ statement: Statement, _ table: TableIdentifier) -> FluentPostgreSQLQuery {
- return .init(
- statement: statement,
- table: table,
- keys: [],
- values: [:],
- joins: [],
- predicate: nil,
- orderBy: [],
- groupBy: [],
- limit: nil,
- offset: nil,
- upsert: nil,
- defaultBinaryOperator: .and
- )
- }
-}
diff --git a/Sources/FluentPostgreSQL/FluentPostgreSQLSchema.swift b/Sources/FluentPostgreSQL/FluentPostgreSQLSchema.swift
deleted file mode 100644
index 08d51fe..0000000
--- a/Sources/FluentPostgreSQL/FluentPostgreSQLSchema.swift
+++ /dev/null
@@ -1,34 +0,0 @@
-public enum FluentPostgreSQLSchemaStatement: FluentSQLSchemaStatement {
- public static var createTable: FluentPostgreSQLSchemaStatement { return ._createTable }
- public static var alterTable: FluentPostgreSQLSchemaStatement { return ._alterTable }
- public static var dropTable: FluentPostgreSQLSchemaStatement { return ._dropTable }
-
- case _createTable
- case _alterTable
- case _dropTable
-}
-
-public struct FluentPostgreSQLSchema: FluentSQLSchema {
- public typealias Statement = FluentPostgreSQLSchemaStatement
- public typealias TableIdentifier = PostgreSQLTableIdentifier
- public typealias ColumnDefinition = PostgreSQLColumnDefinition
- public typealias TableConstraint = PostgreSQLTableConstraint
-
- public var statement: Statement
- public var table: TableIdentifier
- public var columns: [PostgreSQLColumnDefinition]
- public var deleteColumns: [PostgreSQLColumnIdentifier]
- public var constraints: [PostgreSQLTableConstraint]
- public var deleteConstraints: [PostgreSQLTableConstraint]
-
- public static func schema(_ statement: Statement, _ table: TableIdentifier) -> FluentPostgreSQLSchema {
- return .init(
- statement: statement,
- table: table,
- columns: [],
- deleteColumns: [],
- constraints: [],
- deleteConstraints: []
- )
- }
-}
diff --git a/Sources/FluentPostgreSQL/PostgreSQLDatabase+JoinSupporting.swift b/Sources/FluentPostgreSQL/PostgreSQLDatabase+JoinSupporting.swift
deleted file mode 100644
index adaff3c..0000000
--- a/Sources/FluentPostgreSQL/PostgreSQLDatabase+JoinSupporting.swift
+++ /dev/null
@@ -1,7 +0,0 @@
-extension PostgreSQLDatabase: JoinSupporting {
- /// See `SQLDatabase`.
- public typealias QueryJoin = PostgreSQLJoin
-
- /// See `SQLDatabase`.
- public typealias QueryJoinMethod = PostgreSQLJoinMethod
-}
diff --git a/Sources/FluentPostgreSQL/PostgreSQLDatabase+KeyedCacheSupporting.swift b/Sources/FluentPostgreSQL/PostgreSQLDatabase+KeyedCacheSupporting.swift
deleted file mode 100644
index 5fef645..0000000
--- a/Sources/FluentPostgreSQL/PostgreSQLDatabase+KeyedCacheSupporting.swift
+++ /dev/null
@@ -1 +0,0 @@
-extension PostgreSQLDatabase: KeyedCacheSupporting { }
diff --git a/Sources/FluentPostgreSQL/PostgreSQLDatabase+MigrationSupporting.swift b/Sources/FluentPostgreSQL/PostgreSQLDatabase+MigrationSupporting.swift
deleted file mode 100644
index 9c01d7e..0000000
--- a/Sources/FluentPostgreSQL/PostgreSQLDatabase+MigrationSupporting.swift
+++ /dev/null
@@ -1 +0,0 @@
-extension PostgreSQLDatabase: MigrationSupporting { }
diff --git a/Sources/FluentPostgreSQL/PostgreSQLDatabase+QuerySupporting.swift b/Sources/FluentPostgreSQL/PostgreSQLDatabase+QuerySupporting.swift
deleted file mode 100644
index 41ac665..0000000
--- a/Sources/FluentPostgreSQL/PostgreSQLDatabase+QuerySupporting.swift
+++ /dev/null
@@ -1,118 +0,0 @@
-/// Adds ability to do basic Fluent queries using a `PostgreSQLDatabase`.
-extension PostgreSQLDatabase: QuerySupporting {
- /// See `SQLDatabase`.
- public typealias Query = FluentPostgreSQLQuery
-
- /// See `SQLDatabase`.
- public typealias Output = [PostgreSQLColumn: PostgreSQLData]
-
- /// See `SQLDatabase`.
- public typealias QueryAction = FluentPostgreSQLQueryStatement
-
- /// See `SQLDatabase`.
- public typealias QueryAggregate = String
-
- /// See `SQLDatabase`.
- public typealias QueryData = [String: PostgreSQLExpression]
-
- /// See `SQLDatabase`.
- public typealias QueryField = PostgreSQLColumnIdentifier
-
- /// See `SQLDatabase`.
- public typealias QueryFilterMethod = PostgreSQLBinaryOperator
-
- /// See `SQLDatabase`.
- public typealias QueryFilterValue = PostgreSQLExpression
-
- /// See `SQLDatabase`.
- public typealias QueryFilter = PostgreSQLExpression
-
- /// See `SQLDatabase`.
- public typealias QueryFilterRelation = PostgreSQLBinaryOperator
-
- /// See `SQLDatabase`.
- public typealias QueryKey = PostgreSQLSelectExpression
-
- /// See `SQLDatabase`.
- public typealias QuerySort = PostgreSQLOrderBy
-
- /// See `SQLDatabase`.
- public typealias QuerySortDirection = PostgreSQLDirection
-
- /// See `SQLDatabase`.
- public static func queryExecute(
- _ fluent: FluentPostgreSQLQuery,
- on conn: PostgreSQLConnection,
- into handler: @escaping ([PostgreSQLColumn: PostgreSQLData], PostgreSQLConnection) throws -> ()
- ) -> Future {
- let query: PostgreSQLQuery
- switch fluent.statement {
- case ._insert:
- var insert: PostgreSQLInsert = .insert(fluent.table)
- var values: [PostgreSQLExpression] = []
- fluent.values.forEach { row in
- // filter out all `NULL` values, no need to insert them since
- // they could override default values that we want to keep
- switch row.value {
- case ._literal(let literal):
- switch literal {
- case ._null: return
- default: break
- }
- default: break
- }
- insert.columns.append(.column(nil, .identifier(row.key)))
- values.append(row.value)
- }
- insert.values.append(values)
- insert.upsert = fluent.upsert
- insert.returning.append(.all)
- query = .insert(insert)
- case ._select:
- var select: PostgreSQLSelect = .select()
- select.columns = fluent.keys.isEmpty ? [.all] : fluent.keys
- select.tables = [fluent.table]
- select.joins = fluent.joins
- select.predicate = fluent.predicate
- select.orderBy = fluent.orderBy
- select.groupBy = fluent.groupBy
- select.limit = fluent.limit
- select.offset = fluent.offset
- query = .select(select)
- case ._update:
- var update: PostgreSQLUpdate = .update(fluent.table)
- update.table = fluent.table
- update.values = fluent.values.map { val in
- return (.identifier(val.key), val.value)
- }
- update.predicate = fluent.predicate
- query = .update(update)
- case ._delete:
- var delete: PostgreSQLDelete = .delete(fluent.table)
- delete.predicate = fluent.predicate
- query = .delete(delete)
- }
- return conn.query(query) { try handler($0, conn) }
- }
-
- struct InsertMetadata: Codable where ID: Codable {
- var lastval: ID
- }
-
- /// See `QuerySupporting`.
- public static func modelEvent(event: ModelEvent, model: M, on conn: PostgreSQLConnection) -> Future
- where PostgreSQLDatabase == M.Database, M: Model
- {
- switch event {
- case .willCreate:
- if M.ID.self == UUID.self, model.fluentID == nil {
- var model = model
- model.fluentID = UUID() as? M.ID
- return conn.future(model)
- }
- default: break
- }
-
- return conn.future(model)
- }
-}
diff --git a/Sources/FluentPostgreSQL/PostgreSQLDatabase+SchemaSupporting.swift b/Sources/FluentPostgreSQL/PostgreSQLDatabase+SchemaSupporting.swift
deleted file mode 100644
index 1efec61..0000000
--- a/Sources/FluentPostgreSQL/PostgreSQLDatabase+SchemaSupporting.swift
+++ /dev/null
@@ -1,132 +0,0 @@
-extension PostgreSQLDatabase: SQLConstraintIdentifierNormalizer {
- /// See `SQLConstraintIdentifierNormalizer`.
- public static func normalizeSQLConstraintIdentifier(_ identifier: String) -> String {
- return identifier
- }
-}
-
-extension PostgreSQLDatabase: SchemaSupporting {
- /// See `SchemaSupporting`.
- public typealias Schema = FluentPostgreSQLSchema
-
- /// See `SchemaSupporting`.
- public typealias SchemaAction = FluentPostgreSQLSchemaStatement
-
- /// See `SchemaSupporting`.
- public typealias SchemaField = PostgreSQLColumnDefinition
-
- /// See `SchemaSupporting`.
- public typealias SchemaFieldType = PostgreSQLDataType
-
- /// See `SchemaSupporting`.
- public typealias SchemaConstraint = PostgreSQLTableConstraint
-
- /// See `SchemaSupporting`.
- public typealias SchemaReferenceAction = PostgreSQLForeignKeyAction
-
- /// See `SchemaSupporting`.
- public static func schemaExecute(_ fluent: FluentPostgreSQLSchema, on conn: PostgreSQLConnection) -> Future {
- let query: PostgreSQLQuery
- switch fluent.statement {
- case ._createTable:
- var createTable: PostgreSQLCreateTable = .createTable(fluent.table)
- createTable.columns = fluent.columns
- createTable.tableConstraints = fluent.constraints
- query = ._createTable(createTable)
- case ._alterTable:
- var alterTable: PostgreSQLAlterTable = .alterTable(fluent.table)
- alterTable.columns = fluent.columns
- alterTable.constraints = fluent.constraints
- alterTable.dropActions += fluent.deleteColumns.map { .init(.column, $0.identifier) }
- alterTable.dropActions += fluent.deleteConstraints.map {
- guard let id = $0.identifier else {
- fatalError("Cannot drop constraint without identifier: \($0).")
- }
- return .init(.constraint, id)
- }
- query = ._alterTable(alterTable)
- case ._dropTable:
- let dropTable: PostgreSQLDropTable = .dropTable(fluent.table)
- query = ._dropTable(dropTable)
- }
- return conn.query(query).transform(to: ())
- }
-
- /// See `SchemaSupporting`.
- public static func schemaField(for type: Any.Type, isIdentifier: Bool, _ column: PostgreSQLColumnIdentifier) -> PostgreSQLColumnDefinition {
- var constraints: [PostgreSQLColumnConstraint] = []
- var dataType: PostgreSQLDataType
-
- var type = type
- if let optional = type as? AnyOptionalType.Type {
- type = optional.anyWrappedType
- if isIdentifier {
- constraints.append(.notNull)
- }
- } else {
- constraints.append(.notNull)
- }
-
- let isArray: Bool
- if let array = type as? AnyArray.Type {
- type = array.anyElementType
- isArray = true
- } else {
- isArray = false
- }
-
- if let type = type as? PostgreSQLDataTypeStaticRepresentable.Type {
- dataType = type.postgreSQLDataType
- } else {
- dataType = .jsonb
- }
-
- if isIdentifier {
- let pkDefault: PostgreSQLPrimaryKeyDefault?
- // create a unique name for the primary key since it will be added
- // as a separate index.
- let unique: String
- if let table = column.table {
- unique = table.identifier.string + "." + column.identifier.string
- } else {
- unique = column.identifier.string
- }
- if _globalEnableIdentityColumns {
- switch dataType {
- case .smallint, .integer, .bigint:
- pkDefault = .generated(.byDefault)
- default:
- pkDefault = nil
- }
- } else {
- pkDefault = nil
- switch dataType {
- case .smallint: dataType = .smallserial
- case .integer: dataType = .serial
- case .bigint: dataType = .bigserial
- default: break
- }
- }
- constraints.append(.primaryKey(default: pkDefault, identifier: .identifier("pk:\(unique)")))
- }
-
- if isArray {
- dataType = .array(dataType)
- }
-
- return .columnDefinition(column, dataType, constraints)
- }
-
- /// See `SchemaSupporting`.
- public static func enableReferences(on connection: PostgreSQLConnection) -> Future {
- // enabled by default
- return .done(on: connection)
- }
-
- /// See `SchemaSupporting`.
- public static func disableReferences(on connection: PostgreSQLConnection) -> Future {
- return Future.map(on: connection) {
- throw PostgreSQLError(identifier: "disableReferences", reason: "PostgreSQL does not support disabling foreign key checks.")
- }
- }
-}
diff --git a/Sources/FluentPostgreSQL/PostgreSQLDatabase+TransactionSupporting.swift b/Sources/FluentPostgreSQL/PostgreSQLDatabase+TransactionSupporting.swift
deleted file mode 100644
index 86a7a6a..0000000
--- a/Sources/FluentPostgreSQL/PostgreSQLDatabase+TransactionSupporting.swift
+++ /dev/null
@@ -1,14 +0,0 @@
-extension PostgreSQLDatabase: TransactionSupporting {
- /// See `TransactionSupporting`.
- public static func transactionExecute(_ transaction: @escaping (PostgreSQLConnection) throws -> Future, on connection: PostgreSQLConnection) -> Future {
- return connection.simpleQuery("BEGIN TRANSACTION").flatMap { results in
- return try transaction(connection).flatMap { res in
- return connection.simpleQuery("END TRANSACTION").transform(to: res)
- }.catchFlatMap { error in
- return connection.simpleQuery("ROLLBACK").map { results in
- throw error
- }
- }
- }
- }
-}
diff --git a/Sources/FluentPostgreSQL/PostgreSQLEnum.swift b/Sources/FluentPostgreSQL/PostgreSQLEnum.swift
deleted file mode 100644
index 4de34a9..0000000
--- a/Sources/FluentPostgreSQL/PostgreSQLEnum.swift
+++ /dev/null
@@ -1,63 +0,0 @@
-public protocol PostgreSQLEnum: PostgreSQLExpressionRepresentable, CaseIterable, Codable, ReflectionDecodable, PostgreSQLDataTypeStaticRepresentable, RawRepresentable where Self.RawValue: LosslessStringConvertible {
- static var postgreSQLEnumTypeName: String { get }
-}
-
-public protocol PostgreSQLRawEnum: RawRepresentable, Codable, CaseIterable, ReflectionDecodable, PostgreSQLDataTypeStaticRepresentable { }
-
-extension PostgreSQLRawEnum where Self.RawValue: PostgreSQLDataTypeStaticRepresentable {
- /// See `PostgreSQLDataTypeStaticRepresentable`.
- public static var postgreSQLDataType: PostgreSQLDataType {
- return RawValue.postgreSQLDataType
- }
-}
-
-extension PostgreSQLEnum {
- /// See `PostgreSQLEnum`.
- public static var postgreSQLEnumTypeName: String {
- return String(reflecting: self)
- .components(separatedBy: ".")
- .dropFirst()
- .joined(separator: "_")
- // TODO: Determine if this should actually be uppercased.
- // The PostgreSQL documentation for the ENUM type always
- // shows this name being lowercased.
- .uppercased()
- }
-
- /// See `PostgreSQLDataTypeStaticRepresentable`.
- public static var postgreSQLDataType: PostgreSQLDataType {
- return .custom(postgreSQLEnumTypeName)
- }
-
- /// See `PostgreSQLExpressionRepresentable`.
- public var postgreSQLExpression: PostgreSQLExpression {
- return .literal(.string(rawValue.description))
- }
-}
-
-extension PostgreSQLEnum where Self: PostgreSQLMigration {
- /// See `PostgreSQLMigration`.
- public static func prepare(on conn: PostgreSQLConnection) -> Future {
- return PostgreSQLDatabase.create(enum: self, on: conn)
- }
-
- /// See `PostgreSQLMigration`.
- public static func revert(on conn: PostgreSQLConnection) -> Future {
- return PostgreSQLDatabase.drop(enum: self, on: conn)
- }
-}
-
-extension PostgreSQLDatabase {
- public static func create(enum: E.Type, on conn: PostgreSQLConnection) -> Future where E: PostgreSQLEnum {
- let cases = E.allCases.map { "'" + $0.rawValue.description + "'" }.joined(separator: ", ")
- return conn.simpleQuery("CREATE TYPE \(E.postgreSQLEnumTypeName) AS ENUM (\(cases))")
- }
-
- public static func alter(enum: E.Type, add value: E, on conn: PostgreSQLConnection) -> Future where E: PostgreSQLEnum {
- return conn.simpleQuery("ALTER TYPE \(E.postgreSQLEnumTypeName) ADD VALUE '\(value.rawValue.description)'")
- }
-
- public static func drop(enum: E.Type, on conn: PostgreSQLConnection) -> Future where E: PostgreSQLEnum {
- return conn.simpleQuery("DROP TYPE \(E.postgreSQLEnumTypeName)")
- }
-}
diff --git a/Sources/FluentPostgreSQL/PostgreSQLModel.swift b/Sources/FluentPostgreSQL/PostgreSQLModel.swift
deleted file mode 100644
index 4827f89..0000000
--- a/Sources/FluentPostgreSQL/PostgreSQLModel.swift
+++ /dev/null
@@ -1,22 +0,0 @@
-public protocol _PostgreSQLModel: Model, PostgreSQLTable where Self.Database == PostgreSQLDatabase { }
-
-extension _PostgreSQLModel {
- /// See `SQLTable`.
- public static var sqlTableIdentifierString: String {
- return entity
- }
-}
-
-public protocol PostgreSQLModel: _PostgreSQLModel where Self.ID == Int {
- /// This model's unique identifier.
- var id: Int? { get set }
-}
-
-extension PostgreSQLModel {
- /// See `Model`.
- public static var idKey: IDKey { return \.id }
-}
-
-public protocol PostgreSQLPivot: Pivot, PostgreSQLModel { }
-
-public protocol PostgreSQLMigration: Migration where Self.Database == PostgreSQLDatabase { }
diff --git a/Sources/FluentPostgreSQL/PostgreSQLStringModel.swift b/Sources/FluentPostgreSQL/PostgreSQLStringModel.swift
deleted file mode 100644
index d0d2d51..0000000
--- a/Sources/FluentPostgreSQL/PostgreSQLStringModel.swift
+++ /dev/null
@@ -1,11 +0,0 @@
-public protocol PostgreSQLStringModel: _PostgreSQLModel where Self.ID == String {
- /// This model's unique identifier.
- var id: String? { get set }
-}
-
-extension PostgreSQLStringModel {
- /// See `Model.idKey`
- public static var idKey: IDKey { return \.id }
-}
-
-public protocol PostgreSQLStringPivot: Pivot, PostgreSQLStringModel { }
diff --git a/Sources/FluentPostgreSQL/PostgreSQLUUIDModel.swift b/Sources/FluentPostgreSQL/PostgreSQLUUIDModel.swift
deleted file mode 100644
index 6451a5f..0000000
--- a/Sources/FluentPostgreSQL/PostgreSQLUUIDModel.swift
+++ /dev/null
@@ -1,11 +0,0 @@
-public protocol PostgreSQLUUIDModel: _PostgreSQLModel where Self.ID == UUID {
- /// This model's unique identifier.
- var id: UUID? { get set }
-}
-
-extension PostgreSQLUUIDModel {
- /// See `Model.idKey`
- public static var idKey: IDKey { return \.id }
-}
-
-public protocol PostgreSQLUUIDPivot: Pivot, PostgreSQLUUIDModel { }
diff --git a/Sources/FluentPostgreSQL/Utilities.swift b/Sources/FluentPostgreSQL/Utilities.swift
deleted file mode 100644
index dcf9330..0000000
--- a/Sources/FluentPostgreSQL/Utilities.swift
+++ /dev/null
@@ -1,9 +0,0 @@
-protocol AnyArray {
- static var anyElementType: Any.Type { get }
-}
-
-extension Array: AnyArray {
- static var anyElementType: Any.Type {
- return Element.self
- }
-}
diff --git a/Sources/FluentPostgresDriver/Exports.swift b/Sources/FluentPostgresDriver/Exports.swift
new file mode 100644
index 0000000..78f2012
--- /dev/null
+++ b/Sources/FluentPostgresDriver/Exports.swift
@@ -0,0 +1,2 @@
+@_exported import FluentKit
+@_exported import PostgresKit
diff --git a/Sources/FluentPostgresDriver/Postgres+Fluent.swift b/Sources/FluentPostgresDriver/Postgres+Fluent.swift
new file mode 100644
index 0000000..442bf54
--- /dev/null
+++ b/Sources/FluentPostgresDriver/Postgres+Fluent.swift
@@ -0,0 +1,69 @@
+import FluentSQL
+
+extension PostgresConnection: FluentDatabase {
+ public func execute(_ query: FluentQuery, _ onOutput: @escaping (FluentOutput) throws -> ()) -> EventLoopFuture {
+ return FluentSQLDatabase(delegate: PostgresConnectionSQLDelegate(self))
+ .execute(query, onOutput)
+ }
+
+ public func execute(_ schema: FluentSchema) -> EventLoopFuture {
+ return FluentSQLDatabase(delegate: PostgresConnectionSQLDelegate(self))
+ .execute(schema)
+ }
+}
+
+extension ConnectionPool: FluentDatabase where Source.Connection: FluentDatabase {
+ public var eventLoop: EventLoop {
+ return self.source.eventLoop
+ }
+
+ public func execute(_ query: FluentQuery, _ onOutput: @escaping (FluentOutput) throws -> ()) -> EventLoopFuture {
+ return self.withConnection { conn in
+ return conn.execute(query, onOutput)
+ }
+ }
+
+ public func execute(_ schema: FluentSchema) -> EventLoopFuture {
+ return self.withConnection { conn in
+ return conn.execute(schema)
+ }
+ }
+}
+
+
+private struct PostgresConnectionSQLDelegate: FluentSQLDatabaseDelegate {
+ var eventLoop: EventLoop {
+ return self.connection.eventLoop
+ }
+
+ let connection: PostgresConnection
+
+ var database: SQLDatabase {
+ return self.connection
+ }
+
+ init(_ connection: PostgresConnection) {
+ self.connection = connection
+ }
+
+ func convert(_ fluent: FluentQuery, _ sql: SQLExpression) -> SQLExpression {
+ switch fluent.action {
+ case .create:
+ return PostgresReturning(sql)
+ default:
+ return sql
+ }
+ }
+}
+
+private struct PostgresReturning: SQLExpression {
+ let base: SQLExpression
+ init(_ base: SQLExpression) {
+ self.base = base
+ }
+
+ func serialize(to serializer: inout SQLSerializer) {
+ self.base.serialize(to: &serializer)
+ serializer.write(" RETURNING *")
+ }
+}
diff --git a/Tests/FluentPostgreSQLTests/FluentPostgreSQLTests.swift b/Tests/FluentPostgreSQLTests/FluentPostgreSQLTests.swift
deleted file mode 100644
index ec44c86..0000000
--- a/Tests/FluentPostgreSQLTests/FluentPostgreSQLTests.swift
+++ /dev/null
@@ -1,611 +0,0 @@
-import Async
-import Core
-import XCTest
-import FluentBenchmark
-import FluentPostgreSQL
-import Fluent
-import Foundation
-
-class FluentPostgreSQLTests: XCTestCase {
- var benchmarker: Benchmarker!
- var database: PostgreSQLDatabase!
-
- override func setUp() {
- #if os(macOS)
- let hostname = "localhost"
- #else
- let hostname = "psql"
- #endif
-
- let config: PostgreSQLDatabaseConfig = .init(
- hostname: hostname,
- port: 5432,
- username: "vapor_username",
- database: "vapor_database",
- password: "vapor_password"
- )
- database = PostgreSQLDatabase(config: config)
- let eventLoop = MultiThreadedEventLoopGroup(numberOfThreads: 1)
- benchmarker = try! Benchmarker(database, on: eventLoop, onFail: XCTFail)
- let conn = try! benchmarker.pool.requestConnection().wait()
- defer { benchmarker.pool.releaseConnection(conn) }
- try! FluentPostgreSQLProvider._setup(on: conn).wait()
- }
-
- func testBenchmark() throws {
- try benchmarker.runAll()
- }
-
- func testNestedStruct() throws {
- let conn = try benchmarker.pool.requestConnection().wait()
- try? User.revert(on: conn).wait()
- try User.prepare(on: conn).wait()
- var user = User(id: nil, name: "Tanner", pet: Pet(name: "Zizek"))
- user.favoriteColors = ["pink", "blue"]
- user = try user.save(on: conn).wait()
- if let fetched = try User.query(on: conn).first().wait() {
- XCTAssertEqual(user.id, fetched.id)
- XCTAssertNil(user.age)
- XCTAssertEqual(fetched.favoriteColors, ["pink", "blue"])
- } else {
- XCTFail()
- }
- try User.revert(on: conn).wait()
- benchmarker.pool.releaseConnection(conn)
- }
-
- func testMinimumViableModelDeclaration() throws {
- /// NOTE: these must never fail to build
- struct Foo: PostgreSQLModel {
- var id: Int?
- var name: String
- }
- final class Bar: PostgreSQLModel {
- var id: Int?
- var name: String
- }
- struct Baz: PostgreSQLUUIDModel {
- var id: UUID?
- var name: String
- }
- final class Qux: PostgreSQLUUIDModel {
- var id: UUID?
- var name: String
- }
- }
-
-// func testDefaultValue() throws {
-// let conn = try benchmarker.pool.requestConnection().wait()
-// defer { try? DefaultTest.revert(on: conn).wait() }
-// try DefaultTest.prepare(on: conn).wait()
-// let test = DefaultTest()
-// // _ = try test.save(on: conn).await(on: eventLoop)
-// let builder = test.query(on: conn)
-// builder.query.data = try ["foo": "bar".convertToPostgreSQLData()] // there _must_ be a better way
-// builder.query.action = .create
-// try builder.run().wait()
-// if let fetched = try DefaultTest.query(on: conn).first().wait() {
-// XCTAssertNotNil(fetched.date?.value)
-// } else {
-// XCTFail()
-// }
-// benchmarker.pool.releaseConnection(conn)
-// }
-
-
- func testUpdate() throws {
- let conn = try benchmarker.pool.requestConnection().wait()
- defer { try? User.revert(on: conn).wait() }
- try User.prepare(on: conn).wait()
- let user = User(id: nil, name: "Tanner", pet: Pet(name: "Zizek"))
- user.favoriteColors = ["pink", "blue"]
- _ = try user.save(on: conn).wait()
- try User.query(on: conn).update(data: ["name": "Vapor"]).wait()
- benchmarker.pool.releaseConnection(conn)
- }
-
- func testGH24() throws {
- let conn = try benchmarker.pool.requestConnection().wait()
- defer { try? Allergy.revert(on: conn).wait() }
- try Allergy.prepare(on: conn).wait()
- struct Allergy: PostgreSQLModel, Migration {
- static let entity = "allergies"
- var id: Int?
- }
- _ = try Allergy(id: 2).create(on: conn).wait()
- _ = try Allergy(id: 4).create(on: conn).wait()
- let stuff = try Allergy.query(on: conn).filter(\.id ~~ [1, 2, 3]).all().wait()
- XCTAssertEqual(stuff.count, 1)
- XCTAssertEqual(stuff.first?.id, 2)
- }
-
- func testGH21() throws {
- /// - types
- enum PetType: Int, CaseIterable, ReflectionDecodable, Codable {
- static let allCases: [PetType] = [.cat, .dog]
- case cat = 0
- case dog = 1
- }
- struct Pet: PostgreSQLModel, Migration {
- static let entity = "pets"
- var id: Int?
- var type: PetType
- var name: String
-
- static func prepare(on conn: PostgreSQLConnection) -> EventLoopFuture {
- return PostgreSQLDatabase.create(Pet.self, on: conn) { builder in
- builder.field(for: \.id)
- builder.field(for: \.type, type: .bigint)
- builder.field(for: \.name, type: .text)
- }
- }
- }
-
- try print(Pet.reflectProperties())
-
- /// - prepare db
- let conn = try benchmarker.pool.requestConnection().wait()
- defer { try? Pet.revert(on: conn).wait() }
- try Pet.prepare(on: conn).wait()
-
- /// - tests
- _ = try Pet(id: nil, type: .cat, name: "Ziz").save(on: conn).wait()
- _ = try Pet(id: nil, type: .dog, name: "Spud").save(on: conn).wait()
- let cats = try Pet.query(on: conn).filter(\.type == .cat).all().wait()
- let dogs = try Pet.query(on: conn).filter(\.type == .dog).all().wait()
- XCTAssertEqual(cats.count, 1)
- XCTAssertEqual(cats.first?.name, "Ziz")
- XCTAssertEqual(dogs.count, 1)
- XCTAssertEqual(dogs.first?.name, "Spud")
- }
-
- func testPersistsDateMillisecondPart() throws {
- struct DefaultTest: PostgreSQLModel, Migration {
- var id: Int?
- var date: Date?
- var foo: String
- init() {
- self.id = nil
- self.date = nil
- self.foo = "bar"
- }
- static func prepare(on conn: PostgreSQLConnection) -> EventLoopFuture {
- return PostgreSQLDatabase.create(DefaultTest.self, on: conn) { builder in
- builder.field(for: \.id, isIdentifier: true)
- builder.field(for: \.date, type: .timestamp, .default(.literal(.numeric("current_timestamp"))))
- builder.field(for: \.foo)
- }
- }
- }
-
- let conn = try benchmarker.pool.requestConnection().wait()
- defer { try? DefaultTest.revert(on: conn).wait() }
- try DefaultTest.prepare(on: conn).wait()
- _ = try DefaultTest().save(on: conn).wait()
- let fetched = try DefaultTest.query(on: conn).first().wait()!
- // within 1 minute
- XCTAssertEqual(Date().timeIntervalSinceReferenceDate, fetched.date!.timeIntervalSinceReferenceDate, accuracy: 60)
- }
-
- func testGH30() throws {
- /// - types
- struct Foo: PostgreSQLModel, Migration {
- static let entity = "foos"
- var id: Int?
- var location: PostgreSQLPoint?
- }
-
- /// - prepare db
- let conn = try benchmarker.pool.requestConnection().wait()
- defer { try? Foo.revert(on: conn).wait() }
- try Foo.prepare(on: conn).wait()
-
- /// - tests
- var foo = Foo(id: nil, location: PostgreSQLPoint(x: 1, y: 3.14))
- foo = try foo.save(on: conn).wait()
- foo = try Foo.find(foo.requireID(), on: conn).wait()!
- XCTAssertEqual(foo.location?.x, 1)
- XCTAssertEqual(foo.location?.y, 3.14)
- }
-
- // https://github.com/vapor/fluent-postgresql/issues/32
- func testURL() throws {
- struct User: PostgreSQLModel, Migration {
- static let entity = "users"
- var id: Int?
- var name: String
- var website: URL
- }
- let conn = try benchmarker.pool.requestConnection().wait()
- defer { benchmarker.pool.releaseConnection(conn) }
-
- try User.prepare(on: conn).wait()
- defer { try! User.revert(on: conn).wait() }
-
- var user = User(id: nil, name: "Tanner", website: URL(string: "http://tanner.xyz")!)
- user = try user.save(on: conn).wait()
-
- let fetched = try User.find(1, on: conn).wait()
- XCTAssertEqual(fetched?.website.absoluteString, "http://tanner.xyz")
- }
-
- func testDocs_type() throws {
- enum PlanetType: String, PostgreSQLEnum, PostgreSQLMigration {
- static let postgreSQLEnumTypeName = "PLANET_TYPE"
- static let allCases: [PlanetType] = [.smallRocky, .gasGiant, .dwarf]
- case smallRocky
- case gasGiant
- case dwarf
- }
-
- struct Planet: PostgreSQLModel, PostgreSQLMigration {
- var id: Int?
- let name: String
- let type: PlanetType
- let test: String?
-
- static func prepare(on conn: PostgreSQLConnection) -> Future {
- return PostgreSQLDatabase.create(Planet.self, on: conn) { builder in
- builder.field(for: \.id)
- builder.field(for: \.name, type: .varchar(64))
- builder.field(for: \.type)
- }
- }
- }
-
- let conn = try benchmarker.pool.requestConnection().wait()
- defer { benchmarker.pool.releaseConnection(conn) }
-
- try PlanetType.prepare(on: conn).wait()
- // try PostgreSQLDatabase.alter(enum: PlanetType.self, add: .dwarf, on: conn).wait()
- defer { try? PlanetType.revert(on: conn).wait() }
- try Planet.prepare(on: conn).wait()
- defer { try? Planet.revert(on: conn).wait() }
-
- let rows = try Planet.query(on: conn).filter(\.type == .gasGiant).all().wait()
- XCTAssertEqual(rows.count, 0)
-
- try PostgreSQLDatabase.update(Planet.self, on: conn) { builder in
- builder.field(for: \.test)
- }.wait()
- }
-
- func testContains() throws {
- struct User: PostgreSQLModel, PostgreSQLMigration {
- var id: Int?
- var name: String
- var age: Int
- }
- let conn = try benchmarker.pool.requestConnection().wait()
- defer { benchmarker.pool.releaseConnection(conn) }
-
- try User.prepare(on: conn).wait()
- defer { try! User.revert(on: conn).wait() }
-
- // create
- let tanner1 = User(id: nil, name: "tanner", age: 23)
- _ = try tanner1.save(on: conn).wait()
- let tanner2 = User(id: nil, name: "ner", age: 23)
- _ = try tanner2.save(on: conn).wait()
- let tanner3 = User(id: nil, name: "tan", age: 23)
- _ = try tanner3.save(on: conn).wait()
-
- let tas = try User.query(on: conn).filter(\.name, .like, "ta%").count().wait()
- if tas != 2 {
- XCTFail("tas == \(tas)")
- }
- let ers = try User.query(on: conn).filter(\.name, .like, "%er").count().wait()
- if ers != 2 {
- XCTFail("ers == \(tas)")
- }
- let annes = try User.query(on: conn).filter(\.name ~~ "anne").count().wait()
- if annes != 1 {
- XCTFail("annes == \(tas)")
- }
- let ns = try User.query(on: conn).filter(\.name ~~ "n").count().wait()
- if ns != 3 {
- XCTFail("ns == \(tas)")
- }
-
- let nertan = try User.query(on: conn).filter(\.name ~~ ["ner", "tan"]).count().wait()
- if nertan != 2 {
- XCTFail("nertan == \(tas)")
- }
-
- let notner = try User.query(on: conn).filter(\.name !~ ["ner"]).count().wait()
- if notner != 2 {
- XCTFail("nertan == \(tas)")
- }
- }
-
- func testEmptySubset() throws {
- struct User: PostgreSQLModel, PostgreSQLMigration {
- var id: Int?
- }
- let conn = try benchmarker.pool.requestConnection().wait()
- defer { benchmarker.pool.releaseConnection(conn) }
- try User.prepare(on: conn).wait()
- defer { _ = try? User.revert(on: conn).wait() }
-
- let res = try User.query(on: conn).filter(\.id ~~ []).all().wait()
- XCTAssertEqual(res.count, 0)
- _ = try User.query(on: conn).filter(\.id ~~ [1]).all().wait()
- _ = try User.query(on: conn).filter(\.id ~~ [1, 2]).all().wait()
- _ = try User.query(on: conn).filter(\.id ~~ [1, 2, 3]).all().wait()
- }
-
- func testSort() throws {
- let conn = try benchmarker.pool.requestConnection().wait()
- defer { benchmarker.pool.releaseConnection(conn) }
- try Planet.prepare(on: conn).wait()
- defer { _ = try? Planet.revert(on: conn).wait() }
-
- _ = try Planet(name: "Jupiter").save(on: conn).wait()
- _ = try Planet(name: "Earth").save(on: conn).wait()
- _ = try Planet(name: "Mars").save(on: conn).wait()
-
- let unordered = try Planet.query(on: conn).all().wait()
- let ordered = try Planet.query(on: conn).sort(\.name).all().wait()
- XCTAssertNotEqual(unordered, ordered)
- }
-
- func testCustomFilter() throws {
- let conn = try benchmarker.pool.requestConnection().wait()
- defer { benchmarker.pool.releaseConnection(conn) }
- try Planet.prepare(on: conn).wait()
- defer { _ = try? Planet.revert(on: conn).wait() }
-
- _ = try Planet(name: "Jupiter").save(on: conn).wait()
- _ = try Planet(name: "Earth").save(on: conn).wait()
- _ = try Planet(name: "Mars").save(on: conn).wait()
-
- let earth = try Planet.query(on: conn).filter(\.name, .ilike, "earth").first().wait()
- XCTAssertEqual(earth?.name, "Earth")
- }
-
- func testCreateOrUpdate() throws {
- let conn = try benchmarker.pool.requestConnection().wait()
- defer { benchmarker.pool.releaseConnection(conn) }
- defer { try? Planet.revert(on: conn).wait() }
- try Planet.prepare(on: conn).wait()
-
- let a = Planet(id: 1, name: "Mars")
- let b = Planet(id: 1, name: "Earth")
-
- _ = try a.create(orUpdate: true, on: conn).wait()
- _ = try b.create(orUpdate: true, on: conn).wait()
-
- let c = try Planet.find(1, on: conn).wait()
- XCTAssertEqual(c?.name, "Earth")
- }
-
- func testEnumArray() throws {
- enum A: Int16, Codable, CaseIterable, ReflectionDecodable {
- static var allCases: [A] = [.a, .b, .c]
- case a, b, c
- }
- struct B: PostgreSQLModel, PostgreSQLMigration {
- var id: Int?
- var a: [A]
-
- static func prepare(on conn: PostgreSQLConnection) -> Future {
- return PostgreSQLDatabase.create(B.self, on: conn) { builder in
- builder.field(for: \.id, isIdentifier: true)
- builder.field(for: \.a, type: .array(.int2), .notNull)
- }
- }
- }
-
- let conn = try benchmarker.pool.requestConnection().wait()
- conn.logger = DatabaseLogger(database: .psql, handler: PrintLogHandler())
- defer { benchmarker.pool.releaseConnection(conn) }
- defer { try? B.revert(on: conn).wait() }
- try B.prepare(on: conn).wait()
-
- let b = try B(id: nil, a: [.a, .b, .c]).save(on: conn).wait()
- XCTAssertEqual(b.id, 1)
- }
-
- func testAlterDrop() throws {
- struct A: PostgreSQLMigration {
- static func prepare(on conn: PostgreSQLConnection) -> Future {
- return PostgreSQLDatabase.create(Planet.self, on: conn) { builder in
- builder.field(for: \.id)
- }
- }
-
- static func revert(on conn: PostgreSQLConnection) -> Future {
- return PostgreSQLDatabase.delete(Planet.self, on: conn)
- }
- }
- struct B: PostgreSQLMigration {
- static func prepare(on conn: PostgreSQLConnection) -> Future {
- return PostgreSQLDatabase.update(Planet.self, on: conn) { builder in
- builder.field(for: \.name)
- builder.deleteField(for: \.id)
- }
- }
-
- static func revert(on conn: PostgreSQLConnection) -> Future {
- return PostgreSQLDatabase.update(Planet.self, on: conn) { builder in
- builder.deleteField(for: \.name)
- builder.field(for: \.id)
- }
- }
- }
- struct C: PostgreSQLMigration {
- static func prepare(on conn: PostgreSQLConnection) -> Future {
- return PostgreSQLDatabase.update(Planet.self, on: conn) { builder in
- builder.unique(on: \.name)
- }
- }
-
- static func revert(on conn: PostgreSQLConnection) -> Future {
- return PostgreSQLDatabase.update(Planet.self, on: conn) { builder in
- builder.deleteUnique(from: \.name)
- }
- }
- }
-
- let conn = try benchmarker.pool.requestConnection().wait()
- conn.logger = DatabaseLogger(database: .psql, handler: PrintLogHandler())
- defer { benchmarker.pool.releaseConnection(conn) }
-
- try A.prepare(on: conn).wait()
- defer { try? A.revert(on: conn).wait() }
- try B.prepare(on: conn).wait()
- defer { try? B.revert(on: conn).wait() }
- try C.prepare(on: conn).wait()
- defer { try? C.revert(on: conn).wait() }
- }
-
- // https://github.com/vapor/fluent-postgresql/issues/85
- func testGH85() throws {
- enum Availability: UInt8, PostgreSQLRawEnum {
- static var allCases: [Availability] = [.everyday, .sunday, .monday, .tuesday, .wednesday, .thursday, .friday, .saturday]
-
- case everyday
- case sunday
- case monday
- case tuesday
- case wednesday
- case thursday
- case friday
- case saturday
- }
-
- struct Foo: PostgreSQLModel, Migration {
- var id: Int?
- var availability: Availability
- }
-
- let conn = try benchmarker.pool.requestConnection().wait()
- conn.logger = DatabaseLogger(database: .psql, handler: PrintLogHandler())
- defer { benchmarker.pool.releaseConnection(conn) }
-
- try Foo.prepare(on: conn).wait()
- defer { try? Foo.revert(on: conn).wait() }
-
- let a = Foo(id: nil, availability: .everyday)
- _ = try a.save(on: conn).wait()
- }
-
- // https://github.com/vapor/fluent-postgresql/issues/35
- func testGH35() throws {
- struct Game: PostgreSQLModel, Migration {
- var id: Int?
- var tags: [Int64]?
- }
-
- let conn = try benchmarker.pool.requestConnection().wait()
- conn.logger = DatabaseLogger(database: .psql, handler: PrintLogHandler())
- defer { benchmarker.pool.releaseConnection(conn) }
-
- try Game.prepare(on: conn).wait()
- defer { try? Game.revert(on: conn).wait() }
-
- var a = Game(id: nil, tags: [1, 2, 3])
- a = try a.save(on: conn).wait()
- }
-
- // https://github.com/vapor/fluent-postgresql/issues/54
- func testGH54() throws {
- struct User: PostgreSQLModel, Migration {
- var id: Int?
- var username: String
- }
-
- struct AddUserIndex: PostgreSQLMigration {
- static func prepare(on conn: PostgreSQLConnection) -> Future {
- return Database.update(User.self, on: conn) { builder in
- builder.unique(on: \.username)
- }
- }
-
- static func revert(on conn: PostgreSQLConnection) -> Future {
- return Database.update(User.self, on: conn) { builder in
- builder.deleteUnique(from: \.username)
- }
- }
- }
-
- let conn = try benchmarker.pool.requestConnection().wait()
- conn.logger = DatabaseLogger(database: .psql, handler: PrintLogHandler())
- defer { benchmarker.pool.releaseConnection(conn) }
-
- try User.prepare(on: conn).wait()
- defer { try? User.revert(on: conn).wait() }
- try AddUserIndex.prepare(on: conn).wait()
- defer { try? AddUserIndex.revert(on: conn).wait() }
- }
-
- static let allTests = [
- ("testBenchmark", testBenchmark),
- ("testNestedStruct", testNestedStruct),
- ("testMinimumViableModelDeclaration", testMinimumViableModelDeclaration),
- ("testGH24", testGH24),
- ("testGH21", testGH21),
- ("testPersistsDateMillisecondPart", testPersistsDateMillisecondPart),
- ("testGH30", testGH30),
- ("testURL", testURL),
- ("testDocs_type", testDocs_type),
- ("testContains", testContains),
- ("testEmptySubset", testEmptySubset),
- ("testSort", testSort),
- ("testCustomFilter", testCustomFilter),
- ("testCreateOrUpdate", testCreateOrUpdate),
- ("testEnumArray", testEnumArray),
- ("testGH85", testGH85),
- ("testGH35", testGH35),
- ]
-}
-
-struct Planet: PostgreSQLModel, PostgreSQLMigration, Equatable {
- var id: Int?
- var name: String
- init(id: Int? = nil, name: String) {
- self.id = id
- self.name = name
- }
-}
-
-extension PostgreSQLDataType {
- static var planetType: PostgreSQLDataType {
- return .custom("PLANET_TYPE")
- }
-}
-
-struct Pet: Codable {
- var name: String
-}
-
-final class User: PostgreSQLModel, Migration {
- static let idKey: WritableKeyPath = \User.id
- var id: Int?
- var name: String
- var age: Int?
- var favoriteColors: [String]
- var pet: Pet
-
- init(id: Int? = nil, name: String, pet: Pet) {
- self.favoriteColors = []
- self.id = id
- self.name = name
- self.pet = pet
- }
-}
-
-/// Adds a new field to `User`'s table.
-struct AddUsernameToUser: PostgreSQLMigration {
- static func prepare(on conn: PostgreSQLConnection) -> Future {
- return PostgreSQLDatabase.update(User.self, on: conn) { builder in
- builder.field(for: \.name)
- }
- }
-
- static func revert(on conn: PostgreSQLConnection) -> Future {
- return PostgreSQLDatabase.update(User.self, on: conn) { builder in
- builder.deleteField(for: \.name)
- }
- }
-}
diff --git a/Tests/FluentPostgresDriverTests/FluentPostgresDriverTests.swift b/Tests/FluentPostgresDriverTests/FluentPostgresDriverTests.swift
new file mode 100644
index 0000000..ae33131
--- /dev/null
+++ b/Tests/FluentPostgresDriverTests/FluentPostgresDriverTests.swift
@@ -0,0 +1,99 @@
+import FluentBenchmark
+import FluentPostgresDriver
+import XCTest
+
+final class FluentPostgresDriverTests: XCTestCase {
+ var benchmarker: FluentBenchmarker!
+
+ func testAll() throws {
+ try self.benchmarker.testAll()
+ }
+
+ func testCreate() throws {
+ try self.benchmarker.testCreate()
+ }
+
+ func testRead() throws {
+ try self.benchmarker.testRead()
+ }
+
+ func testUpdate() throws {
+ try self.benchmarker.testUpdate()
+ }
+
+ func testDelete() throws {
+ try self.benchmarker.testDelete()
+ }
+
+ func testEagerLoadChildren() throws {
+ try self.benchmarker.testEagerLoadChildren()
+ }
+
+ func testEagerLoadParent() throws {
+ try self.benchmarker.testEagerLoadParent()
+ }
+
+ func testEagerLoadParentJoin() throws {
+ try self.benchmarker.testEagerLoadParentJoin()
+ }
+
+ func testEagerLoadSubqueryJSONEncode() throws {
+ try self.benchmarker.testEagerLoadSubqueryJSONEncode()
+ }
+
+ func testEagerLoadJoinJSONEncode() throws {
+ try self.benchmarker.testEagerLoadJoinJSONEncode()
+ }
+
+ func testMigrator() throws {
+ try self.benchmarker.testMigrator()
+ }
+
+ func testMigratorError() throws {
+ try self.benchmarker.testMigratorError()
+ }
+
+ func testJoin() throws {
+ try self.benchmarker.testJoin()
+ }
+
+ func testBatchCreate() throws {
+ try self.benchmarker.testBatchCreate()
+ }
+
+ func testBatchUpdate() throws {
+ try self.benchmarker.testBatchUpdate()
+ }
+
+ func testNestedModel() throws {
+ try self.benchmarker.testNestedModel()
+ }
+//
+// func testWorkUnit() throws {
+// try self.benchmarker.testWorkUnit()
+// }
+
+ override func setUp() {
+ let eventLoop = MultiThreadedEventLoopGroup(numberOfThreads: 1).next()
+ let hostname: String
+ #if os(Linux)
+ hostname = "psql"
+ #else
+ hostname = "localhost"
+ #endif
+ let config = PostgresDatabase.Config(
+ hostname: hostname,
+ port: 5432,
+ username: "vapor_username",
+ password: "vapor_password",
+ database: "vapor_database",
+ tlsConfig: nil
+ )
+ let conn = try! PostgresDatabase(config: config, on: eventLoop).makeConnection().wait()
+ self.benchmarker = FluentBenchmarker(database: conn)
+ }
+
+ static let allTests = [
+ ("testAll", testAll),
+ ]
+}
diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift
index f34f628..fdd8105 100644
--- a/Tests/LinuxMain.swift
+++ b/Tests/LinuxMain.swift
@@ -1,6 +1,6 @@
import XCTest
-@testable import FluentPostgreSQLTests
+@testable import FluentPostgresDriverTests
XCTMain([
- testCase(FluentPostgreSQLTests.allTests),
+ testCase(FluentPostgresDriverTests.allTests),
])
diff --git a/circle.yml b/circle.yml
index b45cd10..eeb3ad0 100644
--- a/circle.yml
+++ b/circle.yml
@@ -1,17 +1,23 @@
version: 2
jobs:
- macos:
- macos:
- xcode: "9.2"
+ 11-linux:
+ docker:
+ - image: codevapor/swift:5.0
+ - image: circleci/postgres:11
+ name: psql
+ environment:
+ POSTGRES_USER: vapor_username
+ POSTGRES_DB: vapor_database
+ POSTGRES_PASSWORD: vapor_password
steps:
- checkout
- run: swift build
- run: swift test
- linux-10:
+ 10-linux:
docker:
- - image: codevapor/swift:4.1
- - image: circleci/postgres:latest
+ - image: codevapor/swift:5.0
+ - image: circleci/postgres:10
name: psql
environment:
POSTGRES_USER: vapor_username
@@ -19,15 +25,11 @@ jobs:
POSTGRES_PASSWORD: vapor_password
steps:
- checkout
- - run:
- name: Compile code
- command: swift build
- - run:
- name: Run unit tests
- command: swift test
- linux-9:
+ - run: swift build
+ - run: swift test
+ 9-linux:
docker:
- - image: codevapor/swift:4.1
+ - image: codevapor/swift:5.0
- image: circleci/postgres:9
name: psql
environment:
@@ -36,37 +38,20 @@ jobs:
POSTGRES_PASSWORD: vapor_password
steps:
- checkout
- - run:
- name: Compile code
- command: swift build
- - run:
- name: Run unit tests
- command: swift test
+ - run: swift build
+ - run: swift test
linux-release:
docker:
- - image: codevapor/swift:4.1
+ - image: codevapor/swift:5.0
steps:
- checkout
- - run:
- name: Compile code with optimizations
- command: swift build -c release
+ - run: swift build -c release
workflows:
version: 2
tests:
jobs:
- - linux-10
- - linux-9
+ - 11-linux
+ - 10-linux
+ - 9-linux
- linux-release
- # - macos
- nightly:
- triggers:
- - schedule:
- cron: "0 0 * * *"
- filters:
- branches:
- only:
- - master
- jobs:
- - linux
- # - macos
-
+