diff --git a/spec/Schema.spec.js b/spec/Schema.spec.js index 1d3e203e..373672d7 100644 --- a/spec/Schema.spec.js +++ b/spec/Schema.spec.js @@ -181,7 +181,7 @@ describe('SchemaController', () => { it('can add classes without needing an object', done => { config.database.loadSchema() .then(schema => schema.addClassIfNotExists('NewClass', { - foo: {type: 'String'} + foo: {type: 'String'}, })) .then(actualSchema => { const expectedSchema = { @@ -210,6 +210,81 @@ describe('SchemaController', () => { }); }); + it('can update classes without needing an object', done => { + const levelPermissions = { + find: { '*': true }, + get: { '*': true }, + create: { '*': true }, + update: { '*': true }, + delete: { '*': true }, + addField: { '*': true }, + }; + config.database.loadSchema() + .then(schema => { + schema.validateObject('NewClass', { foo: 2 }) + .then(() => schema.reloadData()) + .then(() => schema.updateClass('NewClass', { + fooOne: {type: 'Number'}, + fooTwo: {type: 'Array'}, + fooThree: {type: 'Date'}, + fooFour: {type: 'Object'}, + fooFive: {type: 'Relation', targetClass: '_User' }, + fooSix: {type: 'String'}, + fooSeven: {type: 'Object' }, + fooEight: {type: 'String'}, + fooNine: {type: 'String'}, + fooTeen: {type: 'Number' }, + fooEleven: {type: 'String'}, + fooTwelve: {type: 'String'}, + fooThirteen: {type: 'String'}, + fooFourteen: {type: 'String'}, + fooFifteen: {type: 'String'}, + fooSixteen: {type: 'String'}, + fooEighteen: {type: 'String'}, + fooNineteen: {type: 'String'}, + }, levelPermissions, config.database)) + .then(actualSchema => { + const expectedSchema = { + className: 'NewClass', + fields: { + objectId: { type: 'String' }, + updatedAt: { type: 'Date' }, + createdAt: { type: 'Date' }, + ACL: { type: 'ACL' }, + foo: { type: 'Number' }, + fooOne: {type: 'Number'}, + fooTwo: {type: 'Array'}, + fooThree: {type: 'Date'}, + fooFour: {type: 'Object'}, + fooFive: {type: 'Relation', targetClass: '_User' }, + fooSix: {type: 'String'}, + fooSeven: {type: 'Object' }, + fooEight: {type: 'String'}, + fooNine: {type: 'String'}, + fooTeen: {type: 'Number' }, + fooEleven: {type: 'String'}, + fooTwelve: {type: 'String'}, + fooThirteen: {type: 'String'}, + fooFourteen: {type: 'String'}, + fooFifteen: {type: 'String'}, + fooSixteen: {type: 'String'}, + fooEighteen: {type: 'String'}, + fooNineteen: {type: 'String'}, + }, + classLevelPermissions: { ...levelPermissions }, + }; + + expect(dd(actualSchema, expectedSchema)).toEqual(undefined); + done(); + }) + .catch(error => { + console.trace(error); + done(); + fail('Error creating class: ' + JSON.stringify(error)); + }); + }); + }); + it('will fail to create a class if that class was already created by an object', done => { config.database.loadSchema() .then(schema => { diff --git a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js index 52aa47bc..c74e02bf 100644 --- a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js +++ b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js @@ -543,15 +543,15 @@ export class PostgresStorageAdapter { promise = t.none('CREATE TABLE IF NOT EXISTS $ ("relatedId" varChar(120), "owningId" varChar(120), PRIMARY KEY("relatedId", "owningId") )', {joinTable: `_Join:${fieldName}:${className}`}) } return promise.then(() => { - return t.any('SELECT "schema" FROM "_SCHEMA" WHERE "className" = $', {className}); + return t.any('SELECT "schema" FROM "_SCHEMA" WHERE "className" = $ and ("schema"::json->\'fields\'->$) is not null', {className, fieldName}); }).then(result => { - if (fieldName in result[0].schema.fields) { + if (result[0]) { throw "Attempted to add a field that already exists"; } else { - result[0].schema.fields[fieldName] = type; + const path = `{fields,${fieldName}}`; return t.none( - 'UPDATE "_SCHEMA" SET "schema"=$ WHERE "className"=$', - {schema: result[0].schema, className} + 'UPDATE "_SCHEMA" SET "schema"=jsonb_set("schema", $, $) WHERE "className"=$', + { path, type, className } ); } });