Skip to content

Commit

Permalink
docs: add typeorm examples
Browse files Browse the repository at this point in the history
Adds TypeORM samples along with a new CI target to run tests against the
provided samples, making sure they're always valid usage.

Fixes: #112
  • Loading branch information
ruyadorno committed Nov 23, 2023
1 parent d07da5b commit 0332b43
Show file tree
Hide file tree
Showing 24 changed files with 1,537 additions and 13 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ jobs:

- name: Calculate base code coverage
run: |
export CUR_COVER=$(npx tap | xargs -0 node -p 'parseInt(process.argv[1].split("\nAll files")[1].split("|")[1].trim(), 10)')
export CUR_COVER=$(npx tap test | xargs -0 node -p 'parseInt(process.argv[1].split("\nAll files")[1].split("|")[1].trim(), 10)')
echo "CUR_COVER=$CUR_COVER" >> $GITHUB_ENV
- name: Checkout PR branch
Expand All @@ -75,7 +75,7 @@ jobs:

- name: Calculate PR code coverage
run: |
export PR_COVER=$(npx tap | xargs -0 node -p 'parseInt(process.argv[1].split("\nAll files")[1].split("|")[1].trim(), 10)')
export PR_COVER=$(npx tap test | xargs -0 node -p 'parseInt(process.argv[1].split("\nAll files")[1].split("|")[1].trim(), 10)')
echo "PR_COVER=$PR_COVER" >> $GITHUB_ENV
- name: Verify code coverage. If your reading this and the step has failed, please add tests to cover your changes.
Expand Down
126 changes: 118 additions & 8 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ jobs:

- name: Run Tests v14.x
if: "${{ matrix.node-version == 'v14.x' }}"
run: npx tap -c -t0 --no-coverage --no-ts --node-arg="--require" --node-arg="./scripts/tap16-adapter.js" --node-arg="--no-warnings" --node-arg="--loader" --node-arg="ts-node/esm"
run: npx tap -c -t0 --no-coverage --no-ts --node-arg="--require" --node-arg="./scripts/tap16-adapter.js" --node-arg="--no-warnings" --node-arg="--loader" --node-arg="ts-node/esm" test
timeout-minutes: 5

- name: Run Tests
Expand All @@ -111,7 +111,7 @@ jobs:
TAP_ALLOW_INCOMPLETE_COVERAGE: "${{ matrix.os == 'windows-latest' && '1' || '0' }}"
TAP_ALLOW_EMPTY_COVERAGE: "${{ matrix.os == 'windows-latest' && '1' || '0' }}"
if: "${{ matrix.node-version != 'v14.x' }}"
run: npx tap -c -t0 -o test_results.tap
run: npx tap -c -t0 -o test_results.tap test
timeout-minutes: 5

- name: Convert test output to XML
Expand Down Expand Up @@ -191,12 +191,6 @@ jobs:
- name: Install dependencies
run: npm ci

- name: Setup self-direct dependency
run: npm link

- name: Link self-direct dependency
run: npm link @google-cloud/cloud-sql-connector

- name: Transpile TypeScript
run: npm run prepare

Expand Down Expand Up @@ -236,6 +230,12 @@ jobs:
if: "${{ matrix.node-version == 'v14.x' }}"
run: npm uninstall @typescript-eslint/eslint-plugin eslint-plugin-prettier tap && npm install tap@16 ts-node && npx npm@7 pkg delete tap

- name: Setup self-direct dependency
run: npm link

- name: Link self-direct dependency
run: npm link @google-cloud/cloud-sql-connector

- name: Run System Tests v14.x
env:
MYSQL_CONNECTION_NAME: '${{ steps.secrets.outputs.MYSQL_CONNECTION_NAME }}'
Expand Down Expand Up @@ -304,3 +304,113 @@ jobs:
curl https://github.com/googleapis/repo-automation-bots/releases/download/flakybot-1.1.0/flakybot-darwin-amd64 -o flakybot -s -L
chmod +x ./flakybot
./flakybot --repo ${{github.repository}} --commit_hash ${{github.sha}} --build_url https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}
sample-tests:
# run job on proper workflow event triggers (skip job for pull_request event from forks and only run pull_request_target for "tests: run" label)
if: "${{ (github.event.action != 'labeled' && github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name) || github.event.label.name == 'tests: run' }}"
name: Sample tests
strategy:
matrix:
node-version: [v18.x]
os: [ubuntu-latest]
fail-fast: false
permissions:
contents: 'read'
id-token: 'write'
issues: write
pull-requests: write

runs-on: ${{ matrix.os }}

