Can you use a Map instance as an easy-peasy store property? - node.js

ie.
const store = {
values: new Map(),
// (gross trivial accessor)
setValue: action( (state, payload) => {
state.values.set(payload.key, payload.value);
}
}
I'm curious because easy-peasy uses a Proxy on the store object (and objects nested within) so that in your action you can safely mutate the state object directly (https://easy-peasy.now.sh/docs/tutorials/primary-api.html#modifying-the-state). I don't know if this also works when using non Plain Old JavaScript Objects, such as Maps.

It looks like this is possible on certain versions, but not without first declaring support for the feature (so the code above will not work right out of the box, as of now). See here for more info: https://github.com/ctrlplusb/easy-peasy/issues/440

Related

How to pass nested data structures as properties in LitElement?

In a parent component I have something like:
render() => {
const data = {a:1,b:[1,2,3]}; // of course this is a simplified version of the code
return html`<child-component data=${data}></child-component>`
}
Which is basically equivalent to:
render() => {
const data = {a:1,b:[1,2,3]}; // of course this is a simplified version of the code
return html`<child-component data="[object Object]"></child-component>`
}
Which is basically useless...
Is there a simple way to pass complex object hierarchies into litElement components?
As far as I can tell, my options are:
Option 1. Use attributes: I'm a bit of a litElement noob so I'm not sure if this will work and I'm not sure how to make it work without having to make extra function calls. It would be nice if I could just do all the necessary work inside html.
Research in progress.
Option 2. Use Json.
Stringify the object in the parent component
render() => {
const data = {a:1,b:[1,2,3]}; // of course this is a simplified version of the code
return html`<child-component data=${JSON.stringify(data)}></child-component>`
}
then parse the json in the child component.
This just seems a bit inelegant to me though.
But it works.
In this case what you probably want is to pass the object as a property rather than as an attribute. For complex data such as objects, arrays, functions, etc. that's the preferred method.
You can do it with the following syntax:
render() => {
const data = {a:1,b:[1,2,3]};
// note the period (.), that's the token used to identify that you're passing data as a property
return html`<child-component .data=${data}></child-component>`
}
In general, you should probably give Lit's templating guide a read as some of the most common use cases are covered throughout it.

which nested data structure should I use for FluidFramework

If I want to use nested data structure, which data structure is better choose.
eg.
For eg1 case, It seems can not load children DDS data in 'hasInitialized()'.
For eg2, it seems a little complicated.
Is anyone can show some example for this case?
A DataObject contains a collection of one or more DDSes and nesting them allows you to create organizational structure. DDSes themselves can also be nested and retrieved in the initialization steps.
There are a few ways you can solve eg1 and I highlight two below.
For eg2 you're right that it's a bit complicated and generally not a pattern we are pushing at the moment. There are some example in the repo but you will find that they use a slightly different developer model then the HelloWorld. The SimpleComponentEmbed and the Pond are the best starting points if you want to explore DataObject embedding.
Using root SharedDirectory for nesting
The root SharedDirectory allows you to create sub-directories. This is a great way to manage collections of nested maps. Using sub-directories instead of putting a SharedMap on the root ensures creation and setting happens as one atomic action instead of two actions, (one to create and one to set).
The current draw back to this at the moment is that you have to listen to events on the root directory and see if it corresponds to your sub-directory. Eventing on sub-directories is being tracked with Issue #1403
protected async initializingFirstTime() {
const subDirectory = this.root.createSubDirectory("sub-dir");
subDirectory.createSubDirectory("sub-sub-dir");
}
protected async hasInitialized() {
const subDirectory = this.root.getSubDirectory("sub-dir");
const ssDir = subDirectory.getSubDirectory("sub-sub-dir");
this.root.on("valueChanged", (changed: IDirectoryValueChanged) => {
if (changed.path === ssDir.absolutePath) {
const newValue = ssDir.get(changed.key);
console.log(newValue);
}
});
// An easy way to trigger/test the above handler without user interaction
setTimeout(() => {
ssDir.set("foo", "bar2");
}, 10000); // 10 seconds
}
Using Nested DDSes
You can also store nested DDSes. The thing you need to remember is that you are storing/ retrieving the handle to the DDS. In the below example we are creating map1 with a key/value. We are string map1 in map2 which is being stored on the root DDS. We will then get the value from map1 by first getting map2 then map1 then the value.
protected async initializingFirstTime() {
const map1 = SharedMap.create(this.runtime);
map1.set("foo", "bar");
const map2 = SharedMap.create(this.runtime);
map2.set("map1", map1.handle);
this.root.set("map2", map2.handle);
}
protected async hasInitialized() {
const map2 = await this.root.get<IFluidHandle<SharedMap>>("map2").get();
const map1 = await map2.get<IFluidHandle<SharedMap>>("map1").get();
console.log(map1.get("foo"));
}

Dart: How do I convert an array of objects to an array of hashmaps?

I want to convert my objects to hashmaps so I can use the Flutter method channels to send data to Android.
I've thought of iterating through and mapping them one by one, but there's got to be a more elegant way to do this...
Example:
Object
class Something {
Something(this.what, this.the, this.fiddle);
final String what;
final int the;
final bool fiddle;
}
Somewhere else
List<Something> listOStuff = List<Something>.generate(10, (int index){
return Something(index.toString(), index, false,);
});
List<Map<String, dynamic>> parseToMaps(List<Something> listOStuff){
List<Map<String, dynamic>> results;
// do something crazy to get listOStuff into Map of primitive values for each object
// preferably a built in method of some sort... otherwise, i guess i'll just iterate...
// maybe even an imported package if such thing exists
return results;
}
List<Map<String, dynamic>> listOMaps = parseToMaps(listOStuff);
Something like this in Java
You can use the map and return the object that you want:
List<Map<String, dynamic>> listOMaps = listOStuff
.map((something) => {
"what": something.what,
"the": something.the,
"fiddle": something.fiddle,
})
.toList();
I'm not sure what exactly you're looking for, but there is a way to have custom objects encoded without having to specify it directly when you call the method.
What you have to do is implement a MethodCodec and/or MessageCodec that defines how your object is encoded and decoded. The easiest way is probably to subclass StandardMethodCodec and/or StandardMessageCodec (it might be enough to override StandardMessageCodec and pass it to StandardMessageCodec).
If you implement read & write correctly for your object, then all you have to do is pass the list of objects directly to your method call and flutter will handle the encoding.
Note that there are corresponding classes on the Android & iOS sides of things that you could use to have the data decoded directly to objects, and in fact you might have to implement them to get things to work depending on how you do it.

Specify RequiredCreationPolicy for non-Attributed Imports

I have an IoC wrapper that uses MEF as it's DI container, an applicable snippet of the wrapper is shown below.
public static bool TryGetComponent<T>(out T component)
{
CompositionContainer container = RetrieveContainer();
T retrievedComponent = container.GetExportedValueOrDefault<T>();
if (retrievedComponent.Equals(default(T)))
{
component = default(T);
return false;
}
component = retrievedComponent;
return true;
}
Most of the exported components in the CompositionContainer specify a CreationPolicy of "Any".
[PartCreationPolicy(CreationPolicy.Any)]
For types that I create I can easily use the following import attribute to get MEF to serve the exported types as NonShared instances.
[Import(RequiredCreationPolicy = CreationPolicy.NonShared)]
However, since my IoC wrapper must also be used by classes that do not use MEF or any of its Import attributes and must use my IoC API to obtain instances exported types. I need a way to specify the CreationPolicy when I programmatically use the CompositionContainer to GetExports and GetExportedValues. Is this even possible without using import attributes?
If you really want to query the container exactly like as if you had a ImportAttribute with RequiredCreationPolicy=NonShared then try creating your own custom ContractBasedImportDefinition. One of the parameters for to the contructor is a CreationPolicy that represents the required creation policy.
Something like:
container.GetExports(new ContractBasedImportDefinition(
AttributedModelServices.GetContractName(type),
AttributedModelServices.GetTypeIdentity(type),
null,
ImportCardinality.ZeroOrMore,
false,
false,
CreationPolicy.NonShared));
Of course you can adjust the parameters as necessary but this will get you moving in the right direction and will cause the container to create NonShared versions of any part that is marked as Any (which is the default).
Well, CreationPolicy is passed as part of a component's metadata. This means, you should be able to query the metadata for the part, and see if it exists. The way CreationPolicy is specified in metadata is to use the full type name System.ComponentModel.Composition.CreationPolicy as the key, and the enum result as the value. So, knowing this we can build an extension method:
public static T GetExportedValueOrDefault<T>(this CompositionContainer container, CreationPolicy creationPolicy)
{
var metadataKey = typeof(CreationPolicy).FullName;
var lazy = container.GetExportedValueOrDefault<T, IDictionary<string, object>>();
if (lazy == null)
return default(T);
if (lazy.Metadata.ContainsKey(metadataKey))
{
// If the creation policy matches the required, return.
if (((CreationPolicy)lazy.Metadata[metadataKey]) == creationPolicy)
return lazy.Value;
}
else
{
// Return the value as we assume it satisfies the default CreationPolicy = Any
return lazy.Value;
}
return default(T);
}
Now, firstly we create our expected key, and then we grab a Lazy<T, TMetadata> instance which includes the type and any associated metadata as a Lazy<T, IDictionary<string, object>> instance. If the lazy comes back as null, we can fail early because there were no matching parts at all.
Next, we can check the metadata dictionary Lazy.Metadata to determine if the metadata exists. If it does, we need to cast and compare against our chosen metadata. If that succeeds, return our part instance.
If that doesn't succeed (e.g., if the part is using the implicit CreationPolicy of Any [i.e., the PartCreationPolicyAttribute is omitted from the export]), we'll assume that the part can be returned, as we can match on the default Any creation policy, so we can match both NonShared and Shared parts.
You should be able to use this in place of the normal GetExportedValueOrDefault<T> call:
T retrievedComponent = container.GetExportedValueOrDefault<T>(CreationPolicy.NonShared);

Why missingMethod is not working for Closure?

UPDATE
I have to apologize for confusing the readers. After I got totally lost in the code, I reverted all my changes from Mercurial repo, carefully applied the same logic as before -- and it worked. The answers below helped me understand the (new to me) concept better, and for that I gave them upvotes.
Bottom line: if a call to a missing method happens within a closure, and resolution set to DELEGATE_FIRST, methodMissing() will be called on the delegate. If it doesn't -- check you own code, there is a typo somewhere.
Thanks a lot!
Edit:
OK, now that you've clarified what your are doing (somewhat ;--))
Another approach (one that I use for DSLs) is to parse your closure group to map via a ClosureToMap utility like this:
// converts given closure to map method => value pairs (1-d, if you need nested, ask)
class ClosureToMap {
Map map = [:]
ClosureToMap(Closure c) {
c.delegate = this
c.resolveStrategy = Closure.DELEGATE_FIRST
c.each{"$it"()}
}
def methodMissing(String name, args) {
if(!args.size()) return
map[name] = args[0]
}
def propertyMissing(String name) { name }
}
// Pass your closure to the utility and access the generated map
Map map = new ClosureToMap(your-closure-here)?.map
Now you can iterate through the map, perhaps adding methods to applicable MCL instance. For example, some of my domains have dynamic finders like:
def finders = {
userStatusPaid = { Boolean active = true->
eq {
active "$active"
paid true
}
}
}
I create a map using the ClosureToMap utility, and then iterate through, adding map keys (methods, like "userStatus") and values (in this case, closure "eq") to domain instance MCL, delegating the closure to our ORM, like so:
def injectFinders(Object instance) {
if(instance.hasProperty('finders')) {
Map m = ClosureToMap.new(instance.finders).map
m?.each{ String method, Closure cl->
cl.delegate = instance.orm
cl.resolveStrategy = Closure.DELEGATE_FIRST
instance.orm.metaClass."$method" = cl
}
}
}
In this way in controller scope I can do, say:
def actives = Orders.userStatusPaid()
and "eq" closure will delegate to the ORM and not domain Orders where an MME would occur.
Play around with it, hopefully I've given you some ideas for how to solve the problem. In Groovy, if you can't do it one way, try another ;--)
Good luck!
Original:
Your missingMethod is defined on string metaclass; in order for it to be invoked, you need "someString".foo()
If you simply call foo() by itself within your closure it will fail, regardless of delegation strategy used; i.e. if you don't use the (String) delegate, good luck. Case in point, do "".foo() and it works.
I don't fully understand the issue either, why will you not have access to the closure's delegate? You are setting the closure's delegate and will invoke the closure, which means you will have access to the delegate within the closure itself (and can just delegate.foo())
nope, you will not catch a missing method and redirect it to the delegate with metaclass magic.
the closure delegate is the chance to capture those calls and adapt them to the backing domain.
that means...
you should create your own delegate with the methods required by the dsl.
do not try to force a class to do delegate work if it's not designed for the task, or the code will get really messy in not time.
keep everything dsl related in a set of specially designed delegate classes and everything will suddenly become ridiculously simple and clear.

Resources