Conversation
…uction that can be reused, or usage can be not so pretty, so you decide to packed it in macro. Another way to usege is if you are have a Instruction that must be built in dynamic way with clojure code. - UPDATE QueryDSL. From now it support 3 different type of resolvers: 1. resolve-instruction-qe for commando-resolve instruction 2. resolve-instruction for execution any kind of instruction 3. resolve-fn for function that must be resolved while it being asked by QueryExpression - UPDATE QueryDSL. Better error handling. - UPDATE Registry. Built registry contain also internal commands of Instruction.
multimethod it can be expanded by another Exception types. Serialized object contain neccessary information declared in keywords, and the :data key (even if it contains symbols, etc.) wrapped to string. To avoid default conversion of :data key to string use commando.impl.utils/*debug-mode*. - FIXED Tests for exceptions.
unit testing for QueryExpression corner cases like sequentual return data. - FIXED QueryDSL. Fixed small issue with Exception on cljs. - FIXED QueryDSL. Automaticaly handle in ->query-run the any different types which are not the Resolvers object Co-authored-by: Julia47 <julia.burmich@gmail.com>
- UPDATED the Commando Query DSL documentation to enhance clarity and detail, including examples and explanations of core concepts, lazy resolution, parameterization, and real-world applications.
…ain multiple keys('flags') what can change the behavior of commando/execute
Kaspazza
left a comment
There was a problem hiding this comment.
LGTM, great changes! Good job!
| macro-data (dissoc m :commando/macro) | ||
| result (commando/execute | ||
| (utils/command-map-spec-registry) | ||
| (command-macro macro-type macro-data))] |
There was a problem hiding this comment.
This could be infinite loop if macro extends itself. Which in a nature of this command being used as a quick development tool (as it's alternative to creating a whole new command) I think it's possible to happen.
WDYT about checking expansion depth?
Something like:
(def ^:dynamic macro-expansion-depth 0)
(def ^:private max-macro-expansion-depth 10)
:apply (fn [_instruction _command-map m]
(when (> macro-expansion-depth max-macro-expansion-depth)
(throw (ex-info "Macro expansion depth exceeded"
{:macro m :depth macro-expansion-depth})))
(binding [macro-expansion-depth (inc macro-expansion-depth)]
...))
There was a problem hiding this comment.
hm, i also thinking about it, but based on fact that instructions with macro approach staying some sort of building blocks, the limits by depth can make some risk of usage it, especially if you want to build your logic with huge amount of macrosses that somehowe combine together.
The main feature with using such kind of tool that you do not thinking about hidding limitation you can take. If your machine can do it - do it.
i think we need to make some limitation by depth it should be number of 1000, somewhere neer the region of StackOverflow exception and try to catch it before it gone. Or another, if the StackOverflow is riched, than process this error properly
| QueryExpression)) | ||
|
|
||
| (deftype ^:private QueryResolve [value Instruction] | ||
| (deftype ^:private Resolver [resolver_type resolver_data] |
There was a problem hiding this comment.
This is just general remark, I don't require any change.
But I wonder why you used deftype and create object here. There is no polymorphism here, there are no performance concern, there is no need for encapsulation. I wonder why this is not just a plain map
There was a problem hiding this comment.
Firstly i've done this with maps, but code, based on types look little bit better. In some way this is style of encapsulation of the logic. Cause while you querying data you need know what resolving procedure have to do now, and if it not be based on types thus it should be special Map which probably need to had lambdas on top of it, that can be overwritten if user start to pass simple maps and expanding this interface. I think if you need to do that, you need probably another sort of abstraction that ment you have to rewrite parsing / resolving procedures in the QueryDSL, and better option is a make a clone of command.
From the debug perspective you got # string, what also gave you quicker path to analyze some debug state if you needed it. I meen the thinking about the unique type called "resolver" sounds naturally , so never need to analyze what sit inside of those object.
No description provided.