steps:
- name: Remove PR label
if: "${{ github.event.action == 'labeled' && github.event.label.name == 'tests: run' }}"
uses: actions/github-script@e69ef5462fd455e02edcaf4dd7708eda96b9eda0 # v7.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
try {
await github.rest.issues.removeLabel({
name: 'tests: run',
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number
});
} catch (e) {
console.log('Failed to remove label. Another job may have already removed it!');
}
- name: Checkout Repository
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
with:
node-version: ${{ matrix.node-version }}

- name: Install dependencies
run: npm ci

- name: Setup self-direct dependency
run: npm link

- name: Link self-direct dependency
run: npm link @google-cloud/cloud-sql-connector

- name: Transpile TypeScript
run: npm run prepare

- id: 'auth'
name: Authenticate to Google Cloud
uses: google-github-actions/auth@35b0e87d162680511bf346c299f71c9c5c379033 # v1.1.1
with:
workload_identity_provider: ${{ secrets.PROVIDER_NAME }}
service_account: ${{ secrets.SERVICE_ACCOUNT }}
access_token_lifetime: 600s

- id: 'secrets'
name: Get secrets
uses: google-github-actions/get-secretmanager-secrets@4d6d3dfd94110800dda8d84109cb6da0f6a5919d # v1.0.1
with:
secrets: |-
MYSQL_CONNECTION_NAME:${{ secrets.GOOGLE_CLOUD_PROJECT }}/MYSQL_CONNECTION_NAME
MYSQL_IAM_CONNECTION_NAME:${{ secrets.GOOGLE_CLOUD_PROJECT }}/MYSQL_IAM_CONNECTION_NAME
MYSQL_USER:${{ secrets.GOOGLE_CLOUD_PROJECT }}/MYSQL_USER
MYSQL_IAM_USER:${{ secrets.GOOGLE_CLOUD_PROJECT }}/MYSQL_USER_IAM_NODE
MYSQL_PASS:${{ secrets.GOOGLE_CLOUD_PROJECT }}/MYSQL_PASS
MYSQL_DB:${{ secrets.GOOGLE_CLOUD_PROJECT }}/MYSQL_DB
POSTGRES_CONNECTION_NAME:${{ secrets.GOOGLE_CLOUD_PROJECT }}/POSTGRES_CONNECTION_NAME
POSTGRES_IAM_CONNECTION_NAME:${{ secrets.GOOGLE_CLOUD_PROJECT }}/POSTGRES_IAM_CONNECTION_NAME
POSTGRES_USER:${{ secrets.GOOGLE_CLOUD_PROJECT }}/POSTGRES_USER
POSTGRES_IAM_USER:${{ secrets.GOOGLE_CLOUD_PROJECT }}/POSTGRES_USER_IAM_NODE
POSTGRES_PASS:${{ secrets.GOOGLE_CLOUD_PROJECT }}/POSTGRES_PASS
POSTGRES_DB:${{ secrets.GOOGLE_CLOUD_PROJECT }}/POSTGRES_DB
SQLSERVER_CONNECTION_NAME:${{ secrets.GOOGLE_CLOUD_PROJECT }}/SQLSERVER_CONNECTION_NAME
SQLSERVER_USER:${{ secrets.GOOGLE_CLOUD_PROJECT }}/SQLSERVER_USER
SQLSERVER_PASS:${{ secrets.GOOGLE_CLOUD_PROJECT }}/SQLSERVER_PASS
SQLSERVER_DB:${{ secrets.GOOGLE_CLOUD_PROJECT }}/SQLSERVER_DB
- name: Run Sample Tests
env:
MYSQL_CONNECTION_NAME: '${{ steps.secrets.outputs.MYSQL_CONNECTION_NAME }}'
MYSQL_IAM_CONNECTION_NAME: '${{ steps.secrets.outputs.MYSQL_IAM_CONNECTION_NAME }}'
MYSQL_USER: '${{ steps.secrets.outputs.MYSQL_USER }}'
MYSQL_IAM_USER: '${{ steps.secrets.outputs.MYSQL_IAM_USER }}'
MYSQL_PASS: '${{ steps.secrets.outputs.MYSQL_PASS }}'
MYSQL_DB: '${{ steps.secrets.outputs.MYSQL_DB }}'
POSTGRES_CONNECTION_NAME: '${{ steps.secrets.outputs.POSTGRES_CONNECTION_NAME }}'
POSTGRES_IAM_CONNECTION_NAME: '${{ steps.secrets.outputs.POSTGRES_IAM_CONNECTION_NAME }}'
POSTGRES_USER: '${{ steps.secrets.outputs.POSTGRES_USER }}'
POSTGRES_IAM_USER: '${{ steps.secrets.outputs.POSTGRES_IAM_USER }}'
POSTGRES_PASS: '${{ steps.secrets.outputs.POSTGRES_PASS }}'
POSTGRES_DB: '${{ steps.secrets.outputs.POSTGRES_DB }}'
SQLSERVER_CONNECTION_NAME: '${{ steps.secrets.outputs.SQLSERVER_CONNECTION_NAME }}'
SQLSERVER_USER: '${{ steps.secrets.outputs.SQLSERVER_USER }}'
SQLSERVER_PASS: '${{ steps.secrets.outputs.SQLSERVER_PASS }}'
SQLSERVER_DB: '${{ steps.secrets.outputs.SQLSERVER_DB }}'
if: "${{ matrix.node-version != 'v14.x' }}"
run: npx tap -c -t0 --disable-coverage --allow-empty-coverage examples/*/{mysql2,pg,tedious}.test{.cjs,.mjs,.ts} -o test_results.tap
timeout-minutes: 5
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
!/package-lock.json
!/README.md
!/LICENSE{,.*}
!/example
!/examples
!/scripts
!/system-test
!/tap-snapshots
Expand Down
19 changes: 19 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Cloud SQL Node.js Connector Examples

Welcome to the **Cloud SQL Node.js Connector** examples directory. Here you can
find a collection of ready-to-use samples showing how to use the library with
some of the most popular database libraries and frameworks.

## Available Examples

### TypeORM

- [MySQL (CommonJS)](./typeorm/mysql2.cjs)
- [MySQL (ESM)](./typeorm/mysql2.mjs)
- [MySQL (TypeScript)](./typeorm/mysql2.ts)
- [PostgreSQL (CommonJS)](./typeorm/pg.cjs)
- [PostgreSQL (ESM)](./typeorm/pg.mjs)
- [PostgreSQL (TypeScript)](./typeorm/pg.ts)
- [SQL Server (CommonJS)](./typeorm/tedious.cjs)
- [SQL Server (ESM)](./typeorm/tedious.mjs)
- [SQL Server (TypeScript)](./typeorm/tedious.ts)
44 changes: 44 additions & 0 deletions examples/typeorm/mysql2.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

const {Connector} = require('@google-cloud/cloud-sql-connector');
const typeorm = require('typeorm');

async function connect({ instanceConnectionName, username, database }) {
const connector = new Connector();
const clientOpts = await connector.getOptions({
instanceConnectionName,
ipType: 'PUBLIC',
authType: 'IAM',
});
const dataSource = new typeorm.DataSource({
type: 'mysql',
username,
database,
extra: clientOpts,
});
await dataSource.initialize()

return {
dataSource,
async close() {
await dataSource.destroy();
connector.close();
}
};
};

module.exports = {
connect,
};
40 changes: 40 additions & 0 deletions examples/typeorm/mysql2.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import {Connector} from '@google-cloud/cloud-sql-connector';
import {DataSource} from 'typeorm';

export async function connect({ instanceConnectionName, username, database }) {
const connector = new Connector();
const clientOpts = await connector.getOptions({
instanceConnectionName,
ipType: 'PUBLIC',
authType: 'IAM',
});
const dataSource = new DataSource({
type: 'mysql',
username,
database,
extra: clientOpts,
});
await dataSource.initialize()

return {
dataSource,
async close() {
await dataSource.destroy();
connector.close();
}
};
};
28 changes: 28 additions & 0 deletions examples/typeorm/mysql2.test.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

const t = require('tap');
const connector = require('./mysql2.cjs');

t.test('mysql2 typeorm cjs', async t => {
const { dataSource, close } = await connector.connect({
instanceConnectionName: process.env.MYSQL_IAM_CONNECTION_NAME,
username: process.env.MYSQL_IAM_USER,
database: process.env.MYSQL_DB,
});
const [{ now: time }] = await dataSource.manager.query('SELECT NOW() as now')
t.ok(time.getTime(), 'should have valid returned date object');
await close();
});

27 changes: 27 additions & 0 deletions examples/typeorm/mysql2.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import t from 'tap';
import {connect} from './mysql2.mjs';

t.test('mysql2 typeorm mjs', async t => {
const { dataSource, close } = await connect({
instanceConnectionName: process.env.MYSQL_IAM_CONNECTION_NAME,
username: process.env.MYSQL_IAM_USER,
database: process.env.MYSQL_DB,
});
const [{ now: time }] = await dataSource.manager.query('SELECT NOW() as now');
t.ok(time.getTime(), 'should have valid returned date object');
await close();
});
27 changes: 27 additions & 0 deletions examples/typeorm/mysql2.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import t from 'tap';
import {connect} from './mysql2';

t.test('mysql typeorm ts', async t => {
const {dataSource, close} = await connect({
instanceConnectionName: process.env.MYSQL_IAM_CONNECTION_NAME,
username: process.env.MYSQL_IAM_USER,
database: process.env.MYSQL_DB,
});
const [{now: time}] = await dataSource.manager.query('SELECT NOW() as now');
t.ok(time.getTime(), 'should have valid returned date object');
await close();
});

0 comments on commit 0332b43

Please sign in to comment.