Question about nodem function calling into mumps.

97 views
Skip to first unread message

Kevin Toppenberg

unread,
May 25, 2025, 11:17:22 AMMay 25
to Everything MUMPS
I have been trying to understand the documentation on nodem here: https://docs.yottadb.com/MultiLangProgGuide/jsprogram.html

It looks like for input the documentation shows this:

Arguments as an object:

{ function: string,
arguments
: string[]|number[]|[], // (optional)
autoRelink
: boolean // <false> (optional)
}

So it looks like the arguments can be:
  1. a string (or is that an array of strings?)
  2. A number (or an array of numbers?)
  3. Any arbitrary array.
But I don't feel like this gives enough information.  The example program given doesn't take any input variables. 

Questions:
  1. If a mumps function takes three variables, e.g. MYFUN(A,B,C), and the arguments is a string array, does element 0 go to A, 1 to B, and 2 to C?  Or would A simply be found to be an array with 3 elements, and B and C being undefined?
  2. In mumps, to get an array as an output of a function, one has to pass a variable by reference.  E.g. DO MYFN(.OUT,5,6).    Is this supported in nodem?
  3. My suspicion is that the result of the function is going to be limited to a literal string.  If so, could full multi-var array be serialized and returned that way, and then converted to json in nodem?  If so, what functions would be used on mumps side and on node side?
  4. Since arguments appear to support an arbitrary array, how would nodem handle if I passed an array of json arguments?
I can do some testing to see what I find for answers. But if someone can point me to documentation that could save me time, it will be appreciated.

Thanks in advance,
Kevin

Kevin Toppenberg

unread,
May 29, 2025, 10:09:35 AMMay 29
to Everything MUMPS
I got a reply to my personal email that seemed to be a commit notification with an ultimate link to David Wicksell's github page (https://github.com/dlwicksell/nodem).  At the bottom there is documentation, and I think information has been added about my question, addressing it there.  I'll include it below.  Questions to follow below

Nodem supports full M local symbol table manipulation with the current APIs. In order to use it, instead of defining a global property in your argument object, you define a local property. For APIs that support passing arguments by-position, you signify that you want them to work on a global, by using a ^ as the first character of the first argument, otherwise they are working on a local variable. For the get and set APIs, if the first character of the first argument is a $, then you are working with an intrinsic special variable (ISV). There is also a localDirectory API, that works the same way as the globalDirectory API, except that it lists the local symbols in the symbol table, rather than the globals in the database. One caveat is that you cannot manipulate any local variable that begins with v4w, as Nodem internally uses that namespace to implement the v4wNode.m integration routine. You can also call the kill API with no arguments, and it will clear the local symbol table. This functionality will allow you to call legacy M functions and procedures, without having to write M routine wrappers. Here is an example of using the local symbol table functionality to call a legacy API directly from Nodem. In this example, the local variable, 'U', needs to be set before this API is called, as it expects it to be defined already. You can also see how the local symbol table changes, after setting the required local variable, making the call, and then clearing the symbol table, e.g.

> ydb.localDirectory();
[]
> ydb.set({local: 'U', data: '^'});
{ ok: true, local: 'U', data: '^' }
> ydb.localDirectory();
[ 'U' ]
> ydb.procedure({procedure: 'AGET^ORWORR', arguments: [, 9, '2^0', 13, 0]});
{
  ok: true,
  procedure: 'AGET^ORWORR',
  arguments: [ <1 empty item>, 9, '2^0', 13, 0 ]
}
> ydb.localDirectory();
[ 'DILOCKTM', 'DISYS', 'DT', 'DTIME', 'DUZ', 'IO', 'U', 'XPARSYS' ]
> ydb.kill();
true
> ydb.localDirectory();
[]

Nodem supports calling functions and procedures with arguments passed by-reference, or by-variable, in addition to the standard passing by-value. This will allow someone who needs to interface Nodem with legacy M APIs that require using local variables in this manner, the ability to do so directly in Nodem, rather than having to write an M wrapper around the API, and calling that from Nodem. In order to use this functionality, you need to pass your arguments via a specially formatted object, in order to instruct Nodem that you wish to pass arguments differently than normal. This is necessary because if you tried to pass an argument by-reference or by-variable directly, Node.js will try to dereference it as a local JavaScript variable, and you would never be able to refer to the right symbol in the back-end M environment. The structure of the specially formatted object is simple. It contains a type property, which can be one of three values: reference, variable, or value; and it also contains a value property which contains the name you want to use when the type is reference or variable, and the actual data you want to pass if type is value. The value type is there for consistency, but you would normally just pass arguments by value directly, without resorting to this specially formatted argument object. Here is an example of how you could use this functionality, while calling a legacy M API, many of which require passing arguments in this fashion, e.g.

> ydb.set({local: 'U', data: '^'});
{ ok: true, local: 'U', data: '^' }
> const arg = {type: 'reference', value: 'LIST'};
undefined
> ydb.procedure({procedure: 'LISTALL^ORWPT', arguments: [arg, 'A', 1]});
{
  ok: true,
  procedure: 'LISTALL^ORWPT',
  arguments: [ { type: 'reference', value: 'LIST' }, 'A', 1 ]
}
> ydb.localDirectory();
[ 'LIST', 'U' ]
> ydb.data({local: 'LIST'});
{ ok: true, local: 'LIST', defined: 10 }
> ydb.nextNode({local: 'LIST'});
{
  ok: true,
  local: 'LIST',
  subscripts: [ 1 ],
  data: '1^ZZ PATIENT,TEST ONE^^^^ZZ PATIENT,TEST ONE',
  defined: true
}
> ydb.nextNode({local: 'LIST', subscripts: [1]});
{
  ok: true,
  local: 'LIST',
  subscripts: [ 2 ],
  data: '3^ZZ PATIENT,TEST THREE^^^^ZZ PATIENT,TEST THREE',
  defined: true
}
> ydb.nextNode({local: 'LIST', subscripts: [2]});
{
  ok: true,
  local: 'LIST',
  subscripts: [ 3 ],
  data: '2^ZZ PATIENT,TEST TWO^^^^ZZ PATIENT,TEST TWO',
  defined: true
}
> ydb.nextNode({local: 'LIST', subscripts: [3]});
{ ok: true, local: 'LIST', defined: false }

---------------------------------------------------

According to the Annotated Mumps Standard found here:  http://71.174.62.16/Demo/AnnoStd,  there are two ways that a program can be called: by value or by reference. 

4.5 call by reference: A calling program passes a reference to its actual parameter. If the called subroutine or function changes its formal parameter, the change affects the actual parameter as well. Limited to unsubscripted names of local variables, either scalar or array. See also call by value.

4.6 call by value: A calling program passes the value of its actual parameter to a subroutine or function. Limited to a single value, that is, the value of a scalar variable or of one node in an array. See also call by reference.

In the mumps world, a common use-pattern is to call with the NAME of a variable, aka a "reference".  Here my nomenclature may be off. 

SET REF=$NAME(^VA(200,168)), I think of this as a variable 'reference'.  But passing this 'reference' is not calling by reference.  Its a bit confusing.  So I call this "calling by name", though I don't think that is standard.

QUESTION:

Against this backdrop of confusing (to me) nomenclature, Is it correct to consider that the type variable described above is where the name of a variable is passed?  There is a helpful example provided for passing by reference, but none for passing by variable.

Thanks in advance

Kevin

David Wicksell

unread,
May 29, 2025, 2:15:05 PMMay 29
to Everything MUMPS
I'll help you on Saturday.

David Wicksell
Fourth Watch Software LC

David Wicksell

unread,
May 31, 2025, 4:19:58 PMMay 31
to Everything MUMPS
Hi Kevin,

 I'll start by answering your specific questions, from both posts, and then by
showing you example code, and if you still have questions, I can elaborate in
another post.

 There are two methods to call M code, function and procedure (or routine).
The function method returns a result from the call to the M code, it is a function
that ends with a QUIT with an argument. The procedure method doesn't return
a result, it is a function that ends with a QUIT without an argument. Both methods
can be called synchronously, or asynchronously, the latter is achieved by passing a
JavaScript function with a specific format, as the last argument to the function or
procedure method.

 They can also be called in two different ways; either by passing the input in a single
JavaScript object, or by passing them as separate arguments directly to the method.
The first will result in a return of an output JavaScript object, with more info than just
the result from the function, and the second will return just the result from the function,
or in the case of the procedure method, it will always return the JavaScript undefined
object. The second is also modestly faster. For some Nodem methods, using the JavaScript
input object is very useful, because a single call can return enough info to avoid having
to make an additional call to get that same info, but with the function and procedure
methods, it's probably best to call them passing the arguments separately by position,
as it's faster and you really only care about the result.

 Nodem also has a method called help, and if you call it with no arguments it will list
