Command line arguments parsing in ballerina similar to argparse in python - parsing

Is there any way to parse the command line arguments in ballerina? From what I have seen you can use only positional arguments. What I would like to do is something like this:
//main.bal
public function main(string? name, int? age) returns error? {
if (name is string && age is int) {
io:println("Hello " + name);
io:println("Age " + age.toString());
}
}
And then run the programm as follows:
bal run main.bal -- --name John --age=18
But this does not work, because it takes "--name" as the first positional argument and "John" as the second positional argument. So it throws an error:
error: invalid argument 'John' for parameter 'age', expected integer value
And if I run it as follows then it runs:
bal run main.bal -- John 18

The arguments can be passed by name if they are specified for options.
If the arguments are part of a record like
public type Details record {|
string name?;
int age?;
|};
and the main function has an included record parameter of this type to specify options
public function main(*Details f) {
string? name = f?.name;
int? age = f?.age;
if name is string && age is int {
io:println("Hello ", name);
io:println("Age ", age);
}
}
it can be run as follows
$ bal run main.bal -- --name=Jo --age=25
This was introduced in Swan Lake Alpha5 and the release note provides more information - https://ballerina.io/downloads/swan-lake-release-notes/swan-lake-alpha5/#improved-command-line-argument-parsing.

You can use configurable support for this.
Check this example:
import ballerina/io;
configurable string name = ?;
configurable int age = ?;
public function main() returns error? {
io:println("Hello " + name);
io:println("Age " + age.toString());
}
Then while running you can provide values as following:
bal run main.bal -- -Cname="Ballerina" -Cage=5
The result is
Hello Ballerina
Age 5
Check this guide for more details.

Related

Neo4j Custom Procedures: How to pass query parameters?

I am trying to write a custom procedure for the Neo4J GraphDB in accordance to the documentation and the there referenced template. The procedure should ultimately generate a graph projection using the GDSL, for nodes with a certain label that is provided as a procedure parameter. For this it is, of course, necessary to pass the label to the query that is to be executed within the custom procedure. However, I cannot seem to find out how to pass parameters to a query string.
#Procedure(value = "custom.projectGraph")
#Description("Generates a projection of the graph.")
public Stream<ProRecord> projectGraph(#Name("graph") String graph) {
Map<String, Object> params = Map.of (
"graph", graph
);
return tx.execute("call gds.graph.project.cypher(\"$graph\", "
+ "\"MATCH (n:$graph) return id(n) as id\", "
+ "\"MATCH (src:$graph)-[]-(dst:$graph) "
+ "RETURN id(src) AS source, id(dst) AS target\") "
+ "YIELD graphName", params)
.stream()
.map(result -> (String) result.get("graphName"))
.map(ProRecord::new);
}
public static final class ProRecord {
public final String graphName;
public ProRecord(String graphName) {
this.graphName = graphName;
}
}
This code, unfortunately, does not work as intended, throwing the following exception:
Invalid input '$': expected an identifier
I did copy the syntax of prefixing placeholders with $-characters from other examples, as I could not find any hints on the passing of query parameters in the JavaDoc of the library. Is this even the correct documentation for custom neo4j procedures? Am I possibly using the wrong method here to issue my queries? It'd be very kind if someone could lead me into the right direction on that matter.
In general, when you use a string parameter the $param is automatically quoted, unlike the String.format for example.
Therefore there are 2 problems in your query:
\"$graph\" : in this case you are doubly quoting the parameter, try to write only $graph instead
Things like this n:$graph cannot be done unfortunately, the neo4j parameter handling is not able to recognize where to quote and where not, so you could use String.format or concat string with parameters (e.g. "MATCH (n:" + $graph + ") return id(n)...").
So, in short, this piece of code should work in your case:
return tx.execute("call gds.graph.project.cypher($graph, " +
"'MATCH (n:' + $graph + ') return id(n) as id', " +
"'MATCH (src:' + $graph + ')-[]-(dst:' + $graph + ') RETURN id(src) AS source, id(dst) AS target') YIELD graphName",
params)
.stream()
.map(result -> (String) result.get("graphName"))
.map(ProRecord::new);

get tree root of different DSL file in same project for xtend validation

