Skip to content

Commit

Permalink
🐛 Add support for asynchronous custom schema values in the Schema f…
Browse files Browse the repository at this point in the history
…ield class
  • Loading branch information
skerit committed Mar 11, 2024
1 parent 1fb15ad commit 61e0ef3
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 38 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* Fix unnamed sub-schemas not being able to be normalized properly
* Add `ForeignKey` field
* Fix `Alchemy.Client.Schema.isSchema(value)` never returning true
* Add support for asynchronous custom schema values in the `Schema` field class

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

Expand Down
147 changes: 109 additions & 38 deletions lib/app/helper_field/schema_field.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ SchemaField.setProperty(function requires_translating() {
* @param {Object} record This *should* be the schema context (might not be the root)
* @param {string} some_path Some path to a field in the wanted schema
*
* @return {Schema}
* @return {Alchemy.Schema|Pledge<Alchemy.Schema>}
*/
SchemaField.setMethod(function getSubschema(record, some_path) {

Expand All @@ -142,7 +142,7 @@ SchemaField.setMethod(function getSubschema(record, some_path) {
* @param {string} some_path Some path to a field in the wanted schema
* @param {string} schema The schema path to resolve
*
* @return {Schema}
* @return {Alchemy.Schema|Pledge<Alchemy.Schema>}
*/
SchemaField.setMethod(function resolveSchemaPath(context_schema, record, field_path, schema_path) {

Expand Down Expand Up @@ -221,11 +221,10 @@ SchemaField.setMethod(function resolveSchemaPath(context_schema, record, field_p

/**
* Get the subschema via an association
* @TODO: Work in progress!
*
* @author Jelle De Loecker <[email protected]>
* @since 0.2.0
* @version 1.3.21
* @version 1.4.0
*
* @param {Object} record This *should* be the schema context (might not be the root)
* @param {string} path The path inside the associated schema
Expand All @@ -237,33 +236,33 @@ SchemaField.setMethod(function getSubschemaFromAssociation(record, path, associa

let local_value = record[association.options.local_key];

console.log('Getting schema from association:', association, 'with local value:', local_value);

if (!local_value) {
return false;
}

const associated_model = alchemy.getModel(association.model_name);

console.log(' -- Model:', associated_model)

if (!associated_model) {
return false;
}

return Pledge.Swift.execute(async () => {

let result = await associated_model.findByValues({
[association.options.foreign_key]: local_value,
});

console.log('Gound...', result);
let result = await associated_model.resolveRemoteSchemaRequest(
this,
association.options.foreign_key,
local_value,
path
);

if (!result) {
return null;
}

console.log('Looking for', associated_model.schema);
// If it already is a schema, return that
if (Classes.Alchemy.Client.Schema.isSchema(result)) {
return result;
}

let found_schema = this.resolveSchemaPath(associated_model.schema, result, path, path);

Expand Down Expand Up @@ -308,7 +307,7 @@ SchemaField.setMethod(function _toDatasource(value, holder, datasource, callback
*
* @author Jelle De Loecker <[email protected]>
* @since 0.2.0
* @version 1.3.1
* @version 1.4.0
*
* @param {Object} value Value of field, an object in this case
* @param {Object} data The data object containing `value`
Expand All @@ -334,6 +333,39 @@ SchemaField.setMethod(function _toDatasourceFromValue(value, holder, datasource,

sub_schema = this.getSubschema(record);

if (Pledge.isThenable(sub_schema)) {
let pledge = new Pledge.Swift();

Pledge.Swift.done(sub_schema, (err, sub_schema) => {
if (err) {
pledge.reject(err);
return callback(err);
}

pledge.resolve(this._toDatasourceFromValueWithSubSchema(value, holder, record, sub_schema, datasource, callback));
});

return pledge;
} else {
return this._toDatasourceFromValueWithSubSchema(value, holder, record, sub_schema, datasource, callback);
}
});

/**
* Cast all the subschema values using their _toDatasource method
*
* @author Jelle De Loecker <[email protected]>
* @since 0.2.0
* @version 1.4.0
*
* @param {Object} value Value of field, an object in this case
* @param {Object} data The data object containing `value`
* @param {Datasource} datasource The destination datasource
*
* @return {Object}
*/
SchemaField.setMethod(function _toDatasourceFromValueWithSubSchema(value, holder, record, sub_schema, datasource, callback) {

// If the sub schema has been found, return it now
if (sub_schema) {
return datasource.toDatasource(sub_schema, value, callback);
Expand Down Expand Up @@ -371,7 +403,14 @@ SchemaField.setMethod(function _toDatasourceFromValue(value, holder, datasource,
// Try getting the schema again
sub_schema = that.getSubschema(record);

datasource.toDatasource(sub_schema, value, callback);
Pledge.Swift.done(sub_schema, (err, sub_schema) => {

if (err) {
return callback(err);
}

datasource.toDatasource(sub_schema, value, callback);
});
});

return;
Expand Down Expand Up @@ -439,28 +478,6 @@ SchemaField.setMethod(function _toApp(query, options, value, callback) {
*/
SchemaField.setMethod(async function _toAppFromValue(query, options, value, callback) {

var that = this,
Dummy,
item,
name;

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

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

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
get_associations_recursive_level = 0;
}

let record;

if (options.parent_value) {
Expand Down Expand Up @@ -488,6 +505,60 @@ SchemaField.setMethod(async function _toAppFromValue(query, options, value, call

let sub_schema = this.getSubschema(record);

if (Pledge.isThenable(sub_schema)) {

let pledge = new Pledge.Swift();

Pledge.Swift.done(sub_schema, (err, sub_schema) => {

if (err) {
pledge.reject(err);
return callback(err);
}

this._toAppFromValueWithSubSchema(query, options, value, sub_schema, record, callback);
});

return pledge;
} else {
return this._toAppFromValueWithSubSchema(query, options, value, sub_schema, record, callback);
}
});

/**
* Turn datasource data into app data
*
* @author Jelle De Loecker <[email protected]>
* @since 0.2.0
* @version 1.4.0
*
* @param {Mixed} value
* @param {Function} callback
*/
SchemaField.setMethod(async function _toAppFromValueWithSubSchema(query, options, value, sub_schema, record, callback) {

let that = this,
Dummy,
item,
name;

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

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

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
get_associations_recursive_level = 0;
}

// If the sub schema has been found, return it now
if (sub_schema) {
let tasks = {};
Expand Down
32 changes: 32 additions & 0 deletions lib/app/helper_model/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -982,6 +982,38 @@ Model.setMethod(function findByPk(pk, options, callback) {
return this.find('first', criteria, callback);
});

/**
* Return the context for resolving a remote schema request.
* The only thing we probably need to do is return a document.
*
* @deprecated
*
* @author Jelle De Loecker <[email protected]>
* @since 1.4.0
* @version 1.4.0
*
* @param {Alchemy.Field.Schema} external_field
* @param {string} our_field_name
* @param {*} our_field_value
* @param {string} schema_path
*
* @return {Alchemy.Document|Object|Schema}
*/
Model.setMethod(async function resolveRemoteSchemaRequest(external_field, our_field_name, our_field_value, schema_path) {

let doc = await this.findByValues({
[our_field_name]: our_field_value,
});

if (!doc) {
return null;
}

let found_schema = external_field.resolveSchemaPath(this.schema, doc, schema_path, schema_path);

return found_schema;
});

/**
* Query the database by key-val attributes, return the first result
*
Expand Down

0 comments on commit 61e0ef3

Please sign in to comment.