all of its method APIs, and you can call it with a single string that is the name of a method,
and it will give you a quick API reference for that method. E.g. `ydb.help('function');` would
return info about the function method.

```

So it looks like the arguments can be:
  1. a string (or is that an array of strings?)
  2. A number (or an array of numbers?)
  3. Any arbitrary array
```
 This is documenting the use of the JavaScript input object, and all it is saying is that to pass
arguments to the function, you create a key called arguments, and a value that is an array.
The array can be empty, which is the same as if you didn't pass an arguments key at all. The
array then is just the arguments you want to pass to the function, so they can be a mix of
strings and numbers, just like in M. I'll go over call by-reference a little later.

```
Questions:
  1. If a mumps function takes three variables, e.g. MYFUN(A,B,C), and the arguments is a string array, does element 0 go to A, 1 to B, and 2 to C?  Or would A simply be found to be an array with 3 elements, and B and C being undefined?
  2. In mumps, to get an array as an output of a function, one has to pass a variable by reference.  E.g. DO MYFN(.OUT,5,6).    Is this supported in nodem?
  3. My suspicion is that the result of the function is going to be limited to a literal string.  If so, could full multi-var array be serialized and returned that way, and then converted to json in nodem?  If so, what functions would be used on mumps side and on node side?
  4. Since arguments appear to support an arbitrary array, how would nodem handle if I passed an array of json arguments?
```
  1. The first option you mention. But you are using local M variables as arguments, and the normal passing of arguments from Nodem to M would pass data from JavaScript to M, so by the methods already described, can only be a string or number, originating from JavaScript. In the next section I'll describe how to do this and how to do it calling by-reference. But, if your example used string arguments instead, it would look like this, e.g. `ydb.function({function: 'MYFUNC', arguments: ['A', 'B', 'C']};` or `ydb.function('MYFUNC', 'A', 'B', 'C');`
  2. Yes it is. Both passing arguments that are M local variables, as discussed in 1, and passing arguments that are M local variables by-reference are supported.
  3. The result of the function will be whatever you pass as an argument to QUIT in the explicit function in M. So a string or number. When calling a function using the JavaScript input object, the result will be a JavaScript output object, but the return value of the M function will still just be a string or number, in this case returned as the value of the result property. An array will not be returned from M. I think you are asking about how to call a function, passing an argument that is an M local variable, by-reference, and how to get at those values. I will go over that in a later section.
  4. They would be converted to strings. Quick aside, JSON is just a string. It's a string that represents a particular structure, specifically the structure of a JavaScript object or array. I think you might be conflating terms here, and you are asking what happens if you pass arguments to the function method in the arguments array which are themselves JavaScript objects (not JSON). If so, they will be converted in to strings by the JavaScript engine. Here are examples from the Node.js REPL to help illustrate that. E.g. `{'key': 'value'}.toString()` will return '[object Object]' and `['value1', 'value2'].toString()` will return 'value1,value2'. There is one exception to this. When passing a specially-formatted object as an argument to a function or procedure, it will not be converted in to a string, as Nodem will process it first, in order to convert the arguments you pass in it to YottaDB, so that they can be passed as variables with call by-variable or call by-reference.
 Before I go over how to pass M local variables by-variable and by-reference, I'll move on to
respond to your next email in this thread. I have no idea who sent you a private message
about this, but nothing was added to my repo to address your questions. That information
has been there for over a decade. As I've been writing this response as I'm reading your posts,
I can see that the examples I would have provided are already there from my README.md and
copied in your second post. So I'll just say two more things. First, here is the answer to your last
question.

```
QUESTION:

Against this backdrop of confusing (to me) nomenclature, Is it correct to consider that the type variable described above is where the name of a variable is passed?  There is a helpful example provided for passing by reference, but none for passing by variable.
```
Yep, that's exactly right. When you normally pass a string, number, or variable as an argument
in Node.js, you are passing JavaScript things, so the variable will be dereferenced in Node.js, not
in YottaDB. That's why you have to use the special JavaScript object, so that you can annotate the
type, to tell Nodem that you are not passing data from JavaScript, you are passing data from within
the M engine. When the `type` property is `variable` then the string that you pass to the `value`
property, is passed to the M function as the name of an M variable, which is what you want. When
the `type` property is `reference` then the string that you pass to the `value` property, is passed to\
the M function as the name of an M variable, prefixed with a `.`, hence it's being called by-reference,
not by value.

 I think the terminology is tripping you up a bit, because in the M standard, which only defines
