Wrap postgres class creation in a transaction (#2958)

This commit is contained in:
Kulshekhar Kabra
2016-10-29 05:53:37 +05:30
committed by Florent Vilmart
parent 0e78c28146
commit 22c790f23c

View File

@@ -4,6 +4,7 @@ const PostgresRelationDoesNotExistError = '42P01';
const PostgresDuplicateRelationError = '42P07'; const PostgresDuplicateRelationError = '42P07';
const PostgresDuplicateColumnError = '42701'; const PostgresDuplicateColumnError = '42701';
const PostgresUniqueIndexViolationError = '23505'; const PostgresUniqueIndexViolationError = '23505';
const PostgresTransactionAbortedError = '25P02';
const logger = require('../../../logger'); const logger = require('../../../logger');
const debug = function(){ const debug = function(){
@@ -385,8 +386,9 @@ export class PostgresStorageAdapter {
this._client = createClient(uri, databaseOptions); this._client = createClient(uri, databaseOptions);
} }
_ensureSchemaCollectionExists() { _ensureSchemaCollectionExists(conn) {
return this._client.none('CREATE TABLE "_SCHEMA" ( "className" varChar(120), "schema" jsonb, "isParseClass" bool, PRIMARY KEY ("className") )') conn = conn || this._client;
return conn.none('CREATE TABLE IF NOT EXISTS "_SCHEMA" ( "className" varChar(120), "schema" jsonb, "isParseClass" bool, PRIMARY KEY ("className") )')
.catch(error => { .catch(error => {
if (error.code === PostgresDuplicateRelationError || error.code === PostgresUniqueIndexViolationError) { if (error.code === PostgresDuplicateRelationError || error.code === PostgresUniqueIndexViolationError) {
// Table already exists, must have been created by a different request. Ignore error. // Table already exists, must have been created by a different request. Ignore error.
@@ -410,13 +412,20 @@ export class PostgresStorageAdapter {
} }
createClass(className, schema) { createClass(className, schema) {
return this.createTable(className, schema).then(() => { return this._client.tx(t => {
return this._client.none('INSERT INTO "_SCHEMA" ("className", "schema", "isParseClass") VALUES ($<className>, $<schema>, true)', { className, schema }); const q1 = this.createTable(className, schema, t);
const q2 = t.none('INSERT INTO "_SCHEMA" ("className", "schema", "isParseClass") VALUES ($<className>, $<schema>, true)', { className, schema });
return t.batch([q1, q2]);
}) })
.then(() => { .then(() => {
return toParseSchema(schema) return toParseSchema(schema)
}) })
.catch((err) => { .catch((err) => {
if (Array.isArray(err.data) && err.data.length > 1 && err.data[0].result.code === PostgresTransactionAbortedError) {
err = err.data[1].result;
}
if (err.code === PostgresUniqueIndexViolationError && err.detail.includes(className)) { if (err.code === PostgresUniqueIndexViolationError && err.detail.includes(className)) {
throw new Parse.Error(Parse.Error.DUPLICATE_VALUE, `Class ${className} already exists.`) throw new Parse.Error(Parse.Error.DUPLICATE_VALUE, `Class ${className} already exists.`)
} }
@@ -425,7 +434,8 @@ export class PostgresStorageAdapter {
} }
// Just create a table, do not insert in schema // Just create a table, do not insert in schema
createTable(className, schema) { createTable(className, schema, conn) {
conn = conn || this._client;
debug('createTable', className, schema); debug('createTable', className, schema);
let valuesArray = []; let valuesArray = [];
let patternsArray = []; let patternsArray = [];
@@ -458,10 +468,10 @@ export class PostgresStorageAdapter {
} }
index = index+2; index = index+2;
}); });
const qs = `CREATE TABLE $1:name (${patternsArray.join(',')})`; const qs = `CREATE TABLE IF NOT EXISTS $1:name (${patternsArray.join(',')})`;
const values = [className, ...valuesArray]; const values = [className, ...valuesArray];
return this._ensureSchemaCollectionExists() return this._ensureSchemaCollectionExists(conn)
.then(() => this._client.none(qs, values)) .then(() => conn.none(qs, values))
.catch(error => { .catch(error => {
if (error.code === PostgresDuplicateRelationError) { if (error.code === PostgresDuplicateRelationError) {
// Table already exists, must have been created by a different request. Ignore error. // Table already exists, must have been created by a different request. Ignore error.
@@ -471,7 +481,7 @@ export class PostgresStorageAdapter {
}).then(() => { }).then(() => {
// Create the relation tables // Create the relation tables
return Promise.all(relations.map((fieldName) => { return Promise.all(relations.map((fieldName) => {
return this._client.none('CREATE TABLE IF NOT EXISTS $<joinTable:name> ("relatedId" varChar(120), "owningId" varChar(120), PRIMARY KEY("relatedId", "owningId") )', {joinTable: `_Join:${fieldName}:${className}`}); return conn.none('CREATE TABLE IF NOT EXISTS $<joinTable:name> ("relatedId" varChar(120), "owningId" varChar(120), PRIMARY KEY("relatedId", "owningId") )', {joinTable: `_Join:${fieldName}:${className}`});
})); }));
}); });
} }