passing another test

This commit is contained in:
Drew Gross
2016-06-11 00:43:02 -07:00
parent 803b9be97a
commit 634d672ad1
6 changed files with 134 additions and 34 deletions

View File

@@ -10,6 +10,7 @@ const parseTypeToPostgresType = type => {
case 'Object': return 'jsonb';
case 'Boolean': return 'boolean';
case 'Pointer': return 'char(10)';
case 'Number': return 'double precision';
case 'Array':
if (type.contents && type.contents.type === 'String') {
return 'text[]';
@@ -69,8 +70,8 @@ export class PostgresStorageAdapter {
}
addFieldIfNotExists(className, fieldName, type) {
// TODO: Doing this in a transaction is probably a good idea.
return this._client.query('ALTER TABLE $<className:name> ADD COLUMN $<fieldName:name> text', { className, fieldName })
// TODO: Doing this in a transaction might be a good idea.
return this._client.query('ALTER TABLE $<className:name> ADD COLUMN $<fieldName:name> $<postgresType:raw>', { className, fieldName, postgresType: parseTypeToPostgresType(type) })
.catch(error => {
if (error.code === PostgresRelationDoesNotExistError) {
return this.createClass(className, { fields: { [fieldName]: type } })
@@ -161,7 +162,7 @@ export class PostgresStorageAdapter {
});
}
// TODO: remove the mongo format dependency
// TODO: remove the mongo format dependency in the return value
createObject(className, schema, object) {
let columnsArray = [];
let valuesArray = [];
@@ -181,7 +182,7 @@ export class PostgresStorageAdapter {
});
let columnsPattern = columnsArray.map((col, index) => `$${index + 2}:name`).join(',');
let valuesPattern = valuesArray.map((val, index) => `$${index + 2 + columnsArray.length}`).join(',');
return this._client.query(`INSERT INTO $1~ (${columnsPattern}) VALUES (${valuesPattern})`, [className, ...columnsArray, ...valuesArray])
return this._client.query(`INSERT INTO $1:name (${columnsPattern}) VALUES (${valuesPattern})`, [className, ...columnsArray, ...valuesArray])
.then(() => ({ ops: [object] }))
}
@@ -204,9 +205,53 @@ export class PostgresStorageAdapter {
return Promise.reject('Not implented yet.')
}
// Hopefully we can get rid of this in favor of updateObjectsByQuery.
// Return value not currently well specified.
findOneAndUpdate(className, schema, query, update) {
return Promise.reject('Not implented yet.')
let conditionPatterns = [];
let updatePatterns = [];
let values = []
values.push(className);
let index = 2;
for (let fieldName in update) {
let fieldValue = update[fieldName];
if (fieldValue.__op === 'Increment') {
updatePatterns.push(`$${index}:name = COALESCE($${index}:name, 0) + $${index + 1}`);
values.push(fieldName, fieldValue.amount);
index += 2;
} else if (fieldName === 'updatedAt') { //TODO: stop special casing this. It should check for __type === 'Date' and use .iso
updatePatterns.push(`$${index}:name = $${index + 1}`)
values.push(fieldName, new Date(fieldValue));
index += 2;
} else {
return Promise.reject(new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, `Postgres doesn't support this type of update yet`));
}
}
for (let fieldName in query) {
let fieldValue = query[fieldName];
if (typeof fieldValue === 'string') {
conditionPatterns.push(`$${index}:name = $${index + 1}`);
values.push(fieldName, fieldValue);
index += 2;
} else if (Array.isArray(fieldValue.$in)) {
let inPatterns = [];
values.push(fieldName);
fieldValue.$in.forEach((listElem, listIndex) => {
values.push(listElem);
inPatterns.push(`$${index + 1 + listIndex}`);
});
conditionPatterns.push(`$${index}:name && ARRAY[${inPatterns.join(',')}]`);
index = index + 1 + inPatterns.length;
} else {
return Promise.reject(new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, `Postgres doesn't support this type of request yet`));
}
}
let qs = `UPDATE $1:name SET ${updatePatterns.join(',')} WHERE ${conditionPatterns.join(' AND ')} RETURNING *`;
return this._client.query(qs, values)
.then(val => {
return val[0];
})
}
// Hopefully we can get rid of this. It's only used for config and hooks.
@@ -216,11 +261,61 @@ export class PostgresStorageAdapter {
// Executes a find. Accepts: className, query in Parse format, and { skip, limit, sort }.
find(className, schema, query, { skip, limit, sort }) {
return this._client.query("SELECT * FROM $<className:name>", { className })
let conditionPatterns = [];
let values = [];
values.push(className);
let index = 2;
for (let fieldName in query) {
let fieldValue = query[fieldName];
if (typeof fieldValue === 'string') {
conditionPatterns.push(`$${index}:name = $${index + 1}`);
values.push(fieldName, fieldValue);
index += 2;
} else if (fieldValue.$ne) {
conditionPatterns.push(`$${index}:name <> $${index + 1}`);
values.push(fieldName, fieldValue.$ne)
index += 2;
} else if (Array.isArray(fieldValue.$in)) {
let inPatterns = [];
values.push(fieldName);
fieldValue.$in.forEach((listElem, listIndex) => {
values.push(listElem);
inPatterns.push(`$${index + 1 + listIndex}`);
});
conditionPatterns.push(`$${index}:name IN (${inPatterns.join(',')})`);
index = index + 1 + inPatterns.length;
} else if (fieldValue.__type === 'Pointer') {
conditionPatterns.push(`$${index}:name = $${index + 1}`);
values.push(fieldName, fieldValue.objectId);
index += 2;
} else {
return Promise.reject(new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, "Postgres doesn't support this query type yet"));
}
}
return this._client.query(`SELECT * FROM $1:name WHERE ${conditionPatterns.join(' AND ')}`, values)
.then(results => results.map(object => {
Object.keys(schema.fields).filter(field => schema.fields[field].type === 'Pointer').forEach(fieldName => {
object[fieldName] = { objectId: object[fieldName], __type: 'Pointer', className: schema.fields[fieldName].targetClass };
});
//TODO: remove this reliance on the mongo format. DB adapter shouldn't know there is a difference between created at and any other date field.
if (object.createdAt) {
object.createdAt = object.createdAt.toISOString();
}
if (object.updatedAt) {
object.updatedAt = object.updatedAt.toISOString();
}
if (object.expiresAt) {
object.expiresAt = { __type: 'Date', iso: object.expiresAt.toISOString() };
}
for (let fieldName in object) {
if (object[fieldName] === null) {
delete object[fieldName];
}
}
return object;
}))
}