How to transfer variables between 2 function type code templates - mirth-connect

My channel is receiving HL7 messages and I have 2 transformers in my channel. I am capturing all the data from the HL7 message in one transformer like:
- var vACCNo= msg['PID']['PID.17']['PID.17.1'].toString();
- var vSTATE=msg['PID']['PID.11']['PID.11.4'].toString();
....
In the second transformer I am pushing all this data into a external DB as insert statement like insert into table x values (vACCNo, vSTATE....).
In the above design without doing anything data captured in first transformer is available in second and it works.
Now I am planning to get rid of these 2 transformers and move these into code templates, where I'm planning to create a separate function for each of these transformer.
But how I can pass variables captured in first function to second one?
Thanks

When you say 2 transformers, I assume you mean two steps in the same transformer? Different transformer steps compile into the same javascript function, so they share the same variable context/scope. To actually pass values to a different transformer (like from your source transformer to a destination transformer) normally you would use the channelMap for this.
In your (presumed) situation, you can add all of your variables to an object that you return from the first function. Pass the object to the second function.
Code Templates
function getValues(msg) {
var fieldWithComplicatedAssignment = '';
var result = {
vACCNo: msg['PID']['PID.17']['PID.17.1'].toString(),
vSTATE: msg['PID']['PID.11']['PID.11.4'].toString(),
fieldWithComplicatedAssignment: fieldWithComplicatedAssignment
};
if (optionalCondition) {
result.optionalField = '';
}
return result;
}
function insertIntoDB(obj) {
// insert into table x values (obj.vACCNo, obj.vSTATE....)
// return a result status indicating succeeded or failure (or
// just throw an error from this function)
}
Transformer steps
var obj = getValues(msg);
var result = insertIntoDb(obj);

Related

Why the array is empty after observer?

I am trying to get the values from the Room database:
val cars = mutableListOf<String>()
carsDb.getAll.observe(viewLifecycleOwner) {
cars = it.toMutableList()
// cars.size = 5
}
// cars.size = 0
Why can't I get the values outside the observer?
I am facing this issuing every time.
Looks like a problem of synchronisation, the db call carsDb.getAll.observe() is likely asynchronous, so the cars.size=5 you get inside the function is resolved later than the cars.size=0you got just after calling the db call (but before the request is resolved)

How Should Complex ReQL Queries be Composed?

Are there any best practices or ReQL features that that help with composing complex ReQL queries?
In order to illustrate this, imagine a fruits table. Each document has the following structure.
{
"id": 123,
"name": "name",
"colour": "colour",
"weight": 5
}
If we wanted to retrieve all green fruits, we might use the following query.
r
.db('db')
.table('fruits')
.filter({colour: 'green'})
However, in more complex cases, we might wish to use a variety of complex command combinations. In such cases, bespoke queries could be written for each case, but this could be difficult to maintain and could violate the Don't Repeat Yourself (DRY) principle. Instead, we might wish to write bespoke queries which could chain custom commands, thus allowing complex queries to be composed in a modular fashion. This might take the following form.
r
.db('db')
.table('fruits')
.custom(component)
The component could be a function which accepts the last entity in the command chain as its argument and returns something, as follows.
function component(chain)
{
return chain
.filter({colour: 'green'});
};
This is not so much a feature proposal as an illustration of the problem of complex queries, although such a feature does seem intuitively useful.
Personally, my own efforts in resolving this problem have involved the creation of a compose utility function. It takes an array of functions as its main argument. Each function is called, passed a part of the query chain, and is expected to return an amended version of the query chain. Once the iteration is complete, a composition of the query components is returned. This can be viewed below.
function compose(queries, parameters)
{
if (queries.length > 1)
{
let composition = queries[0](parameters);
for (let index = 1; index < queries.length; index++)
{
let query = queries[index];
composition = query(composition, parameters);
};
return composition;
}
else
{
throw 'Must be two or more queries.';
};
};
function startQuery()
{
return RethinkDB;
};
function filterQuery1(query)
{
return query.filter({name: 'Grape'});
};
function filterQuery2(query)
{
return query.filter({colour: 'Green'});
};
function filterQuery3(query)
{
return query.orderBy(RethinkDB.desc('created'));
};
let composition = compose([startQuery, filterQuery1, filterQuery2, filterQuery3]);
composition.run(connection);
It would be great to know whether something like this exists, whether there are best practises to handle such cases, or whether this is an area where ReQL could benefit from improvements.
In RethinkDB doc, they state it clearly: All ReQL queries are chainable
Queries are constructed by making function calls in the programming
language you already know. You don’t have to concatenate strings or
construct specialized JSON objects to query the database. All ReQL
queries are chainable. You begin with a table and incrementally chain
transformers to the end of the query using the . operator
You do not have to compose another thing which just implicit your code, which gets it more difficult to read and be unnecessary eventually.
The simple way is assign the rethinkdb query and filter into the variables, anytime you need to add more complex logic, add directly to these variables, then run() it when your query is completed
Supposing I have to search a list of products with different filter inputs and getting pagination. The following code is exposed in javascript (This is simple code for illustration only)
let sorterDirection = 'asc';
let sorterColumnName = 'created_date';
var buildFilter = r.row('app_id').eq(appId).and(r.row('status').eq('public'))
// if there is no condition to start up, you could use r.expr(true)
// append every filter into the buildFilter var if they are positive
if (escapedKeyword != "") {
buildFilter = buildFilter.and(r.row('name').default('').downcase().match(escapedKeyword))
}
// you may have different filter to add, do the same to append them into buildFilter.
// start to make query
let query = r.table('yourTableName').filter(buildFilter);
query.orderBy(r[sorterDirection](sorterColumnName))
.slice(pageIndex * pageSize, (pageIndex * pageSize) + pageSize).run();