call by-value and call by-reference, the handling of an argument that is passed as a variable, without
a `.` in front of it, is dereferenced to its value, prior to the actual call to the function. So calling a function
as `write $$label^function("string")` is the same thing when binding arguments to parameters and
making the actual call, as `write $$label^function(arg)` is, when arg was previously set to "string". They
are the same thing as far as argument passing semantics. But when you add a `.` to the front of that
variable, you are no longer binding the value of that argument to the parameter in the function (the M
Standard uses the terms 'actual parameter' and 'formal parameter' to refer to 'argument' and
'parameter' in this discussion), you are binding a reference to that variable in the symbol table, to the
parameter in the M function, allowing it to treat it as a regular M array with all of its nodes, rather than
simply containing a copy of the value of the variable in the argument.

Second, Nodem has a debug tracing built in to it, so if you call the configure method, and pass it a JavaScript
object, that contains a property named 'debug', and a value of 0, 1, 2, or 3 (other things work, but these
numbers are the simplest), then you can see a trace of everything Nodem is doing, in the C++, C, and
M code. A value of 0 is no debug output, the default, and then 1, 2, and 3 are increasing levels of debug
tracing. By doing this, you can see what Nodem is doing with your JavaScript data at every point, and with it
set up at 3, you can see what it's doing in the M code even, like how your JavaScript data is being used in
your M function call.

 I hope this helps, and again, if you have any other questions, let me know.

David Wicksell
Fourth Watch Software LC

David Wicksell

unread,
May 31, 2025, 7:05:10 PMMay 31
to Everything MUMPS
Kevin,

 One more thing to note, the debug tracing output is written on standard error,
so you can redirect it to a file if it's too voluminous and making it hard to follow
the normal output of the code you are testing.

 Here is a long session of me using the function method, and setting up an M
function and data, and showing how it works, with some comments that I hope
make various technical details clearer to you. I only commented the JavaScript code
in Node.js, not the M code; you already know that well. I hope it helps.

