diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..6ff9614 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,8 @@ +* @gwynne +/.github/CONTRIBUTING.md @gwynne @0xTim +/.github/workflows/*.yml @gwynne @0xTim +/.github/workflows/test.yml @gwynne +/.spi.yml @gwynne @0xTim +/.gitignore @gwynne @0xTim +/LICENSE @gwynne @0xTim +/README.md @gwynne @0xTim diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8d76db6..2b4aa7c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,8 +3,8 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true on: - pull_request: { branches: ['*'] } - push: { branches: ['main'] } + pull_request: { types: [opened, reopened, synchronize, ready_for_review] } + push: { branches: [ main ] } env: LOG_LEVEL: info @@ -23,50 +23,8 @@ env: POSTGRES_PASSWORD_B: 'test_password' jobs: - # Baseline test run for code coverage stats - codecov: - strategy: - matrix: - include: - - dbimage: postgres:15 - dbauth: scram-sha-256 - runs-on: ubuntu-latest - container: swift:5.8-jammy - services: - psql-a: - image: ${{ matrix.dbimage }} - env: - POSTGRES_USER: 'test_username' - POSTGRES_DB: 'test_database' - POSTGRES_PASSWORD: 'test_password' - POSTGRES_HOST_AUTH_METHOD: ${{ matrix.dbauth }} - POSTGRES_INITDB_ARGS: --auth-host=${{ matrix.dbauth }} - psql-b: - image: ${{ matrix.dbimage }} - env: - POSTGRES_USER: 'test_username' - POSTGRES_DB: 'test_database' - POSTGRES_PASSWORD: 'test_password' - POSTGRES_HOST_AUTH_METHOD: ${{ matrix.dbauth }} - POSTGRES_INITDB_ARGS: --auth-host=${{ matrix.dbauth }} - steps: - - name: Save Postgres version and method to env - run: | - echo POSTGRES_VERSION='${{ matrix.dbimage }}' >> $GITHUB_ENV - echo POSTGRES_AUTH_METHOD='${{ matrix.dbauth }}' >> $GITHUB_ENV - - name: Check out package - uses: actions/checkout@v3 - - name: Run local tests with coverage - run: swift test --enable-code-coverage - - name: Submit coverage report to Codecov.io - uses: vapor/swift-codecov-action@v0.2 - with: - cc_env_vars: 'SWIFT_VERSION,SWIFT_PLATFORM,RUNNER_OS,RUNNER_ARCH,POSTGRES_VERSION,POSTGRES_AUTH_METHOD' - cc_fail_ci_if_error: false - - # Check for API breakage versus main api-breakage: - if: github.event_name == 'pull_request' + if: ${{ !(github.event.pull_request.draft || false) }} runs-on: ubuntu-latest container: swift:5.8-jammy steps: @@ -77,7 +35,7 @@ jobs: uses: vapor/ci/.github/actions/ci-swift-check-api-breakage@reusable-workflows linux-all: - if: github.event_name == 'pull_request' + if: ${{ !(github.event.pull_request.draft || false) }} strategy: fail-fast: false matrix: @@ -107,13 +65,28 @@ jobs: POSTGRES_HOST_AUTH_METHOD: ${{ matrix.dbauth }} POSTGRES_INITDB_ARGS: --auth-host=${{ matrix.dbauth }} steps: + - name: Display versions + shell: bash + run: | + echo POSTGRES_VERSION='${{ matrix.dbimage }}' >> $GITHUB_ENV + echo POSTGRES_AUTH_METHOD='${{ matrix.dbauth }}' >> $GITHUB_ENV + if [[ '${{ contains(matrix.container, 'nightly') }}' == 'true' ]]; then + SWIFT_PLATFORM="$(source /etc/os-release && echo "${ID}${VERSION_ID}")" SWIFT_VERSION="$(cat /.swift_tag)" + printf 'SWIFT_PLATFORM=%s\nSWIFT_VERSION=%s\n' "${SWIFT_PLATFORM}" "${SWIFT_VERSION}" >>"${GITHUB_ENV}" + fi + printf 'OS: %s\nTag: %s\nVersion:\n' "${SWIFT_PLATFORM}-${RUNNER_ARCH}" "${SWIFT_VERSION}" && swift --version - name: Check out package uses: actions/checkout@v3 - name: Run all tests - run: swift test --sanitize=thread + run: swift test --sanitize=thread --enable-code-coverage + - name: Submit coverage report to Codecov.io + uses: vapor/swift-codecov-action@v0.2 + with: + cc_env_vars: 'SWIFT_VERSION,SWIFT_PLATFORM,RUNNER_OS,RUNNER_ARCH,POSTGRES_VERSION,POSTGRES_AUTH_METHOD' + cc_fail_ci_if_error: false macos-all: - if: github.event_name == 'pull_request' + if: ${{ !(github.event.pull_request.draft || false) }} strategy: fail-fast: false matrix: diff --git a/Package.swift b/Package.swift index bfbf858..3dfaa0a 100644 --- a/Package.swift +++ b/Package.swift @@ -13,9 +13,9 @@ let package = Package( .library(name: "FluentPostgresDriver", targets: ["FluentPostgresDriver"]), ], dependencies: [ - .package(url: "https://github.com/vapor/async-kit.git", from: "1.14.0"), - .package(url: "https://github.com/vapor/fluent-kit.git", from: "1.36.0"), - .package(url: "https://github.com/vapor/postgres-kit.git", from: "2.11.0"), + .package(url: "https://github.com/vapor/async-kit.git", from: "1.17.0"), + .package(url: "https://github.com/vapor/fluent-kit.git", from: "1.43.0"), + .package(url: "https://github.com/vapor/postgres-kit.git", from: "2.11.4"), ], targets: [ .target(name: "FluentPostgresDriver", dependencies: [ diff --git a/README.md b/README.md index 84be6fa..8803fe2 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,13 @@ MIT License - - Continuous Integration + + Continuous Integration + + + Test Coverage - Swift 5.2 + Swift 5.7

diff --git a/Sources/FluentPostgresDriver/PostgresConverterDelegate.swift b/Sources/FluentPostgresDriver/PostgresConverterDelegate.swift index 4749888..7eb55c4 100644 --- a/Sources/FluentPostgresDriver/PostgresConverterDelegate.swift +++ b/Sources/FluentPostgresDriver/PostgresConverterDelegate.swift @@ -45,18 +45,6 @@ struct PostgresConverterDelegate: SQLConverterDelegate { return nil } } - - func nestedFieldExpression(_ column: String, _ path: [String]) -> any SQLExpression { - switch path.count { - case 1: - return SQLRaw("\(column)->>'\(path[0])'") - case 2...: - let inner = path[0..") - return SQLRaw("\(column)->\(inner)->>'\(path.last!)'") - default: - fatalError() - } - } } private struct SQLArrayDataType: SQLExpression { diff --git a/Tests/FluentPostgresDriverTests/FluentPostgresDriverTests.swift b/Tests/FluentPostgresDriverTests/FluentPostgresDriverTests.swift index 6c3fa7d..a2f510e 100644 --- a/Tests/FluentPostgresDriverTests/FluentPostgresDriverTests.swift +++ b/Tests/FluentPostgresDriverTests/FluentPostgresDriverTests.swift @@ -4,6 +4,7 @@ import FluentBenchmark import FluentPostgresDriver import XCTest import PostgresKit +import SQLKit final class FluentPostgresDriverTests: XCTestCase { //func testAll() throws { try self.benchmarker.testAll() } @@ -162,6 +163,40 @@ final class FluentPostgresDriverTests: XCTestCase { try! EventWithFooMigration().revert(on: self.db).wait() try! EnumMigration().revert(on: self.db).wait() } + + func testEncodingArrayOfModels() throws { + final class Elem: Model, ExpressibleByIntegerLiteral { + static let schema = "" + @ID(custom: .id) var id: Int? + init() {}; init(integerLiteral l: Int) { self.id = l } + } + final class Seq: Model, ExpressibleByNilLiteral, ExpressibleByArrayLiteral { + static let schema = "seqs" + @ID(custom: .id) var id: Int?; @OptionalField(key: "list") var list: [Elem]? + init() {}; init(nilLiteral: ()) { self.list = nil }; init(arrayLiteral el: Elem...) { self.list = el } + } + do { + try self.db.schema(Seq.schema).field(.id, .int, .identifier(auto: true)).field("list", .sql(embed: "JSONB[]")).create().wait() + defer { try! db.schema(Seq.schema).delete().wait() } + + let s1: Seq = [1, 2], s2: Seq = nil; try [s1, s2].forEach { try $0.create(on: self.db).wait() } + + // Make sure it went into the DB as "array of jsonb" rather than as "array of one jsonb containing array" or such. + let raws = try (self.db as! SQLDatabase).raw("SELECT array_to_json(list)::text t FROM seqs").all().wait().map { try $0.decode(column: "t", as: String?.self) } + XCTAssertEqual(raws, [#"[{"id": 1},{"id": 2}]"#, nil]) + + // Make sure it round-trips through Fluent. + let seqs = try Seq.query(on: self.db).all().wait() + + XCTAssertEqual(seqs.count, 2) + XCTAssertEqual(seqs.dropFirst(0).first?.id, s1.id) + XCTAssertEqual(seqs.dropFirst(0).first?.list?.map(\.id), s1.list?.map(\.id)) + XCTAssertEqual(seqs.dropFirst(1).first?.id, s2.id) + XCTAssertEqual(seqs.dropFirst(1).first?.list?.map(\.id), s2.list?.map(\.id)) + } catch let error { + XCTFail("caught error: \(String(reflecting: error))") + } + } var benchmarker: FluentBenchmarker {