IBM Mobilefirst SQL adapter with parameters for select IN statement

I've a problem calling a MobileFirst SQL adapter to retrieve result from an Oracle Select-where-IN statement.
My environment is MobileFirst v7.0
The adapter definition is:
sqlGetResultsStatement = WL.Server.createSQLStatement ("select * from table where field IN (?)");
function getResults(param) {
return WL.Server.invokeSQLStatement({
preparedStatement : sqlGetResultsStatement,
parameters : [param]
});
}
If I call adapter with a single value in parameter (e.g. '0001') all works fine, and I obtain results. But if I call adapter with this type of parameter: "'0001','0002','0003'" I obtain an empty-resultset (w/o errors) response like this
{
"isSuccessful": true,
"resultSet": [
]
}
Is there something in the call that is wrong?
You cannot pass in a set of values to a single prepared statement parameter. One of the key features of prepared statements is that it helps prevent SQL injection attacks and thus it makes sense that when there is one parameter inside of the statement it is considered as a single value, that's why it encloses the value you passed in with quotes "'0001','0002','0003'". Also, MobileFirst doesn't allow you to create prepared statements inside if functions in the JS adapters and therefore you cannot modify the number of parameters when the procedure is invoked. With that being said there are two approaches you can take to accomplish this.
Javascript Adapter
Determine the maximum number of parameters that you will ever pass to this procedure and add the parameters to the prepared statement beforehand. Let's say you are never going to pass more than 10 parameters, then I would use something like:
var MAX_PARAMS = 10;
sqlGetResultsStatement = WL.Server.createSQLStatement ("select * from table where field IN (?,?,?,?,?,?,?,?,?,?)");
function getResults(param) {
/*
* (arguments) is an array of parameters passed to the procedure
*/
return WL.Server.invokeSQLStatement({
preparedStatement : sqlGetResultsStatement,
parameters : fillVars(arguments)
});
}
// helper function to fill all the values for the SQL Statement Parameters
function fillVars(vars) {
var list = [];
for(var i = 0; i < MAX_PARAMS; i++) {
if(vars.length >= i + 1) {
list.push(vars[i]);
} else {
// some value that will not be in your db
list.push(null);
}
}
return list;
}
Java Adapter The other option would be to use a Java Adapter and connect to your DB directly and write your own queries/prepared statements. FYI: this option will give you more flexibility but you will have to include DB driver jar files and write all the DB connection/querying logic, etc.

Select one unique instance from LINQ query

I'm using LINQ to SQL to obtain data from a set of database tables. The database design is such that given a unique ID from one table (Table A) one and only one instance should be returned from an associated table (Table B).
Is there a more concise way to compose this query and ensure that only one item was returned without using the .Count() extension method like below:
var set = from itemFromA in this.dataContext.TableA
where itemFromA.ID == inputID
select itemFromA.ItemFromB;
if (set.Count() != 1)
{
// Exception!
}
// Have to get individual instance using FirstOrDefault or Take(1)
FirstOrDefault helps somewhat but I want to ensure that the returned set contains only one instance and not more.
It sounds like you want Single:
var set = from itemFromA in this.dataContext.TableA
where itemFromA.ID == inputID
select itemFromA.ItemFromB;
var onlyValue = set.Single();
Documentation states:
Returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence.
Of course that means you don't get to customize the message of the exception... if you need to do that, I'd use something like:
// Make sure that even if something is hideously wrong, we only transfer data
// for two elements...
var list = set.Take(2).ToList();
if (list.Count != 1)
{
// Throw an exception
}
var item = list[0];
The benefit of this over your current code is that it will avoid evaluating the query more than once.

Updating an Entity Without Saving the Data back to the Database

I have created a new query like the following
var pressData = from press in dataContext.Releases
select new
{
Heading = press.Heading,
Description = press.Desc,
DatePublished = press.PublishDate.ToString(),
Body = press.BodyContent,
ID=press.ReleaseID,
CreatedBy=press.CreatedBy
};
Later in the code I want to update the entity from a session variable, but not save any data back to the database. Here is the code I am trying to accomplish this with....
var edit = pressData.Where(a => a.Heading == sectionPreview.HeadingContent && a.ID == sectionPreview.tionID).FirstOrDefault();
if (edit != null)
{
//WONT LET ME UPDATE THE Body VALUE
edit.Body = sectionPreview.SectionContent;
}
The code aboves purpose is to look at pressData and replace the body content with the new body from a session variable(not shown here), but NOT save it to the db. I want pressData to be filtered and updated only in the entity. So when I bind it to the control in this case it binds the data stored in my session.
this.rptSections.DataSource = pressData;
this.rptSections.DataBind();
I am getting a complier error stating
Property or indexer 'AnonymousType#1.Body' cannot be assigned to -- it is read only.
I checked the entity model and nothing is read only not any fields not anything. I must be missing something?
Anonymous Types encapsulate a read only property collection - for more information, read here. The compiler rewrites anonymous types as a constructor injections, ie:
select new
{
Heading = press.Heading,
Description = press.Desc,
DatePublished = press.PublishDate.ToString(),
Body = press.BodyContent,
ID=press.ReleaseID,
CreatedBy=press.CreatedBy
};
Is really rewritten as:
new Anonymous`1(press.Heading, press.Desc, press.PublishDate.ToString(), press.BodyContent, press.ReleaseID, press.CreatedBy)
And the properties are read only (public get, private / protected set, to use an easy comparison). If you want to solve your issue, instead of taking the data and making an anonymous object, create a real type and set properties on it.

Resources