Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add postgres samples #396

Merged
merged 1 commit into from
May 26, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 34 additions & 18 deletions appengine/cloudsql/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
This sample demonstrates how to use [Google Cloud SQL][sql] (or any other SQL
server) on [Google App Engine Flexible][flexible].

This sample has instructions for both [MySQL][mysql] and [Postgres][postgres].

## Setup

### General steps
Before you can run or deploy the sample, you will need to do the following:

1. In order for some of the commands below to work, you need to enable the
Expand All @@ -26,6 +29,10 @@ SDK use the following command:
where `[YOUR_INSTANCE_NAME]` is the name you chose in step 1 and
`[YOUR_INSTANCE_ROOT_PASSWORD]` is a password of your choice.

1. Using the [Cloud SQL console][sql_console], select your Cloud SQL instance.
Then, create a [user][user] (using the button in the *Access Control* > *Users* tab) and a
[database][database] (using the button in the *Databases* tab).

1. Create and download a [Service Account][service] for your project. You will
use this service account to connect to your Cloud SQL instance locally.

Expand All @@ -35,51 +42,60 @@ use this service account to connect to your Cloud SQL instance locally.
machine:

./cloud_sql_proxy \
-instances=[YOUR_INSTANCE_CONNECTION_NAME]=tcp:3306 \
-instances=[YOUR_INSTANCE_CONNECTION_NAME]=tcp:[PORT] \
-credential_file=PATH_TO_YOUR_SERVICE_ACCOUNT_JSON_FILE

where `[YOUR_INSTANCE_CONNECTION_NAME]` is the connection name of your
instance on its Overview page in the Google Cloud Platform Console, or use
`[YOUR_PROJECT_ID]:[YOUR_REGION]:[YOUR_INSTANCE_NAME]`.
`[YOUR_PROJECT_ID]:[YOUR_REGION]:[YOUR_INSTANCE_NAME]`. If you're using
MySQL, `[PORT]` will be `3306`; for Postgres, it will be `5432`.

1. Use the MySQL command line tools (or a management tool of your choice) to
create a [new user][user] and [database][database] for your application:
1. In a separate terminal, set the `SQL_USER`, `SQL_PASSWORD`, and `SQL_DATABASE` environment
variables to their respective values. This allows your local app to connect to your Cloud SQL
instance through the proxy.

mysql -h 127.0.0.1 -P 3306 -u root -p
mysql> create database `YOUR_DATABASE`;
mysql> create user 'YOUR_USER'@'%' identified by 'PASSWORD';
mysql> grant all on YOUR_DATABASE.* to 'YOUR_USER'@'%';
export SQL_USER="..."
export SQL_PASSWORD="..."
export SQL_DATABASE="..."

1. Set the `MYSQL_USER`, `MYSQL_PASSWORD`, and `MYSQL_DATABASE` environment
variables (see below). This allows your local app to connect to your Cloud SQL
instance through the proxy.
### Choosing a SQL client
Choose which database connector to use via the `SQL_CLIENT` environment variable.

To use MySQL, set it to `mysql`:

export SQL_CLIENT="mysql"

To use Postgres, set it to `pg`:

export SQL_CLIENT="pg"

1. Update the values in in `app.yaml` with your instance configuration.
### Final setup steps
1. Update the values in `app.yaml` with your instance configuration.

1. Finally, run `createTables.js` to ensure that the database is properly
configured and to create the tables needed for the sample.

## Running locally
### Running locally

Refer to the [top-level README](../README.md) for instructions on running and deploying.

It's recommended to follow the instructions above to run the Cloud SQL proxy.
You will need to set the following environment variables via your shell before
running the sample:
You will need to set the appropriate environment variables (as shown above) and
run the following commands via your shell to run the sample:

export MYSQL_USER="YOUR_USER"
export MYSQL_PASSWORD="YOUR_PASSWORD"
export MYSQL_DATABASE="YOUR_DATABASE"
npm install
npm start

[sql]: https://cloud.google.com/sql/
[flexible]: https://cloud.google.com/appengine
[gen]: https://cloud.google.com/sql/docs/create-instance
[console]: https://console.developers.google.com
[sql_console]: https://console.developers.google.com/sql/instances/
[sdk]: https://cloud.google.com/sdk
[service]: https://cloud.google.com/sql/docs/external#createServiceAccount
[proxy]: https://cloud.google.com/sql/docs/external#install
[start]: https://cloud.google.com/sql/docs/external#6_start_the_proxy
[user]: https://cloud.google.com/sql/docs/create-user
[database]: https://cloud.google.com/sql/docs/create-database
[mysql]: https://www.mysql.com/downloads/
[postgres]: https://www.postgresql.org/download/
7 changes: 4 additions & 3 deletions appengine/cloudsql/app.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ env: flex

# [START env]
env_variables:
MYSQL_USER: YOUR_USER
MYSQL_PASSWORD: YOUR_PASSWORD
MYSQL_DATABASE: YOUR_DATABASE
SQL_USER: YOUR_USER
SQL_PASSWORD: YOUR_PASSWORD
SQL_DATABASE: YOUR_DATABASE
# e.g. my-awesome-project:us-central1:my-cloud-sql-instance
INSTANCE_CONNECTION_NAME: YOUR_INSTANCE_CONNECTION_NAME
SQL_CLIENT: YOUR_SQL_CLIENT # either 'pg' or 'mysql' (all lowercase)
# [END env]