```
$ cat test.m
test(param) ;
 new sub,i
 set i=0
 if $data(param)#2 set i=$increment(i) write "Root node = "_param,!
 set sub="param"
 for i=i:1 set sub=$query(@sub) quit:sub=""  write "Subscript "_i_": "_sub_" = "_@sub,!
 quit i
$ ydb_routines=". $ydb_routines" yottadb -direct_mode

YDB:r202 [UTF-8]>write $$^test(.test)
0
YDB:r202 [UTF-8]>set test="A test message"

YDB:r202 [UTF-8]>write $$^test(.test)
Root node = A test message
1
YDB:r202 [UTF-8]>k test

YDB:r202 [UTF-8]>set test(1)=1,test(1,1)=11,test(2)=2,test(2,1)=21,test(3)=3

YDB:r202 [UTF-8]>write $$^test(.test)
Subscript 1: param(1) = 1
Subscript 2: param(1,1) = 11
Subscript 3: param(2) = 2
Subscript 4: param(2,1) = 21
Subscript 5: param(3) = 3
5
YDB:r202 [UTF-8]>set test="A test message"

YDB:r202 [UTF-8]>write $$^test(.test)
Root node = A test message
Subscript 1: param(1) = 1
Subscript 2: param(1,1) = 11
Subscript 3: param(2) = 2
Subscript 4: param(2,1) = 21
Subscript 5: param(3) = 3
6
YDB:r202 [UTF-8]>kill ^param

YDB:r202 [UTF-8]>merge ^param=test

YDB:r202 [UTF-8]>zwrite ^param
^param="A test message"
^param(1)=1
^param(1,1)=11
^param(2)=2
^param(2,1)=21
^param(3)=3

YDB:r202 [UTF-8]>halt
$ ydb_routines=". $ydb_routines" node
Welcome to Node.js v24.1.0.
Type ".help" for more information.
> const ydb = require('nodem').Ydb(); // Import NodeM, calling the Ydb constructor to create the ydb object that binds the library
undefined
> ydb.open(); // Open a connection to the YottaDB runtime environment - pid = process ID, tid = thread ID (for worker threads)
{ ok: true, pid: 637555, tid: 637555 }
> ydb.function('test'); // Call the ^test function in YottaDB with no arguments
0
> ydb.function('test', 10); // Call the ^test function in YottaDB with an argument of 10, passed from Node.js
Root node = 10
1
> ydb.function('test', arg); // Call the ^test function with an argument of arg, a JavaScript variable that is undefined
Uncaught ReferenceError: arg is not defined
> let arg = {type: 'value', value: 'Test string'}; // Create a JavaScript object called arg, passing 'Test string' by-value
undefined
> ydb.function('test', arg); // Call the ^test function with an argument of arg, which just passes 'Test string' from Node.js
Root node = Test string
1
> arg = {type: 'variable', value: 'test'}; // Change arg to pass 'test', not as a string by-value, but as the name of an M variable
{ type: 'variable', value: 'test' }
> ydb.function('test', arg); // Call the ^test function, passing the M variable test, not the string 'test'
Uncaught Error: function+24^v4wNode,%YDB-E-LVUNDEF, Undefined local variable: test
> ydb.set('test', 'Pass by-variable'); // Define the M variable test to a string
undefined
> ydb.function('test', arg); // Call the ^test function, passing the M variable test again, this time it's defined
Root node = Pass by-variable
1
> ydb.set('test', 'Pass by-reference'); // Change the value of the M test variable
undefined
> arg = {type: 'reference', value: 'test'}; // Change the arg object to pass its value property by-reference, not by-variable
{ type: 'reference', value: 'test' }
> ydb.function('test', arg); // Call the ^test function, passing the M variable test by-reference (.test), it has just a root node
Root node = Pass by-reference
1
> ydb.merge({from: {global: 'param'}, to: {local: 'test'}}); // Merge all the nodes from ^param to test in M
{ ok: true, from: { global: 'param' }, to: { local: 'test' } }
> ydb.function('test', arg); // Call the ^test function, passing the M variable test by-referfence, now with many nodes
Root node = A test message
Subscript 1: param(1) = 1
Subscript 2: param(1,1) = 11
Subscript 3: param(2) = 2
Subscript 4: param(2,1) = 21
Subscript 5: param(3) = 3
6
> ydb.localDirectory(); // Get a listing of all the local variables defined in the M symbol table
[ 'test' ]
> ydb.data('test'); // Get back the $DATA of the M test variable
11
> ydb.nextNode('test'); // Call $QUERY on test
[ 1 ]
> ydb.nextNode('test', 1); // Call $QUERY on test(1)
[ 1, 1 ]
> ydb.nextNode('test', 1, 1); // Call $QUERY on test(1,1)
[ 2 ]
> let sub = ydb.nextNode('test', 2); // Call $QUERY on test(2) and store the next node as an array in the JavaScript variable sub
undefined
> sub
[ 2, 1 ]
> sub = ydb.nextNode('test', ...sub); // Call $QUERY on test(2,1) using the JavaScript spread syntax to turn [2, 1] in to 2, 1
[ 3 ]
> sub = ydb.nextNode('test', ...sub); // Call $QUERY on test(3) using the JavaScript spread operator again
[]
> sub = ydb.nextNode('test', ...sub); // Call $QUERY on test using the JavaScript spread operator again
[ 1 ]
> sub = ydb.nextNode('test', ...sub); // Call $QUERY on test(1) using the JavaScript spread operator again
[ 1, 1 ]
> sub = ydb.nextNode('test', ...sub); // Call $QUERY on test(1,1) using the JavaScript spread operator again
[ 2 ]
> sub = ydb.nextNode('test', ...sub); // Call $QUERY on test(2) using the JavaScript spread operator again
[ 2, 1 ]
> sub = ydb.nextNode('test', ...sub); // Call $QUERY on test(2,1) using the JavaScript spread operator again
[ 3 ]
> sub = ydb.nextNode('test', ...sub); // Call $QUERY on test(3) using the JavaScript spread operator again
[]
> ydb.nextNode({local: 'test', subscripts: [...sub]}); // The spread operator works here, when used in the array syntax brackets
{ ok: true, local: 'test', subscripts: [ 1 ], data: 1, defined: true }
> sub = ydb.nextNode({local: 'test', subscripts: [...sub]}).subscripts;
[ 1 ]
> sub = ydb.nextNode({local: 'test', subscripts: [...sub]}).subscripts;
[ 1, 1 ]
> sub = ydb.nextNode({local: 'test', subscripts: [...sub]}).subscripts;
[ 2 ]
> sub = ydb.nextNode({local: 'test', subscripts: [...sub]}).subscripts;
[ 2, 1 ]
> sub = ydb.nextNode({local: 'test', subscripts: [...sub]}).subscripts;
[ 3 ]
> sub = ydb.nextNode({local: 'test', subscripts: [...sub]}).subscripts;
undefined
> sub = ydb.nextNode({local: 'test', subscripts: sub}).subscripts; // This also works when calling this way, without [] or ...
[ 1 ]
> sub = ydb.nextNode({local: 'test', subscripts: sub}).subscripts;
[ 1, 1 ]
> sub = ydb.nextNode({local: 'test', subscripts: sub}).subscripts;
[ 2 ]
> sub = ydb.nextNode({local: 'test', subscripts: sub}).subscripts;
[ 2, 1 ]
> sub = ydb.nextNode({local: 'test', subscripts: sub}).subscripts;
[ 3 ]
> sub = ydb.nextNode({local: 'test', subscripts: sub}).subscripts;
undefined
> ydb.nextNode({local: 'test', subscripts: []}); // This shows what calling with a JavaScript input object returns
{ ok: true, local: 'test', subscripts: [ 1 ], data: 1, defined: true }
> ydb.nextNode({local: 'test', subscripts: [1]});
{
  ok: true,
  local: 'test',
  subscripts: [ 1, 1 ],
  data: 11,
  defined: true
}
> ydb.nextNode({local: 'test', subscripts: [1, 1]});
{ ok: true, local: 'test', subscripts: [ 2 ], data: 2, defined: true }
> ydb.nextNode({local: 'test', subscripts: [2]});
{
  ok: true,
  local: 'test',
  subscripts: [ 2, 1 ],
  data: 21,
  defined: true
}
> ydb.nextNode({local: 'test', subscripts: [2, 1]});
{ ok: true, local: 'test', subscripts: [ 3 ], data: 3, defined: true }
> ydb.nextNode({local: 'test', subscripts: [3]});
{ ok: true, local: 'test', defined: false }
> ydb.close(); // Close the connection to the YottaDB engine and clean up resources
undefined
>
```
David Wicksell
Fourth Watch Software LC

