Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot Define Mapper To Include a Key That Does Not Exist With DefaultIncludes #40

Open
homestar9 opened this issue Sep 9, 2024 · 4 comments

Comments

@homestar9
Copy link
Contributor

homestar9 commented Sep 9, 2024

Defining a mapper to include a key that doesn't exist within the model will throw an exception if the mapper exists inside of the model, and not outside.

Steps to reproduce this issue?

Update the test-harness User model and add the "foo" mapper inside the model and also add optionally it to the list of defaultIncludes.

this.memento = {
	// Default properties to serialize
	defaultIncludes : [
		"userId",
		"blogUrl",
		"fname:firstName",
		"lname:lastName"
		"foo" // <--- (optional) This property does not exist in the model
	],
	// Mappers to serialize the properties
	mappers = {
		// Add the mapper for the key that doesn't exist.
		"foo" : function( _, memento ){
			return memento.firstName & " " & memento.lastName;
		}
	}
};

Now, when you call getMemento() on the object, you will get a missing method error that getFoo can't be found.

Based on what I have discovered by playing around with the test harness, you can define a mapper to a key that doesn't exist if you define the mapper outside the model and specify the name in the list of includes. However, it breaks if the mapper exists inside the model and you use defaultIncludes inside the model or includes outside.

// Mapper outside the model: This works
var result = user.getMemento(
    includes = [ "foo" ],
    mappers = {
		"foo" : function( _, memento ){
			return memento.firstName & " " & memento.lastName;
		}
	}
}

// Mapper inside the model: This does not work
var result = user.getMemento(
    includes = [ "foo" ]
}

The only workaround is to explicitly add the property (or virtual attribute if you're using Quick) to your model or define your mappers outside of the model.

@lmajano
Copy link
Contributor

lmajano commented Sep 14, 2024

This is the code that processes the includes

if ( arguments.trustedGetters || structKeyExists( this, "get#item#" ) ) {
				try {
					thisValue = invoke( this, "get#item#" );
				} catch ( any e ) {
					// Unless trusted getters is on and there is a mapper for this item rethrow the exception.
					if ( !arguments.trustedGetters || !structKeyExists( arguments.mappers, item ) ) {
						rethrow;
					}
				}
				// If the key doesn't exist and there is no mapper for the item, go to the next item.
			} else if ( !structKeyExists( thisMemento.mappers, item ) ) {
				continue;
			}

As you can see it does check the mappers. However, do you happen to have trusted getters to TRUE??

@homestar9
Copy link
Contributor Author

homestar9 commented Jan 13, 2025

You're right @lmajano , and I think I see the problem. Quick, by default, has trustedGetters set to true. I'm not sure if Quick requires it to be set to true, but setting it to false by overriding it, appears to let the mappers do their thing.

One suggestion that might be cool, so it doesn't mess with Quick would be to allow for Mementifier profiles to be able to override trustedSetters. So you could have something like this:

// Mememtifier Customization
private void function setUpMementifier() {
	
	// Override Quick's defaults with some mementifier profiles
	this.memento = {
		"profiles": {
			// Memento for autocomplete suggestions
			"suggest": {
				"trustedGetters": false, // <-- Override defaults (this might be a useful feature)
				"defaultIncludes": [ "id", "name", "description", "thumbnail" ],
				"mappers": {
					"name": function( _, memento ) {
						return getSuggestName();
					},
					"description": function( _, memento ) {
						return getSuggestDescription();
					},
					"thumbnail": function( _, memento ) {
						return getSuggestThumbnail();
					}
				}
			}
		}
	}
	
        // Let Quick setup the mementifier defaults
	super.setupMementifier();

}

Current way to override Quick's trustedSetters setting (Warning: This might break Quick!)

// Mememtifier Customization
private void function setUpMementifier() {
	
    // Let Quick setup the mementifier defaults
	super.setupMementifier();
	
	// Override trustedGetters
	this.memento.trustedGetters = false;
	
}

@elpete
Copy link
Contributor

elpete commented Jan 13, 2025

trustedGetters is the only way I have with mementifier to trigger onMissingMethod in Quick. I need that for retrieving relationships. To avoid setting that flag I would need a way to dynamically provide a list of valid keys.

@homestar9
Copy link
Contributor Author

homestar9 commented Jan 13, 2025

Can confirm: trustedSetters needs to be true for Quick to work properly.

Possible workaround if you need to use a memento profile, and you don't need Quick's onMissingMethod, you can pass trustedGetters as an argument in a handler like this:

getInstance( "User" )
    .asMemento( profile="suggest", trustedGetters=false )
    .simplePaginate( 1, 10 );

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants