diff --git a/Package.swift b/Package.swift index d8c0dae8..d7b4511c 100644 --- a/Package.swift +++ b/Package.swift @@ -23,7 +23,7 @@ let package = Package( .package(url: "https://github.com/apple/swift-nio.git", from: "1.0.0"), // *️⃣ Build SQL queries in Swift. Extensible, protocol-based design that supports DQL, DML, and DDL. - .package(url: "https://github.com/vapor/sql.git", from: "2.0.0-beta"), + .package(url: "https://github.com/vapor/sql.git", from: "2.0.0-beta.3"), ], targets: [ .target(name: "PostgreSQL", dependencies: ["Async", "Bits", "Core", "Crypto", "DatabaseKit", "NIO", "Service", "SQL"]), diff --git a/Sources/PostgreSQL/SQL/PostgreSQLDropIndex.swift b/Sources/PostgreSQL/SQL/PostgreSQLDropIndex.swift new file mode 100644 index 00000000..3a12d99f --- /dev/null +++ b/Sources/PostgreSQL/SQL/PostgreSQLDropIndex.swift @@ -0,0 +1,39 @@ +public struct PostgreSQLDropIndex: SQLDropIndex { + public var identifier: PostgreSQLIdentifier + + /// See `SQLSerializable`. + public func serialize(_ binds: inout [Encodable]) -> String { + var sql: [String] = [] + sql.append("DROP INDEX") + sql.append(identifier.serialize(&binds)) + return sql.joined(separator: " ") + } +} + +public final class PostgreSQLDropIndexBuilder: SQLQueryBuilder + where Connection: DatabaseQueryable, Connection.Query == PostgreSQLQuery +{ + /// `AlterTable` query being built. + public var dropIndex: PostgreSQLDropIndex + + /// See `SQLQueryBuilder`. + public var connection: Connection + + /// See `SQLQueryBuilder`. + public var query: PostgreSQLQuery { + return .dropIndex(dropIndex) + } + + /// Creates a new `SQLCreateIndexBuilder`. + public init(_ dropIndex: PostgreSQLDropIndex, on connection: Connection) { + self.dropIndex = dropIndex + self.connection = connection + } +} + + +extension DatabaseQueryable where Query == PostgreSQLQuery { + public func drop(index identifier: PostgreSQLIdentifier) -> PostgreSQLDropIndexBuilder { + return .init(PostgreSQLDropIndex(identifier: identifier), on: self) + } +} diff --git a/Sources/PostgreSQL/SQL/PostgreSQLGeneric.swift b/Sources/PostgreSQL/SQL/PostgreSQLGeneric.swift index c364572c..7033f17c 100644 --- a/Sources/PostgreSQL/SQL/PostgreSQLGeneric.swift +++ b/Sources/PostgreSQL/SQL/PostgreSQLGeneric.swift @@ -18,7 +18,12 @@ public typealias PostgreSQLColumnIdentifier = GenericSQLColumnIdentifier< PostgreSQLTableIdentifier, PostgreSQLIdentifier > -/// See `SQLQuery` +/// See `SQLQuery`. +public typealias PostgreSQLCreateIndex = GenericSQLCreateIndex< + PostgreSQLIndexModifier, PostgreSQLIdentifier, PostgreSQLTableIdentifier +> + +/// See `SQLQuery`. public typealias PostgreSQLCreateTable = GenericSQLCreateTable< PostgreSQLTableIdentifier, PostgreSQLColumnDefinition, PostgreSQLTableConstraint > @@ -53,6 +58,9 @@ public typealias PostgreSQLForeignKeyAction = GenericSQLForeignKeyAction /// See `SQLQuery`. public typealias PostgreSQLGroupBy = GenericSQLGroupBy +/// See `SQLQuery`. +public typealias PostgreSQLIndexModifier = GenericSQLIndexModifier + /// See `SQLQuery`. public typealias PostgreSQLIdentifier = GenericSQLIdentifier diff --git a/Sources/PostgreSQL/SQL/PostgreSQLQuery.swift b/Sources/PostgreSQL/SQL/PostgreSQLQuery.swift index b628fcc7..22b04048 100644 --- a/Sources/PostgreSQL/SQL/PostgreSQLQuery.swift +++ b/Sources/PostgreSQL/SQL/PostgreSQLQuery.swift @@ -2,12 +2,18 @@ public enum PostgreSQLQuery: SQLQuery { /// See `SQLQuery`. public typealias AlterTable = PostgreSQLAlterTable + /// See `SQLQuery`. + public typealias CreateIndex = PostgreSQLCreateIndex + /// See `SQLQuery`. public typealias CreateTable = PostgreSQLCreateTable /// See `SQLQuery`. public typealias Delete = PostgreSQLDelete + /// See `SQLQuery`. + public typealias DropIndex = PostgreSQLDropIndex + /// See `SQLQuery`. public typealias DropTable = PostgreSQLDropTable @@ -28,6 +34,11 @@ public enum PostgreSQLQuery: SQLQuery { return ._alterTable(alterTable) } + /// See `SQLQuery`. + public static func createIndex(_ createIndex: PostgreSQLCreateIndex) -> PostgreSQLQuery { + return ._createIndex(createIndex) + } + /// See `SQLQuery`. public static func createTable(_ createTable: CreateTable) -> PostgreSQLQuery { return ._createTable(createTable) @@ -38,6 +49,11 @@ public enum PostgreSQLQuery: SQLQuery { return ._delete(delete) } + /// See `SQLQuery`. + public static func dropIndex(_ dropIndex: PostgreSQLDropIndex) -> PostgreSQLQuery { + return ._dropIndex(dropIndex) + } + /// See `SQLQuery`. public static func dropTable(_ dropTable: DropTable) -> PostgreSQLQuery { return ._dropTable(dropTable) @@ -66,12 +82,18 @@ public enum PostgreSQLQuery: SQLQuery { /// See `SQLQuery`. case _alterTable(PostgreSQLAlterTable) + /// See `SQLQuery`. + case _createIndex(PostgreSQLCreateIndex) + /// See `SQLQuery`. case _createTable(PostgreSQLCreateTable) /// See `SQLQuery`. case _delete(PostgreSQLDelete) + /// See `SQLQuery`. + case _dropIndex(PostgreSQLDropIndex) + /// See `SQLQuery`. case _dropTable(PostgreSQLDropTable) @@ -91,8 +113,10 @@ public enum PostgreSQLQuery: SQLQuery { public func serialize(_ binds: inout [Encodable]) -> String { switch self { case ._alterTable(let alterTable): return alterTable.serialize(&binds) + case ._createIndex(let createIndex): return createIndex.serialize(&binds) case ._createTable(let createTable): return createTable.serialize(&binds) case ._delete(let delete): return delete.serialize(&binds) + case ._dropIndex(let dropIndex): return dropIndex.serialize(&binds) case ._dropTable(let dropTable): return dropTable.serialize(&binds) case ._insert(let insert): return insert.serialize(&binds) case ._select(let select): return select.serialize(&binds) diff --git a/Tests/PostgreSQLTests/PostgreSQLConnectionTests.swift b/Tests/PostgreSQLTests/PostgreSQLConnectionTests.swift index fbc57949..7aab4bdb 100644 --- a/Tests/PostgreSQLTests/PostgreSQLConnectionTests.swift +++ b/Tests/PostgreSQLTests/PostgreSQLConnectionTests.swift @@ -8,21 +8,17 @@ class PostgreSQLConnectionTests: XCTestCase { } func testBenchmark() throws { - let conn = try PostgreSQLConnection.makeTest(transport: .cleartext) + #if !TEST_NO_GENERATED_AS_IDENTITY + let conn = try PostgreSQLConnection.makeTest() let benchmarker = SQLBenchmarker(on: conn) try benchmarker.run() + #endif } func testVersion() throws { - let client = try PostgreSQLConnection.makeTest(transport: .cleartext) - let results = try client.select().column(.function("version", [])).all(decoding: VersionMetadata.self).wait() - XCTAssertTrue(results[0].version.contains("10.")) - } - - func testUnverifiedSSLConnection() throws { - let client = try PostgreSQLConnection.makeTest(transport: .unverifiedTLS) + let client = try PostgreSQLConnection.makeTest() let results = try client.select().column(.function("version", [])).all(decoding: VersionMetadata.self).wait() - XCTAssertTrue(results[0].version.contains("10.")) + XCTAssertTrue(results[0].version.contains(".")) } func testSelectTypes() throws { @@ -89,7 +85,7 @@ class PostgreSQLConnectionTests: XCTestCase { // var typdefault: String? // var typacl: String? } - let client = try PostgreSQLConnection.makeTest(transport: .cleartext) + let client = try PostgreSQLConnection.makeTest() let results = try client.select().all().from(PGType.self).all(decoding: PGType.self).wait() XCTAssert(results.count >= 350, "Results count not large enough: \(results.count)") } @@ -101,11 +97,15 @@ class PostgreSQLConnectionTests: XCTestCase { } struct Hello: Codable, ReflectionDecodable, Equatable { + static func reflectDecoded() throws -> (PostgreSQLConnectionTests.Hello, PostgreSQLConnectionTests.Hello) { + return (.init(message: "0"), .init(message: "1")) + } + var message: String } func testStruct() throws { - let client = try PostgreSQLConnection.makeTest(transport: .cleartext) + let client = try PostgreSQLConnection.makeTest() struct Foo: PostgreSQLTable { var id: Int? @@ -115,10 +115,17 @@ class PostgreSQLConnectionTests: XCTestCase { defer { _ = try? client.drop(table: Foo.self).ifExists().run().wait() } + #if TEST_NO_GENERATED_AS_IDENTITY + try client.create(table: Foo.self) + .column(for: \Foo.id, type: .bigserial, .primaryKey(identifier: nil)) + .column(for: \Foo.dict) + .run().wait() + #else try client.create(table: Foo.self) .column(for: \Foo.id, .primaryKey) .column(for: \Foo.dict) .run().wait() + #endif let hello = Hello(message: "Hello, world!") try client.insert(into: Foo.self).value(Foo(id: nil, dict: hello)).run().wait() @@ -133,7 +140,7 @@ class PostgreSQLConnectionTests: XCTestCase { } func testNull() throws { - let conn = try PostgreSQLConnection.makeTest(transport: .cleartext) + let conn = try PostgreSQLConnection.makeTest() struct Nulltest: PostgreSQLTable { var i: Int? @@ -143,17 +150,33 @@ class PostgreSQLConnectionTests: XCTestCase { defer { try? conn.drop(table: Nulltest.self).ifExists().run().wait() } + + #if TEST_NO_GENERATED_AS_IDENTITY + try conn.create(table: Nulltest.self) + .column(for: \Nulltest.i, type: .bigserial, .primaryKey(default: nil)) + .column(for: \Nulltest.d) + .run().wait() + #else try conn.create(table: Nulltest.self) .column(for: \Nulltest.i, .primaryKey) .column(for: \Nulltest.d) .run().wait() + #endif try conn.insert(into: Nulltest.self).value(Nulltest(i: nil, d: nil)).run().wait() } func testGH24() throws { /// PREPARE - let client = try PostgreSQLConnection.makeTest(transport: .cleartext) + let client = try PostgreSQLConnection.makeTest() + + let idtype: String + + #if TEST_NO_GENERATED_AS_IDENTITY + idtype = "BIGSERIAL" + #else + idtype = "BIGINT GENERATED BY DEFAULT AS IDENTITY" + #endif /// CREATE let _ = try client.query(""" @@ -161,11 +184,11 @@ class PostgreSQLConnectionTests: XCTestCase { """).wait() defer { _ = try! client.simpleQuery("DROP TABLE users").wait() } let _ = try client.query(""" - CREATE TABLE "acronyms" ("id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, "short" TEXT NOT NULL, "long" TEXT NOT NULL, "userID" UUID NOT NULL, FOREIGN KEY ("userID") REFERENCES "users" ("id"), FOREIGN KEY ("userID") REFERENCES "users" ("id")) + CREATE TABLE "acronyms" ("id" \(idtype) PRIMARY KEY, "short" TEXT NOT NULL, "long" TEXT NOT NULL, "userID" UUID NOT NULL, FOREIGN KEY ("userID") REFERENCES "users" ("id"), FOREIGN KEY ("userID") REFERENCES "users" ("id")) """).wait() defer { _ = try! client.simpleQuery("DROP TABLE acronyms").wait() } let _ = try client.query(""" - CREATE TABLE "categories" ("id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, "name" TEXT NOT NULL) + CREATE TABLE "categories" ("id" \(idtype) PRIMARY KEY, "name" TEXT NOT NULL) """).wait() defer { _ = try! client.simpleQuery("DROP TABLE categories").wait() } let _ = try client.query(""" @@ -230,7 +253,7 @@ class PostgreSQLConnectionTests: XCTestCase { // https://github.com/vapor/postgresql/issues/46 func testGH46() throws { - let conn = try PostgreSQLConnection.makeTest(transport: .cleartext) + let conn = try PostgreSQLConnection.makeTest() _ = try conn.simpleQuery("CREATE TABLE apps (id INT, platform TEXT, identifier TEXT)").wait() defer { _ = try? conn.simpleQuery("DROP TABLE apps").wait() } _ = try conn.simpleQuery("INSERT INTO apps VALUES (1, 'a', 'b')").wait() @@ -312,7 +335,7 @@ class PostgreSQLConnectionTests: XCTestCase { } func testRowCodableTypes() throws { - let conn = try PostgreSQLConnection.makeTest(transport: .cleartext) + let conn = try PostgreSQLConnection.makeTest() struct Types: PostgreSQLTable, Codable { static let postgreSQLTable = "types" @@ -391,7 +414,7 @@ class PostgreSQLConnectionTests: XCTestCase { var timestamptz: Date } - let conn = try PostgreSQLConnection.makeTest(transport: .cleartext) + let conn = try PostgreSQLConnection.makeTest() defer { try? conn.drop(table: Time.self).ifExists().run().wait() } @@ -408,13 +431,13 @@ class PostgreSQLConnectionTests: XCTestCase { } func testListen() throws { - let conn = try PostgreSQLConnection.makeTest(transport: .cleartext) + let conn = try PostgreSQLConnection.makeTest() let done = conn.listen("foo") { message in XCTAssertEqual(message, "hi") return true } do { - let conn = try PostgreSQLConnection.makeTest(transport: .cleartext) + let conn = try PostgreSQLConnection.makeTest() _ = try conn.notify("foo", message: "hi").wait() } try done.wait() @@ -422,7 +445,7 @@ class PostgreSQLConnectionTests: XCTestCase { // https://github.com/vapor/postgresql/issues/56 func testSum() throws { - let conn = try PostgreSQLConnection.makeTest(transport: .cleartext) + let conn = try PostgreSQLConnection.makeTest() struct Sum: Decodable { var sum: Double } @@ -443,7 +466,7 @@ class PostgreSQLConnectionTests: XCTestCase { } } - let conn = try PostgreSQLConnection.makeTest(transport: .cleartext) + let conn = try PostgreSQLConnection.makeTest() defer { try? conn.drop(table: Planet.self).ifExists().run().wait() } @@ -474,7 +497,7 @@ class PostgreSQLConnectionTests: XCTestCase { // https://github.com/vapor/postgresql/issues/53 func testInvalidDate() throws { - let conn = try PostgreSQLConnection.makeTest(transport: .cleartext) + let conn = try PostgreSQLConnection.makeTest() struct Time: PostgreSQLTable, Equatable { static let sqlTableIdentifierString = "timetest" @@ -521,7 +544,6 @@ class PostgreSQLConnectionTests: XCTestCase { static var allTests = [ ("testBenchmark", testBenchmark), ("testVersion", testVersion), - ("testUnverifiedSSLConnection", testUnverifiedSSLConnection), ("testSelectTypes", testSelectTypes), ("testStruct", testStruct), ("testNull", testNull), @@ -542,22 +564,27 @@ class PostgreSQLConnectionTests: XCTestCase { } extension PostgreSQLConnection { - /// Creates a test event loop and psql client over ssl. - static func makeTest(transport: PostgreSQLConnection.TransportConfig) throws -> PostgreSQLConnection { - #if Xcode - return try _makeTest(hostname: "localhost", port: transport.isTLS ? 5433 : 5432, password: "vapor_password", transport: transport) + /// Creates a test connection. + static func makeTest() throws -> PostgreSQLConnection { + let transport: PostgreSQLConnection.TransportConfig + #if TEST_USE_UNVERIFIED_TLS + transport = .unverifiedTLS #else - return try _makeTest(hostname: transport.isTLS ? "tls" : "cleartext", port: 5432, password: "vapor_password", transport: transport) + transport = .cleartext #endif - } - - /// Creates a test connection. - private static func _makeTest(hostname: String, port: Int, password: String? = nil, transport: PostgreSQLConnection.TransportConfig = .cleartext) throws -> PostgreSQLConnection { + + let hostname: String + #if os(macOS) + hostname = "localhost" + #else + hostname = "psql" + #endif + let group = MultiThreadedEventLoopGroup(numberOfThreads: 1) - let client = try PostgreSQLConnection.connect(hostname: hostname, port: port, transport: transport, on: group) { error in + let client = try PostgreSQLConnection.connect(hostname: hostname, port: 5432, transport: transport, on: group) { error in XCTFail("\(error)") }.wait() - _ = try client.authenticate(username: "vapor_username", database: "vapor_database", password: password).wait() + _ = try client.authenticate(username: "vapor_username", database: "vapor_database", password: "vapor_password").wait() client.logger = DatabaseLogger(database: .psql, handler: PrintLogHandler()) return client } @@ -566,133 +593,3 @@ extension PostgreSQLConnection { func +=(lhs: inout [T], rhs: T) { lhs.append(rhs) } - - - - - - - - -extension ReflectionDecodable where Self: Decodable { - public static func reflectDecoded() throws -> (Self, Self) { - return try (Self.init(from: ArityDecoder(false)), Self.init(from: ArityDecoder(true))) - } -} - -private struct ArityDecoder: Decoder { - let codingPath: [CodingKey] = [] - let userInfo: [CodingUserInfoKey: Any] = [:] - let arity: Bool - init(_ arity: Bool) { - self.arity = arity - } - - func container(keyedBy type: Key.Type) throws -> KeyedDecodingContainer where Key : CodingKey { - return .init(ArityKeyedDecodingContainer(arity)) - } - - func unkeyedContainer() throws -> UnkeyedDecodingContainer { - fatalError() - } - - func singleValueContainer() throws -> SingleValueDecodingContainer { - fatalError() - } - - private struct ArityKeyedDecodingContainer: KeyedDecodingContainerProtocol where Key: CodingKey { - let allKeys: [Key] = [] - - let codingPath: [CodingKey] = [] - let userInfo: [CodingUserInfoKey: Any] = [:] - let arity: Bool - init(_ arity: Bool) { - self.arity = arity - } - - - func contains(_ key: Key) -> Bool { - return true - } - - func decodeNil(forKey key: Key) throws -> Bool { - return true - } - - func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool { - return arity - } - - func decode(_ type: String.Type, forKey key: Key) throws -> String { - return arity ? "1" : "0" - } - - func decode(_ type: Double.Type, forKey key: Key) throws -> Double { - return arity ? 1 : 0 - } - - func decode(_ type: Float.Type, forKey key: Key) throws -> Float { - return arity ? 1 : 0 - } - - func decode(_ type: Int.Type, forKey key: Key) throws -> Int { - return arity ? 1 : 0 - } - - func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 { - return arity ? 1 : 0 - } - - func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 { - return arity ? 1 : 0 - } - - func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 { - return arity ? 1 : 0 - } - - func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 { - return arity ? 1 : 0 - } - - func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt { - return arity ? 1 : 0 - } - - func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 { - return arity ? 1 : 0 - } - - func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 { - return arity ? 1 : 0 - } - - func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 { - return arity ? 1 : 0 - } - - func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 { - return arity ? 1 : 0 - } - - func decode(_ type: T.Type, forKey key: Key) throws -> T where T : Decodable { - return try T.init(from: ArityDecoder(arity)) - } - - func nestedContainer(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer where NestedKey : CodingKey { - return .init(ArityKeyedDecodingContainer(arity)) - } - - func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer { - fatalError() - } - - func superDecoder() throws -> Decoder { - return ArityDecoder(arity) - } - - func superDecoder(forKey key: Key) throws -> Decoder { - return ArityDecoder(arity) - } - } -} diff --git a/circle.yml b/circle.yml index 50be9415..8acc824d 100644 --- a/circle.yml +++ b/circle.yml @@ -8,19 +8,28 @@ jobs: - checkout - run: swift build - run: swift test - - - linux: + 10-linux: docker: - image: codevapor/swift:4.1 - - image: circleci/postgres:latest - name: cleartext + - image: circleci/postgres:10 + name: psql environment: POSTGRES_USER: vapor_username POSTGRES_DB: vapor_database POSTGRES_PASSWORD: vapor_password + steps: + - checkout + - run: + name: Compile code + command: swift build + - run: + name: Run unit tests + command: swift test + 10-linux-ssl: + docker: + - image: codevapor/swift:4.1 - image: scenecheck/postgres-ssl:latest - name: tls + name: psql environment: POSTGRES_USER: vapor_username POSTGRES_DB: vapor_database @@ -32,22 +41,51 @@ jobs: command: swift build - run: name: Run unit tests + command: swift test -Xswiftc -DTEST_USE_UNVERIFIED_TLS + 10-linux-fluent: + docker: + - image: codevapor/swift:4.1 + - image: circleci/postgres:10 + name: psql + environment: + POSTGRES_USER: vapor_username + POSTGRES_DB: vapor_database + POSTGRES_PASSWORD: vapor_password + steps: + - run: + name: Clone Fluent PostgreSQL + command: git clone -b master https://github.com/vapor/fluent-postgresql.git + working_directory: ~/ + - run: + name: Switch Fluent PostgreSQL to this PostgreSQL revision + command: swift package edit PostgreSQL --revision $CIRCLE_SHA1 + working_directory: ~/fluent-postgresql + - run: + name: Run Fluent PostgreSQL unit tests command: swift test - - - linux-release: + working_directory: ~/fluent-postgresql + 9-linux: docker: - image: codevapor/swift:4.1 + - image: circleci/postgres:9 + name: psql + environment: + POSTGRES_USER: vapor_username + POSTGRES_DB: vapor_database + POSTGRES_PASSWORD: vapor_password steps: - checkout - run: - name: Compile code with optimizations - command: swift build -c release - - linux-fluent: + name: Compile code + command: swift build + - run: + name: Run unit tests + command: swift test -Xswiftc -DTEST_NO_GENERATED_AS_IDENTITY + 9-linux-fluent: docker: - image: codevapor/swift:4.1 - - image: circleci/postgres:latest + - image: circleci/postgres:9 + name: psql environment: POSTGRES_USER: vapor_username POSTGRES_DB: vapor_database @@ -65,16 +103,24 @@ jobs: name: Run Fluent PostgreSQL unit tests command: swift test working_directory: ~/fluent-postgresql - + linux-release: + docker: + - image: codevapor/swift:4.1 + steps: + - checkout + - run: + name: Compile code with optimizations + command: swift build -c release workflows: version: 2 tests: jobs: - - linux - - linux-fluent + - 10-linux + - 10-linux-ssl + - 10-linux-fluent + - 9-linux + - 9-linux-fluent - linux-release - # - macos - nightly: triggers: - schedule: @@ -85,5 +131,3 @@ workflows: - master jobs: - linux - # - macos - diff --git a/docker-compose.yml b/docker-compose.yml index df139c4f..0dd672f9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,19 +1,27 @@ version: '2' services: - cleartext: - image: postgres:latest + psql-10: + image: postgres:10 environment: POSTGRES_USER: vapor_username POSTGRES_DB: vapor_database POSTGRES_PASSWORD: vapor_password ports: - 5432:5432 - tls: + psql-9: + image: postgres:9 + environment: + POSTGRES_USER: vapor_username + POSTGRES_DB: vapor_database + POSTGRES_PASSWORD: vapor_password + ports: + - 5432:5432 + psql-ssl: image: scenecheck/postgres-ssl:latest environment: POSTGRES_USER: vapor_username POSTGRES_DB: vapor_database POSTGRES_PASSWORD: vapor_password ports: - - 5433:5432 + - 5432:5432