# [START cloudsql_settings]
Expand Down
105 changes: 60 additions & 45 deletions appengine/cloudsql/createTables.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,71 +13,86 @@
* limitations under the License.
*/

'use strict';

// Require process, so we can mock environment variables
const process = require('process');

// [START createTables]
// [START setup]
const mysql = require('mysql');
const Knex = require('knex');
const prompt = require('prompt');
// [END setup]

// [START createTable]
const SQL_STRING = `CREATE TABLE visits (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
timestamp DATETIME NULL,
userIp VARCHAR(46) NULL,
PRIMARY KEY (id)
);`;

/**
* Create the "visits" table.
*
* @param {object} connection A mysql connection object.
* @param {function} callback The callback function.
* @param {object} knex A Knex client object.
*/
function createTable (connection, callback) {
connection.query(SQL_STRING, callback);
function createTable (knex) {
return knex.schema.createTable('visits', (table) => {
table.increments();
table.timestamp('timestamp');
table.string('userIp');
})
.then(() => {
console.log(`Successfully created 'visits' table.`);
return knex;
})
.catch((err) => {
console.error(`Failed to create 'visits' table:`, err);
return knex;
});
}
// [END createTable]

// [START getConnection]
const FIELDS = ['user', 'password', 'database'];

/**
* Ask the user for connection configuration and create a new connection.
*
* @param {function} callback The callback function.
*/
function getConnection (callback) {
prompt.start();
prompt.get(FIELDS, (err, config) => {
if (err) {
callback(err);
return;
}

const user = encodeURIComponent(config.user);
const password = encodeURIComponent(config.password);
const database = encodeURIComponent(config.database);
function getConnection () {
const FIELDS = ['user', 'password', 'database'];
return new Promise((resolve, reject) => {
prompt.start();
prompt.get(FIELDS, (err, config) => {
if (err) {
return reject(err);
}

const uri = `mysql://${user}:${password}@127.0.0.1:3306/${database}`;
callback(null, mysql.createConnection(uri));
// Connect to the database
return resolve(Knex({
client: process.env.SQL_CLIENT,
connection: config
}));
});
});
}
// [END getConnection]

// [START main]
getConnection((err, connection) => {
if (err) {
console.error(err);
return;
}
createTable(connection, (err, result) => {
connection.end();
if (err) {
console.error(err);
return;
}
console.log(result);
});
});
// [END main]
exports.main = function () {
// [START main]
getConnection()
.then((knex) => {
return createTable(knex);
})
.then((knex) => {
return knex.destroy();
})
.catch((err, knex) => {
console.error(`Failed to create database connection:`, err);
if (knex) {
knex.destroy();
}
});
// [END main]
};
// [END createTables]

// Get type of SQL client to use
const sqlClient = process.env.SQL_CLIENT;
if (sqlClient === 'pg' || sqlClient === 'mysql') {
exports.main();
} else {
throw new Error(`The SQL_CLIENT environment variable must be set to lowercase 'pg' or 'mysql'.`);
}
23 changes: 12 additions & 11 deletions appengine/cloudsql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
},
"dependencies": {
"express": "4.15.2",
"knex": "^0.13.0",
"mysql": "2.13.0",
"pg": "^6.2.3",
"prompt": "1.0.0"
},
"devDependencies": {
Expand All @@ -35,19 +37,18 @@
"test": {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing a dependency on pg. Run yarn add pg

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing also a dependency on knex

"app": {
"requiredEnvVars": [
"MYSQL_USER",
"MYSQL_PASSWORD",
"MYSQL_DATABASE",
"YOUR_INSTANCE_CONNECTION_NAME"
"SQL_CLIENT",
"SQL_USER",
"SQL_PASSWORD",
"SQL_DATABASE",
"INSTANCE_CONNECTION_NAME"
],
"msg": "Last 10 visits:",
"args": ["server.js"]
},
"deploy": {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why remove this configuration?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The line below it seems to be MySQL-specific environment variables - but if we use the same environment variables for both clients, then I'll add it back in + update it accordingly.

"substitutions": "YOUR_USER=$MYSQL_USER,YOUR_PASSWORD=$MYSQL_PASSWORD,YOUR_DATABASE=$MYSQL_DATABASE,YOUR_INSTANCE_CONNECTION_NAME=$INSTANCE_CONNECTION_NAME"
"substitutions": "YOUR_SQL_CLIENT=$SQL_CLIENT,YOUR_USER=$SQL_USER,YOUR_PASSWORD=$SQL_PASSWORD,YOUR_DATABASE=$SQL_DATABASE,YOUR_INSTANCE_CONNECTION_NAME=$INSTANCE_CONNECTION_NAME",
"args": [
"server.js"
]
}
},
"requiresKeyFile": true,
"requiresProjectId": true
}
}
}
Loading