Skip to content

Commit

Permalink
🐛 Fix unnamed sub-schemas not being able to be normalized properly
Browse files Browse the repository at this point in the history
  • Loading branch information
skerit committed Mar 10, 2024
1 parent b5e5394 commit 54f4b99
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 28 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* Add `should_add_exports()` SCSS function
* Add `postcss-prune-var` dependency to remove unused variables from CSS files
* Don't make `Alchemy#getResource()` helper method overwrite params data
* Fix unnamed sub-schemas not being able to be normalized properly

## 1.4.0-alpha.3 (2024-02-25)

Expand Down
15 changes: 9 additions & 6 deletions lib/app/helper/enum_values.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ EnumMap.setMethod(function set(name, value) {
*
* @author Jelle De Loecker <[email protected]>
* @since 1.2.1
* @version 1.3.6
* @version 1.4.0
*
* @param {WeakMap} wm
*
Expand All @@ -136,26 +136,29 @@ EnumMap.setMethod(function toHawkejs(wm) {
cloned_entry.type = 'function';
}

// Always add the `schema` property if it's there
if (val.schema) {
cloned_entry.schema = JSON.clone(val.schema, 'toHawkejs', wm);
}

let key,
let field_key,
field_val;

for (key in val) {
// Now we need to look for other `Schema`-like instances
// and add those too
for (field_key in val) {

if (key == 'schema') {
if (field_key == 'schema') {
continue;
}

field_val = val[key];
field_val = val[field_key];

if (field_val) {
const SchemaClass = Blast.isBrowser ? Classes.Alchemy.Client.Schema : Classes.Alchemy.Schema;

if (field_val instanceof SchemaClass) {
cloned_entry[key] = JSON.clone(field_val, 'toHawkejs', wm);
cloned_entry[field_key] = JSON.clone(field_val, 'toHawkejs', wm);
}
}
}
Expand Down
35 changes: 18 additions & 17 deletions lib/app/helper_field/schema_field.js
Original file line number Diff line number Diff line change
Expand Up @@ -418,34 +418,31 @@ SchemaField.setMethod(function _toApp(query, options, value, callback) {
SchemaField.setMethod(async function _toAppFromValue(query, options, value, callback) {

var that = this,
recursive,
Dummy,
item,
name;

// Don't get schema associated records if recursive is disabled
recursive = options.recursive;
let get_associations_recursive_level = options.recursive;

if (recursive == null) {
if (get_associations_recursive_level == null) {
if (this.options?.recursive != null) {
recursive = this.options.recursive;
get_associations_recursive_level = this.options.recursive;
} else {
recursive = 1;
get_associations_recursive_level = 1;
}
}

if (recursive && Blast.isBrowser) {
if (get_associations_recursive_level && Blast.isBrowser) {
// @TODO: this will mostly fail on the browser, so disable it for now.
// Maybe make it configurable later
recursive = 0;
get_associations_recursive_level = 0;
}

let record;

if (options.parent_value) {
record = {
[this.schema.name] : options.parent_value
};
record = options.parent_value;
} else if (options._root_data) {

let root_data = options._root_data;
Expand All @@ -454,14 +451,16 @@ SchemaField.setMethod(async function _toAppFromValue(query, options, value, call
root_data = root_data[this.schema.name];
}

record = root_data;
} else {
record = {
[this.schema.name] : root_data
[this.name] : value,
};
} else {
}

if (this.schema.name) {
record = {
[this.schema.name] : {
[this.name] : value,
}
[this.schema.name] : record,
};
}

Expand Down Expand Up @@ -490,10 +489,12 @@ SchemaField.setMethod(async function _toAppFromValue(query, options, value, call
});

value = await Function.parallel(4, tasks);
} else {
console.warn('Failed to find sub schema for', this.name, 'in', record);
}

// Get associated records if the subschema has associations defined
if (recursive && this.field_schema && !Object.isEmpty(this.field_schema.associations)) {
if (get_associations_recursive_level && this.field_schema && !Object.isEmpty(this.field_schema.associations)) {

name = this.name + 'FieldModel';
Dummy = alchemy.getModel('Model', false);
Expand All @@ -516,7 +517,7 @@ SchemaField.setMethod(async function _toAppFromValue(query, options, value, call
sub_criteria.setOption('_root_data', options._root_data);
sub_criteria.setOption('_parent_field', that);
sub_criteria.setOption('_parent_model', that.schema.model_name);
sub_criteria.setOption('recursive', recursive);
sub_criteria.setOption('recursive', get_associations_recursive_level);

sub_criteria.setOption('associations', this.field_schema.associations);

Expand Down
115 changes: 110 additions & 5 deletions test/04-field.js
Original file line number Diff line number Diff line change
Expand Up @@ -861,30 +861,39 @@ describe('Field.FixedDecimal', function() {
});
});

let flobotonum_to_app_counter = 0;
let flobotonum_to_ds_counter = 0;

describe('Field.Schema', function() {

before(function(next) {
next = Function.regulate(next);

let to_app_counter = 0;

const FlobotonumField = Function.inherits('Alchemy.Field', 'Flobotonum');
FlobotonumField.setDatatype('object');
FlobotonumField.setSelfContained(true);
FlobotonumField.setMethod(function _toApp(query, options, value, callback) {

let result = {
type : 'flobotonum',
value : value,
value : value?.main_value,
to_apped : true,
to_app_counter : ++to_app_counter,
to_app_counter : ++flobotonum_to_app_counter,
};

callback(null, result);
});

FlobotonumField.setMethod(function _toDatasource(value, data, datasource, callback) {
callback(null, value.value);

let main_value = value.value;

let value_wrapper = {
main_value,
to_ds_counter: ++flobotonum_to_ds_counter,
};

callback(null, value_wrapper);
});

let QuestComponents = alchemy.getClassGroup('all_quest_component');
Expand Down Expand Up @@ -1036,6 +1045,102 @@ describe('Field.Schema', function() {
assert.strictEqual(second.settings?.flobotonum?.type, 'flobotonum', 'The value should have been passed through `toApp`');
assert.strictEqual(second.settings?.flobotonum?.value?.morestuff, true, 'The inner flobotonum value should have been saved');
assert.strictEqual(second.settings?.flobotonum?.to_app_counter, 6, 'This should have been the sixth `toApp` call for this field');
});

it('should handle nested schemas with custom property names', async () => {

flobotonum_to_app_counter = 0;

const PropertyType = Function.inherits('Alchemy.Base', 'PropertyType', 'PropertyType');

PropertyType.constitute(function setConfigSchema() {
// Create a new schema
let configuration_schema = alchemy.createSchema();
this.configuration_schema = configuration_schema;
});

PropertyType.constitute(function setValueSchema() {
// Create a new schema
let value_schema = alchemy.createSchema();
this.value_schema = value_schema;
});

const StringType = Function.inherits('PropertyType', 'String');

StringType.constitute(function setSchema() {

this.value_schema.addField('value', 'String', {
description : 'The actual value of this string property',
});

this.configuration_schema.addField('max_length', 'Number', {
description : 'The maximum length of the string',
});

this.configuration_schema.addField('flobotonum', 'Flobotonum');
});

const UnitType = Function.inherits('Alchemy.Base', 'UnitType', 'UnitType');
const TypeDefinitionType = Function.inherits('UnitType', 'TypeDefinition');

TypeDefinitionType.constitute(function setSchema() {

this.schema = alchemy.createSchema();

this.schema.addField('defined_type', 'Enum', {
description : 'The defined type of this property',
values : PropertyType.getDescendantsDict(),
});

this.schema.addField('defined_type_configuration', 'Schema', {
description : 'The configuration of the defined type',
schema : 'defined_type.configuration_schema',
});
});

let pledge = new Classes.Pledge.Swift();

const Unit = Function.inherits('Alchemy.Model', 'SwUnit');
Unit.constitute(function addFields() {

this.addField('unit_type', 'Enum', {
description : 'The type of this unit',
values : UnitType.getDescendantsDict(),
});

this.addField('unit_type_settings', 'Schema', {
schema : 'unit_type',
});

pledge.resolve();
});

await pledge;

let UnitModel = Model.get('SwUnit');
let unit = UnitModel.createDocument();
unit.unit_type = 'type_definition';
unit.unit_type_settings = {
defined_type : 'string',
defined_type_configuration : {
max_length : '10',
flobotonum: {
value : {
xstuff : true
}
}
},
};

await unit.save();

unit = await UnitModel.findByPk(unit._id);
const type_settings = unit.unit_type_settings || {};

assert.strictEqual(unit.unit_type, 'type_definition');
assert.strictEqual(type_settings.defined_type, 'string');
assert.strictEqual(type_settings.defined_type_configuration?.max_length, 10);
assert.strictEqual(type_settings.defined_type_configuration?.flobotonum?.value?.xstuff, true);
assert.strictEqual(type_settings.defined_type_configuration?.flobotonum?.to_app_counter, 2);
});
});

0 comments on commit 54f4b99

Please sign in to comment.