Invoke mirrored global function - reflection

I'm searching all global annotated functions in my lib:
#MyAnnotation()
String func(arg1, arg2) => "test";
main() {
var routines = m.currentMirrorSystem().findLibrary(#my.lib).declarations.values
.where((m.DeclarationMirror dm) =>
dm is m.MethodMirror && dm.metadata.map((m.InstanceMirror im) => im.reflectee)
.any((refl) => refl is MyAnnotation)
);
// this works all ok
}
Now I have List<DeclarationMirror> of my annotated functions. But I need to invoke it later. ClosureMirror has invoke method, but I cannot see any way to get this for my either MethodMirror or Symbol of routine.
I cannot use just new ClosureMirror(func) as I have dozens of my annotated functions and I don't know every name. Also I dont have any ClassMirror or InstanceMirror.
So question is, how to invoke global mirrored functions by its Symbol or MethodMirror.

m.MethodMirror f = routines[0];
(f.owner as m.LibraryMirror).invoke(f.simpleName, ['a', 'b']);

Related

How does rust simply get a return from a closure

Here's the problem I'm having with tauri.
'return' shows you the return value I need, and I know for a fact that writing it this way does not work at all.
'pick_file' is called asynchronously, and I know that message passing seems to work, but is there an easier way to get the value I need.
#[tauri::command]
fn open_file() -> String {
dialog::FileDialogBuilder::default()
.add_filter("data", &["json"])
.pick_file(|path_buf| match path_buf {
Some(p) => return format!("{}", p.to_str().unwrap()),
_ => return "".into()
});
}
First, return in a closure returns from the closure and not from the function that contains it.
The more fundamental issue is that you can't return a String from open_file() if you use FileDialogBuilder::pick_file(). According to the documentation, pick_file() is non-blocking and returns immediately without waiting for the user to pick the file. What you can do in the closure is send the file down a channel, and pick it up elsewhere.

Flow type refine mixed to function

I'm using koa which has middleware props typed as mixed, so I'm trying to do something along the lines of the following below but I'm getting an error that Cannot call `ctx.render` because mixed [1] is not a function.Flow(not-a-function)
app.use(async (ctx, next) => {
// some other code above it
await ctx.render('index');
});
My question is, what's the correct way to do a type refinement that this is a function and then allow me to call it?
You can refine this to a function, but calling it is another matter.
app.use(async (ctx, next) => {
if (typeof ctx.render === 'function') {
// Now we know that `ctx.render` is a function.
}
});
Flow actually has a special case for this, this is called an "unknown function." We know that ctx.render is a function, but we don't know anything about its arguments or return type so we can't safely do anything with it except pass it around. How can we safely call ctx.render(1) if we don't know that ctx.render takes a number?
What's more, we can't know anything about it. There is no reflection mechanism provided by JavaScript that we could interrogate for enough information about this function to be able to safely call it. The only thing we can find is the static arity (ctx.render.length) but this by itself is not reliable or sufficient.
If we had more information, like say if this were a union type instead of mixed, then we could use type refinement to do what we want:
(arg: boolean | (number => void)) => {
if (typeof arg === 'function') {
arg(1); // safe because if this is a function, we know it takes a number
}
};
In this case the most reasonable solution is to type through any. Assuming that we know that we should only ever receive one type of render function, then we just forcibly cast it to that type with all the blaring caveats one would expect:
// I don't know what the type of your render function is, but you would put it
// here:
type RenderFunction = string => void;
app.use(async (ctx, next) => {
// some other code above it
if (typeof ctx.render === 'function') {
// DANGER: We make a hard assumption here that the render function is
// always of this specific type. If it is ever of any other type then
// behavior is undefined!
await ((ctx.render: any): RenderFunction)('index');
}
});
Also it sounds to me like the koa libdef could probably be improved upon.

distinctUntilChanged: Old value is alway null

I'm bad at introductions, so let's just cut right to the chase:
I am getting an observable from a redux store by using ngRedux.select. Immediately after I use a pipe with distinctUntilChanged with a custom compare function. However, inside this function the old value is always null, no matter how often it is being called.
Also when I put the distinctUntilChanged at a later point in the pipe after some parsing (which was the original plan), it will again always return the same value: The first one that came through the observable. Somehow I feel I am completely misunderstanding this operator, but I am using it the way the documentation suggests.
Here's the complete code I am using:
this.ngRedux.select((store: RootDomain) => getValue(() => {
const localContext = store.core.context[contextUuid];
const globalContext = store.core.context[GLOBAL_CONTEXT_KEY];
const context = Object.assign({}, globalContext, localContext);
return context[key];
})).pipe(
distinctUntilChanged((x, y) => {
console.log('OLD: ', x);
console.log('NEW: ', y);
return isEqual(x, y);
})
);
I also tried simply returning true all the time to see if anything would change (of course it didn't). x will always log as null here. Please help me understand this operator!

exported typed functions that return functions should NOT require the returned function to be typed to work in other modules

For example if you are using redux-actions and have created the following module definition for it:
declare module 'redux-actions' {
declare type ActionType = string
declare type Action = {
type: ActionType,
payload?: any,
error?: bool,
meta?: any,
}
declare function createAction<T>(
type: string,
payloadCreator?: (...args: Array<T>) => any,
metaCreator?: Function
): (...args: Array<T>) => Action
}
and then you use that function to return a new function like this:
export const selectProfileTab = createAction('SELECT_PROFILE_TAB', (index: number) => {
playSound()
return { index }
})
and then in another file use it incorrectly like this:
selectorProfileTab('someString')
that won't report an error. It seems to be because flow requires annotations at the "boundaries" of modules. Am I correct?
Because the following does work:
export const selectProfileTab: (index: number) => any = createAction('SELECT_PROFILE_TAB', (index: number) => {
playSound()
return { index }
})
Notice I've annotated the returned function. The following will now produce an error:
selectProfileTab('someString')
I'm just trying to get a hold of this and verify this because it's a lot of extra "boilerplate" to annotate those returned functions, especially when it calling selectProfileTab('someString') would correctly produce an error if used in the same file. It makes you think: what's the point in creating module definitions for the redux-actions package which doesn't have them yet if it doesn't provide any/much value since you have to annotate your returned functions anyway. That's quite disappointing. Am I correct in determining that it's a module "boundaries" limitation/requirement with Flow? Are there any ways to get the desired result of not having to type returned functions that you export?

Custom functions for knex

There's a number of operations that I do all the time and I was hoping there would be a way to "extend" knex to be able to do them.
I would like to something like:
oneExists
result = knex.count(id).from('table').where({'code': 25})
if (result.length === 0) return false
if (result.length === 1) return true
throw an error
I would like to be able to do something like
knex.oneExists.count('id').from('table').where({'code': 25}).
at the moment i'm writing the code like this:
KnexUtil.oneExists(knex.select('id').from('table').where({code: 25}))
which returns a promise
I've looked through the knex codebase and i'm not sure:
how to chain this (and whether i would do this in /lib/query/compiler.js)
how to just make an extension to knex so i don't need to modify the original codebase
Starting from v0.19.1, knex have build-in ability to extend QueryBuilder
import Knex from 'knex'
Knex.QueryBuilder.extend('someFn', function (arg) {
console.log('Do Smth', arg)
return this
})
const knex = Knex({ client: 'pg' })
knex.select().from('table').someFn(0).toString()
Sure you can. I would recommend just creating your own plugin, something like the following:
// my-plugin.js
'use strict';
module.exports = function (Bookshelf) {
Bookshelf.Model = Bookshelf.Model.extend({
foo: function ( bar ) {
if( bar )
console.log('Method foo was called on a model with the arguments:', arguments.join(', '));
}
});
Bookshelf.Collection = Bookshelf.Collection.extend({
foo: function ( bar ) {
if( bar )
console.log('Method foo was called on a collection with the arguments:', arguments.join(', '));
}
});
};
Then inside your main application file, add:
Bookshelf.plugin( require( './my-plugin' ) );
BookshelfJS plugins basically allow you to extend the models and collections (and more), which allows you to add your own method, or overwrite existing ones (while still being able to call the original method from within your plugin)
For a better understanding, it might be a good idea for you to look at some existing BookshelfJS plugins, some already come with bookshelf, inside the plugins directory.
Another plugin that may be good to look at to better understand how the plugins work, would be the Soft Delete Plugin. In that plugin, you can see how some BookshelfJS methods are overridden in both the models and the collections objects, with methods that execute the original version of the method, then return the parsed/modified result (Lines #37-#59 and Lines #37-#57), as well as adding completely new methods (Lines #61-#72)
Edit: Obviously this is more BookshelfJS than KnexJS, but I didn't see any way to create plugins for KnexJS, since it's just a query constructor, all the real magic is in the ORM
If using TypeScript:
import { knex, Knex as KnexOriginal } from "knex";
declare module "knex" {
namespace Knex {
interface QueryBuilder {
customFunction<TRecord, TResult>(
value: number
): KnexOriginal.QueryBuilder<TRecord, TResult>;
}
}
}
knex.QueryBuilder.extend("customFunction", function (value: number) {
console.log("Custom Function:", value);
return this;
});
const pg = knex({ client: "pg" });
pg("table").select("*").customFunction(10).toString()
Check out documentation about how to extend knex

Resources