Skip to content

Commit

Permalink
docs: update Sequelize tests and sample (#1949)
Browse files Browse the repository at this point in the history
* docs: update Sequelize tests and sample

* chore: fix test cases

* fix: show dates as dates
  • Loading branch information
olavloite authored Jun 12, 2024
1 parent ec04265 commit 5342ff8
Show file tree
Hide file tree
Showing 4 changed files with 619 additions and 10 deletions.
33 changes: 32 additions & 1 deletion samples/nodejs/sequelize/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# PGAdapter Spanner and Sequelize

PGAdapter has experimental support for [Sequelize](https://sequelize.org/) with the standard Node.js
PGAdapter can be used with [Sequelize](https://sequelize.org/) with the standard Node.js
`pg` driver. This sample application shows how to connect to PGAdapter with Sequelize, and how to
execute queries and transactions on Cloud Spanner.

Expand All @@ -15,3 +15,34 @@ npm start

PGAdapter and the emulator are started in a Docker test container by the sample application.
Docker is therefore required to be installed on your system to run this sample.

## Performance Considerations

### Query Parameters

[Sequelize](https://sequelize.org/) does not use parameterized queries by default. The following query __will not use
a parameterized query__, which will incur a performance penalty on Spanner.

```typescript
// DO NOT USE!
const singers = await Singer.findAll({
where: {
lastName: {[Op.like]: pattern },
},
});
```

Instead, construct queries with bind parameters like this:

```typescript
// BEST PRACTICE: USE BIND PARAMETERS
const singers = await Singer.findAll({
where: {
lastName: {[Op.like]: literal('$pattern') },
},
bind: {pattern},
});
```

See https://sequelize.org/docs/v6/core-concepts/raw-queries/#bind-parameter for more information on
bind parameters in Sequelize.
31 changes: 30 additions & 1 deletion samples/nodejs/sequelize/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import {createDataModel, startPGAdapter} from './init'
import {Album, Concert, initModels, Singer, TicketSale, Track, Venue} from '../models/models';
import {QueryTypes, Sequelize} from "sequelize";
import {literal, Op, QueryTypes, Sequelize} from "sequelize";
import {randomInt} from "crypto";
import {randomAlbumTitle, randomFirstName, randomLastName, randomTrackTitle} from "./random";

Expand Down Expand Up @@ -60,6 +60,8 @@ async function main() {
// Create and then print some random data.
await createRandomSingersAndAlbums(sequelize, 20);
await printSingersAlbums();
// Print all singers whose name start with an 'C'.
await printSingersWithLastNameLike('C%');

// Create Venues and Concerts rows.
// The "venues" table contains a JSONB column.
Expand Down Expand Up @@ -142,6 +144,33 @@ async function printSingersAlbums() {
}
}

// Selects all Singers whose last name match the given pattern.
async function printSingersWithLastNameLike(pattern: string) {
// Use `literal('$param_name')` in combination with an array of bind parameters
// to use parameterized queries on Spanner. This will reduce latency, as Spanner
// can cache the execution plan for the query.
// See https://sequelize.org/docs/v6/core-concepts/raw-queries/#bind-parameter for
// more information on bind parameters in Sequelize.
const singers = await Singer.findAll({
where: {
lastName: {[Op.like]: literal('$pattern') },
},
bind: {pattern},
});
console.log(`Found singers whose last name match the pattern ${pattern}:`);
for (const singer of singers) {
console.log(`Singer ${singer.fullName}`);
}

// This gives the same result, but is inefficient.
// DO NOT USE!
// const singers = await Singer.findAll({
// where: {
// lastName: {[Op.like]: pattern },
// },
// });
}

// Shows how to execute a stale read on Spanner.
async function staleRead(sequelize: Sequelize) {
console.log("");
Expand Down
Loading

0 comments on commit 5342ff8

Please sign in to comment.