I have 2 different DSL. These are linked in their grammar, in such a way that "hobbies" defined in 1 DSL, can be referenced in the 2nd DSL. I want to have validation rule that all the Hobbies are referenced in the 2nd DSL.
How can I obtain all the defined hobbies of the first DSL in the validation file of the 2nd DSL?
The first DSL called "MyDsl.xtext" looks like:
'I' 'am' name=ID
greetings+=HelloGreeting* 'Hobbies' hobbies+=Hobbie+
('I_dont_like' detests+=[Hobbie|QualifiedName])?
;
Hobbie:
'eg' name=ID
;
HelloGreeting:
'Hello' person=[Person] '!'
;
The second DSL called "MyDsl1.xtext" looks like:
JustGreetings:
greetings+=HiGreeting* stuff=Stuff
;
HiGreeting:
'Hi' person=[imported::Person] '!'
;
Stuff:
'I_also_like_to_do:' hobbies+=[imported::Hobbie|QualifiedName]+
;
The validation I am trying to do in the validation file looks like:
import org.eclipse.xtext.validation.Check;
import org.xtext.example.mydsl.myDsl.Person
import org.xtext.example.mydsl1.myDsl1.Stuff
class MyDsl1Validator extends AbstractMyDsl1Validator {
public static val INVALID_NAME = 'invalidName'
boolean found
#Check
def checkWalking(Stuff stuffs) {
var myHobbies = stuffs.hobbies
var definedHobbies = getPersons().hobbies
for (i: 0..definedHobbies.size) {
found = false
for (j: 0..myHobbies.size) {
if (definedHobbies.get(i).name == myHobbies.get(j).name) {
found = true
}
}
if (found == false) {
error("you are missing hobbie" + myHobbies.get(i).name + '.', null)
}
}
}
}
Current result: Right now I can import the Person type in the imports, that gives no error, but i do not know how to get all the instances.
Expected Result:
I can get a list of Persons defined in the other DSL, and use it to compare.
Edit:
Example inputs:
definition.mydsl
I am A
Hello B !
Hobbies eg walking
usage.mydsl1
Hi A!
I_also_like_to_do: A.walking

How to remove dashes (-) in autogenerated UUID - typeorm

