Skip to content

Commit 8828d56

Browse files
tanner0101gwynne
andauthored
FluentKit 1.0.0 GM (#152)
* fluentkit gm * Include the new benchmarker suites for this driver's tests * new tests * gm update, tests * cleanup * macos formatting * fix macos tests * env var rename * update ci config * env var fixes * rm nested * version update Co-authored-by: Gwynne Raskind <[email protected]>
1 parent 2bf6bf2 commit 8828d56

File tree

8 files changed

+170
-103
lines changed

8 files changed

+170
-103
lines changed

.github/workflows/test.yml

+49-37
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,70 @@
11
name: Test Matrix
2-
on: ['pull_request']
3-
defaults:
4-
run:
5-
shell: bash
2+
on:
3+
- pull_request
64
jobs:
7-
PR-tests-linux:
5+
linux:
86
strategy:
97
fail-fast: false
108
matrix:
11-
dbimage: ['postgres:11', 'postgres:12']
12-
runner: [
13-
'swift:5.2-xenial', 'swift:5.2-bionic',
14-
'swiftlang/swift:nightly-5.2-xenial', 'swiftlang/swift:nightly-5.2-bionic',
15-
'swiftlang/swift:nightly-5.3-xenial', 'swiftlang/swift:nightly-5.3-bionic',
16-
'swiftlang/swift:nightly-master-xenial', 'swiftlang/swift:nightly-master-bionic',
17-
'swiftlang/swift:nightly-master-focal',
18-
'swiftlang/swift:nightly-master-centos8',
19-
'swiftlang/swift:nightly-master-amazonlinux2'
20-
]
21-
include:
22-
- installcmd: 'apt-get -q update && apt-get -q install -y postgresql-client'
23-
- { 'runner': 'swiftlang/swift:nightly-master-centos8', 'installcmd': 'dnf install -y zlib-devel postgresql' }
24-
- { 'runner': 'swiftlang/swift:nightly-master-amazonlinux2', 'installcmd': 'yum install -y zlib-devel postgresql' }
9+
dbimage:
10+
- postgres:11
11+
- postgres:12
12+
runner:
13+
# 5.2 Stable
14+
- swift:5.2-xenial
15+
- swift:5.2-bionic
16+
# 5.2 Unstable
17+
- swiftlang/swift:nightly-5.2-xenial
18+
- swiftlang/swift:nightly-5.2-bionic
19+
# 5.3 Unstable
20+
- swiftlang/swift:nightly-5.3-xenial
21+
- swiftlang/swift:nightly-5.3-bionic
22+
# Master Unsable
23+
- swiftlang/swift:nightly-master-xenial
24+
- swiftlang/swift:nightly-master-bionic
25+
- swiftlang/swift:nightly-master-focal
26+
- swiftlang/swift:nightly-master-centos8
27+
- swiftlang/swift:nightly-master-amazonlinux2
2528
container: ${{ matrix.runner }}
2629
runs-on: ubuntu-latest
2730
services:
28-
postgres:
31+
postgres-a:
2932
image: ${{ matrix.dbimage }}
30-
env: { POSTGRES_USER: vapor_username, POSTGRES_PASSWORD: vapor_password, POSTGRES_DB: vapor_database }
31-
env: { 'PGPASSWORD': 'vapor_password' }
33+
env:
34+
POSTGRES_USER: vapor_username
35+
POSTGRES_PASSWORD: vapor_password
36+
POSTGRES_DB: vapor_database
37+
postgres-b:
38+
image: ${{ matrix.dbimage }}
39+
env:
40+
POSTGRES_USER: vapor_username
41+
POSTGRES_PASSWORD: vapor_password
42+
POSTGRES_DB: vapor_database
3243
steps:
33-
- name: Install dependencies
34-
run: ${{ matrix.installcmd }}
35-
- name: Wait for Postgres server to be ready
36-
run: until echo | psql -hpostgres -Uvapor_username vapor_database; do sleep 1; done
37-
timeout-minutes: 5
38-
- name: Set up Postgres databases and privileges
39-
run: |
40-
for db in vapor_migration_extra; do createdb -hpostgres -Uvapor_username -Ovapor_username $db; done
4144
- name: Check out code
4245
uses: actions/checkout@v2
4346
- name: Run tests with Thread Sanitizer
4447
run: swift test --enable-test-discovery --sanitize=thread
45-
env: { 'POSTGRES_HOSTNAME': 'postgres' }
46-
PR-tests-macos:
48+
env:
49+
POSTGRES_HOSTNAME_A: postgres-a
50+
POSTGRES_HOSTNAME_B: postgres-b
51+
macos:
4752
strategy:
4853
fail-fast: false
4954
matrix:
5055
include:
51-
- {'formula': 'postgresql@11', 'datadir': 'postgresql@11'}
52-
- {'formula': 'postgresql@12', 'datadir': 'postgres'}
56+
- formula: postgresql@11
57+
datadir: postgresql@11
58+
- formula: postgresql@12
59+
datadir: postgres
5360
runs-on: macos-latest
54-
env: { 'PGPASSWORD': 'vapor_password' }
61+
env:
62+
PGPASSWORD: vapor_password
5563
steps:
5664
- name: Select latest available Xcode
5765
uses: maxim-lobanov/[email protected]
58-
with: { 'xcode-version': 'latest' }
66+
with:
67+
xcode-version: latest
5968
- name: Blow away the default Postgres installation
6069
run: brew uninstall --force postgresql php && rm -rf /usr/local/{etc,var}/{postgres,pg}*
6170
- name: Install Postgres server from Homebrew
@@ -70,10 +79,13 @@ jobs:
7079
- name: Set up Postgres databases and privileges
7180
run: |
7281
createuser --createdb --login vapor_username
73-
for db in vapor_{database,migration_extra}; do
82+
for db in vapor_{database_a,database_b}; do
7483
createdb -Ovapor_username $db && psql $db <<<"ALTER SCHEMA public OWNER TO vapor_username;"
7584
done
7685
- name: Check out code
7786
uses: actions/checkout@v2
7887
- name: Run tests with Thread Sanitizer
7988
run: swift test --enable-test-discovery --sanitize=thread
89+
env:
90+
POSTGRES_DATABASE_A: vapor_database_a
91+
POSTGRES_DATABASE_B: vapor_database_b

Package.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ let package = Package(
1010
.library(name: "FluentPostgresDriver", targets: ["FluentPostgresDriver"]),
1111
],
1212
dependencies: [
13-
.package(url: "https://github.com/vapor/fluent-kit.git", from: "1.0.0-rc.1"),
13+
.package(url: "https://github.com/vapor/fluent-kit.git", from: "1.0.0-rc.2"),
1414
.package(url: "https://github.com/vapor/postgres-kit.git", from: "2.0.0"),
1515
],
1616
targets: [

Sources/FluentPostgresDriver/FluentPostgresDatabase.swift

+14-4
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import FluentSQL
33
struct _FluentPostgresDatabase {
44
let database: PostgresDatabase
55
let context: DatabaseContext
6-
76
let encoder: PostgresDataEncoder
87
let decoder: PostgresDataDecoder
8+
let inTransaction: Bool
99
}
1010

1111
extension _FluentPostgresDatabase: Database {
@@ -72,13 +72,17 @@ extension _FluentPostgresDatabase: Database {
7272
}
7373

7474
func transaction<T>(_ closure: @escaping (Database) -> EventLoopFuture<T>) -> EventLoopFuture<T> {
75-
self.database.withConnection { conn in
75+
guard !self.inTransaction else {
76+
return closure(self)
77+
}
78+
return self.database.withConnection { conn in
7679
conn.simpleQuery("BEGIN").flatMap { _ in
7780
let db = _FluentPostgresDatabase(
7881
database: conn,
7982
context: self.context,
8083
encoder: self.encoder,
81-
decoder: self.decoder
84+
decoder: self.decoder,
85+
inTransaction: true
8286
)
8387
return closure(db).flatMap { result in
8488
conn.simpleQuery("COMMIT").map { _ in
@@ -95,7 +99,13 @@ extension _FluentPostgresDatabase: Database {
9599

96100
func withConnection<T>(_ closure: @escaping (Database) -> EventLoopFuture<T>) -> EventLoopFuture<T> {
97101
self.database.withConnection {
98-
closure(_FluentPostgresDatabase(database: $0, context: self.context, encoder: self.encoder, decoder: self.decoder))
102+
closure(_FluentPostgresDatabase(
103+
database: $0,
104+
context: self.context,
105+
encoder: self.encoder,
106+
decoder: self.decoder,
107+
inTransaction: self.inTransaction
108+
))
99109
}
100110
}
101111
}

Sources/FluentPostgresDriver/FluentPostgresDriver.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ struct _FluentPostgresDriver: DatabaseDriver {
1616
database: self.pool.pool(for: context.eventLoop).database(logger: context.logger),
1717
context: context,
1818
encoder: self.encoder,
19-
decoder: self.decoder
19+
decoder: self.decoder,
20+
inTransaction: false
2021
)
2122
}
2223

Sources/FluentPostgresDriver/PostgresConverterDelegate.swift

+13
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,17 @@ struct PostgresConverterDelegate: SQLConverterDelegate {
2323
return nil
2424
}
2525
}
26+
27+
28+
func nestedFieldExpression(_ column: String, _ path: [String]) -> SQLExpression {
29+
switch path.count {
30+
case 1:
31+
return SQLRaw("\(column)->>'\(path[0])'")
32+
case 2...:
33+
let inner = path[0..<path.count - 1].map { "'\($0)'" }.joined(separator: "->")
34+
return SQLRaw("\(column)->\(inner)->>'\(path.last!)'")
35+
default:
36+
fatalError()
37+
}
38+
}
2639
}

Sources/FluentPostgresDriver/PostgresRow+Database.swift

+57-19
Original file line numberDiff line numberDiff line change
@@ -4,48 +4,86 @@ extension PostgresRow {
44
internal func databaseOutput(using decoder: PostgresDataDecoder) -> DatabaseOutput {
55
_PostgresDatabaseOutput(
66
row: self,
7-
decoder: decoder,
8-
schema: nil
7+
decoder: decoder
98
)
109
}
1110
}
1211

1312
private struct _PostgresDatabaseOutput: DatabaseOutput {
1413
let row: PostgresRow
1514
let decoder: PostgresDataDecoder
16-
let schema: String?
1715

1816
var description: String {
1917
self.row.description
2018
}
2119

22-
func contains(_ path: [FieldKey]) -> Bool {
23-
return self.row.column(self.columnName(path)) != nil
20+
func decodeNil(_ key: FieldKey) throws -> Bool {
21+
if let data = self.row.column(self.columnName(key)) {
22+
return data.type == .null
23+
} else {
24+
return true
25+
}
26+
}
27+
28+
func contains(_ key: FieldKey) -> Bool {
29+
self.row.column(self.columnName(key)) != nil
2430
}
2531

2632
func schema(_ schema: String) -> DatabaseOutput {
27-
_PostgresDatabaseOutput(
28-
row: self.row,
29-
decoder: self.decoder,
33+
_SchemaDatabaseOutput(
34+
output: self,
3035
schema: schema
3136
)
3237
}
3338

34-
func decode<T>(
35-
_ path: [FieldKey],
36-
as type: T.Type
37-
) throws -> T where T : Decodable {
39+
func decode<T>(_ key: FieldKey, as type: T.Type) throws -> T
40+
where T: Decodable
41+
{
3842
try self.row.sql(decoder: self.decoder)
39-
.decode(column: self.columnName(path), as: T.self)
43+
.decode(column: self.columnName(key), as: T.self)
4044
}
4145

42-
private func columnName(_ path: [FieldKey]) -> String {
43-
let field = path.map { $0.description }.joined(separator: "_")
44-
if let schema = self.schema {
45-
return "\(schema)_\(field)"
46-
} else {
47-
return field
46+
func columnName(_ key: FieldKey) -> String {
47+
switch key {
48+
case .id:
49+
return "id"
50+
case .aggregate:
51+
return key.description
52+
case .string(let name):
53+
return name
54+
case .prefix(let prefix, let key):
55+
return self.columnName(prefix) + self.columnName(key)
4856
}
57+
}
58+
}
59+
60+
private struct _SchemaDatabaseOutput: DatabaseOutput {
61+
let output: DatabaseOutput
62+
let schema: String
63+
64+
var description: String {
65+
self.output.description
66+
}
67+
68+
func schema(_ schema: String) -> DatabaseOutput {
69+
self.output.schema(schema)
70+
}
71+
72+
func contains(_ key: FieldKey) -> Bool {
73+
self.output.contains(self.key(key))
74+
}
75+
76+
func decodeNil(_ key: FieldKey) throws -> Bool {
77+
try self.output.decodeNil(self.key(key))
78+
}
79+
80+
func decode<T>(_ key: FieldKey, as type: T.Type) throws -> T
81+
where T: Decodable
82+
{
83+
try self.output.decode(self.key(key), as: T.self)
84+
}
4985

86+
private func key(_ key: FieldKey) -> FieldKey {
87+
.prefix(.string(self.schema + "_"), key)
5088
}
5189
}

0 commit comments

Comments
 (0)