David Wicksell

unread,
May 31, 2025, 7:13:15 PMMay 31
to Everything MUMPS
I should have had the output of the M code use Node, rather than Subscripts.
I also didn't need to use $increment, since it's a local and I set i to 0 ahead of
time. Oh well, I just whipped that M code together for this quick demo, and
didn't check it after. :-)

Kevin Toppenberg

unread,
Jun 9, 2025, 2:30:31 PMJun 9
to Everything MUMPS
David,

I've spent some time thinking about your post.  I think you wrote nodem such that complete applications could be written outside the mumps environment.  As such you provide functionality to get and set globals and even local variables.  I, on the other hand, want to use this to call RPC's, where the primary code is running on the server. 

I have gotten my stringified_json <---> mumps_array working.  So I think I am going to just use that to pass variables back and forth to the mumps side. 

Thanks again for all this information. 

Best wishes,

Kevin

Sam Habiel

unread,
Jun 9, 2025, 3:02:35 PMJun 9
to Kevin Toppenberg, Everything MUMPS
Since you are talking about RPCs, a group of us wrote this a few years ago (Nikolay, Rob, and myself):


The code doesn't work anymore (Node.js moved on to newer versions). But you can try taking pieces of it. It tries to be comprehensive and handle all RPC logic with full symbol table management.

--Sam

--
You received this message because you are subscribed to the Google Groups "Everything MUMPS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to everythingmum...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/everythingmumps/8632bdd0-ff98-432b-b7d9-f88e890f2247n%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Kevin Toppenberg

unread,
Jun 9, 2025, 4:23:05 PMJun 9
to Everything MUMPS
Sam,

Thanks for this.  It has given me an idea about managing the symbol table to maintain state.   Thanks

Kevin

Rob Tweed

unread,
Jun 12, 2025, 8:20:05 AMJun 12
to Everything MUMPS
Note: that was a fork of an original version I created which, as it happens, was adopted by the folks at Jordan to provide the REST interfacing of VistA RPCs which their web interface uses.

Based on issues they've been trying to deal with, I've recently rebuilt a much more effective, efficient and scalable version using mg-web/mgweb-server (it doesn't require any JS/Node.js code and will work with Apache, NGINX or IIS web servers).   Essentially it should provide a robust REST mapping for all VistA's RPCs: all you'd need to write is your front end to call and consume/use them. Should be compatible with YottaDB, Cache or IRIS implementations of VistA

 I"ve yet to decide what to do with it though (nobody, not even Jordan, has seen it!).
Reply all
Reply to author
Forward
0 new messages