I am using UUID as primary key for my entity and it works just fine. But I wish to remove those dashes.
Now ids are saved as 8e5365f4-3d42-4274-bafc-93b97bd6e3f2 36 characters
And what I want is 8e5365f43d424274bafc93b97bd6e3f2 32 characters
I dont see any option of using transformer in #PrimaryGeneratedColumn('uuid') is there a simple way to archive this?
You can't remove the dashes when using #PrimaryGeneratedColumn('uuid').
The UUID is either generated by the database (for example postgres) or, if not supported by the database, it is generated by a function.
See Typeorm sources (https://github.com/typeorm/typeorm/blob/master/src/query-builder/InsertQueryBuilder.ts):
else if (column.isGenerated && column.generationStrategy === "uuid" && !this.connection.driver.isUUIDGenerationSupported() && value === undefined) {
const paramName = "uuid_" + column.databaseName + valueSetIndex;
value = RandomGenerator.uuid4();
this.expressionMap.nativeParameters[paramName] = value;
expression += this.connection.driver.createParameter(paramName, parametersCount);
parametersCount++;
// if value for this column was not provided then insert default value
}
If you really want this, you need to generate it yourself, for example:
import { BeforeInsert, Entity, PrimaryColumn } from 'typeorm';
import { v4 as uuid4 } from 'uuid';
#Entity({})
export class User {
#PrimaryColumn()
uuid: string;
#BeforeInsert()
generateUuid() {
this.uuid = uuid4().replace(/-/g, '');
}
}
Instead of using #PrimaryGeneratedColumn, you could use #PrimaryColumn with generated: "uuid" and specify a transformer:
const removeDashes: ValueTransformer = {
from: (str: string | null | undefined) => str != null ? str.replace(/-/g, "") : str,
to: (str: string | null | undefined) => str != null ? str.replace(/-/g, "") : str,
};
#Entity()
export class SomeEntity {
#PrimaryColumn({ type: "uuid", generated: "uuid", transformer: removeDashes })
id: string;
}
Theoretically that should work with databases other than postgres (perhaps with some minor adjustments).
But if you are using postgres, and your column is the built-in uuid type, the dashes that you see in the UUID are not actually stored in the database. Instead, they're stored as a 128-bit integer, and postgres converts it to a human-readable format (with dashes) for display when needed. Postgres accepts UUID input in a variety of formats, both with and without dashes. (See https://www.postgresql.org/docs/11/datatype-uuid.html)
Since postgres is so flexible with input, you don't need to strip the dashes when sending a UUID to postgres if you're using the uuid type:
const removeDashesPostgres: ValueTransformer = {
from: (str: string | null | undefined) => str != null ? str.replace(/-/g, "") : str,
to: (str: string | null | undefined) => str,
};
When typeorm transforms query results into the entity, the transformer will strip the dashes from the string representation of your UUID, so you always "see" the dash-less UUIDs in your objects. When typeorm transforms an entity into a query to save/update/etc., it passes through the string representation of the UUID to the database as-is, and postgres converts it to its own uuid thanks to its extreme input tolerance.
For completeness, the id column in the table in these postgres examples is defined as:
id uuid NOT NULL PRIMARY KEY DEFAULT uuid_generate_v4()

Compile-time foreach outside function body

Is there any way to have a foreach outside a function body for ex. generating code.
My scenario is that I have an associative array at compile-time that I need to use to generate specific fields. Unfortunately I can't really use a foreach outside of a function body to generate the members.
Right now I am using a work-around where I have a few mixins where I give one AA to the first mixin and that mixin converts the AA to an array and passes it to the second mixin, the second mixin is recursive with itself by ng itself until there is no more member, while also calling the first member in the array, which calls a third mixin that I can use to generate code.
It's not as smooth and dynamic as I really would want it to be and I was wondering if anyone has a better solution.
Here is my solution
// First mixin that takes the associative array and a string for the mixin to handle the items
mixin template StaticForEachAA(TKey,TValue, TKey[TValue] enumerator, string itemMixin) {
enum array = arrayAA!(TKey,TValue)(enumerator); // Converts the AA to an array of key-value pair structs
alias ArrayType = KeyValuePair!(TKey,TValue);
mixin StaticForEachArray!(ArrayType, array, itemMixin); // Calls second mixin with the array
}
// The second mixin that "fake loops" the array
mixin template StaticForEachArray(T, T[] array, string itemMixin) {
static if (array.length) {
import std.string : format;
mixin(format("mixin %s!(T, array[0]);", itemMixin)); // Mixins the itemMixin to handle the current item
mixin StaticForEachArray!(T, array[1 .. $], itemMixin); // slices the array to remove the item we just handled
}
}
// The third mixin that can be used to do whatever has to be done with item
mixin template StaticForEachItem(T, T item) {
import std.conv : to;
pragma(msg, to!string(item));
}
And to do the "fake foreach" for an associative
enum AA = [0 : 1, 1 : 2, 2 : 3];
mixin StaticForEachAA!(int, int, AA, "StaticForEachItem");
This will print the key-value pairs from AA at compile-time.
Leveraging the power of compile-time functione excution (CTFE) you could make a helper function that generates code for you using the data from an associative array (AA) you provide.
import std.string : format;
string generateCodeForEachAA(TKey, TValue)(TValue[TKey] data, string foreachBody)
{
string result;
foreach(k, v ; data)
{
result ~= format(foreachBody, k, v);
}
return result;
}
This function turns the given AA data into a string by formatting the given foreachBody with each AA element. The returned string can then be mixin'ed:
enum Data = [ 0 : 1, 1 : 2, 2 : 3 ];
enum Code = generateCodeForEachAA(Data, q{ pragma(msg, "%1$s => %2$s"); });
pragma(msg, "Code: " ~ Code);
mixin(Code);
Output:
Code: pragma(msg, "0 => 1"); pragma(msg, "1 => 2"); pragma(msg, "2 => 3");
0 => 1
1 => 2
2 => 3
Using this to generate members within a struct:
struct Foo
{
enum Members = [ "foo": 123, "bar": 42 ];
mixin(generateCodeForEachAA(Members, q{ typeof(%2$s) %1$s = %2$s; }));
}
void main()
{
import std.stdio : writeln;
Foo f;
writeln("foo: ", f.foo);
writeln("bar: ", f.bar);
}
Output:
foo: 123
bar: 42

Using __arglist with a varying set of named parameters

in my application I have 2 layers. The first layer is a C legacy exposing cdecl functions that use the "..." syntax for a varying parameter list. The only way I found to call these functions from my .Net layer (the second one) is using the DllImport technics. For example the C function below:
int myFunc(char* name, ...);
looks like that in C#:
[DllImport("MyDll.dll"),
CharSet = CharSet.Ansi,
CallingConvention = CallingConvention.Cdecl]
int myFunc(string name, __arglist);
My problem is that sometimes I want to call this function with 2 extra parameters but if one of them is NULL it won't be included in the argument list (my legacy code fails on NULL values). For example I want this call:
int foo(string name, string a, string b)
{
myFunc(name, __arglist(a, b));
}
{
foo("john", "arg1", null);
}
to be interpreted by C as
myFunc("john", "arg1");
Unfortunately doing something like that:
int foo(string name, string a, string b)
{
List<string> args = new List<string>();
if(a != null) args.Add(a);
if(b != null) args.Add(b);
myFunc(name, __arglist(args));
}
{
foo("john", "arg1", null);
}
is interpreted by C like that:
myFunc(name, args);
and not:
myFunc(name, args[0]);
Does anybody have any idea?
How does the C function know which one is the last parameter? It cannot know a priori how many parameters there are. It needs additional information. One common way for functions get the information they need is by parsing the included string parameter to count format specifiers, as in printf. In that case, if the format string only indicates that there is one extra parameter, then the function doesn't know the difference between a call that really had just one extra parameter and a call that had two or a call that had 20. The function should have the self-discipline to only read one parameter, since that's all the format string said there was. Reading more would lead to undefined behavior.
If what I've described is not the way your function works, then there's not much you can do on the calling end to solve it. But if it is how your function works, then there's nothing to do on the calling end, because there's no problem.
Another option, since you indicate that your "legacy code fails on null values," is to fix your legacy code so it doesn't fail anymore.
A third option is to simply write all four possibilities:
if (a != null) {
if (b != null)
return myFunc(name, a, b);
else
return myFunc(name, a);
} else {
if (b != null)
return myFunc(names, b);
else
return myFunc(names);
}
More than two optional parameters, though, and the code starts getting unwieldy.
Try converting your System.List ToArray() before wrapping it in __arglist
myFunc(name, __arglist(args.ToArray()));

Resources