Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Layouts failing because maps are incorrect for ORed segments #39

Open
ahives opened this issue Nov 18, 2017 · 8 comments
Open

Layouts failing because maps are incorrect for ORed segments #39

ahives opened this issue Nov 18, 2017 · 8 comments

Comments

@ahives
Copy link
Contributor

ahives commented Nov 18, 2017

Consider the following HL7 2.6 specification fragment...

ORC
[
<OBR|RQD|RQ1|RXO|ODS|ODT>
[{ NTE }]
[ CTD ]
[{ DG1 }]
[{
OBX
[{ NTE }]
}]
]

...the current Machete schema and map for this is as follows:

public class ORM_O01_ORDER_DETAILMap :
    HL7V26LayoutMap<ORM_O01_ORDER_DETAIL>
{
    public ORM_O01_ORDER_DETAILMap()
    {
        Segment(x => x.OBR, 0, x => x.Required = true);
        Segment(x => x.RQD, 1, x => x.Required = true);
        Segment(x => x.RQ1, 2, x => x.Required = true);
        Segment(x => x.RXO, 3, x => x.Required = true);
        Segment(x => x.ODS, 4, x => x.Required = true);
        Segment(x => x.ODT, 5, x => x.Required = true);
        Segment(x => x.NTE, 6);
        Segment(x => x.CTD, 7);
        Segment(x => x.DG1, 8);
        Layout(x => x.Observation, 9);
    }
}

The problem is that when the spec identifies segments as <OBR|RQD|RQ1|RXO|ODS|ODT> we are interpreting this to mean all segments are required rather than one, which is the intent of the spec specifying the OR operator (i.e. |). Also, because we have defined this as being 6 segments the indexes are off, which means it will never match a real ORM message.

@ahives
Copy link
Contributor Author

ahives commented Nov 19, 2017

ORR_O02_ORDERMap has same problem

@phatboyg
Copy link
Owner

So this is a choice, and you're right, the generated map just isn't going to cut it.

The question is, should the Layout include a single Segment, which can be one of those types, or does there need to be a new type which allows a selection/choice of segments.

Because of things like Segment<OBR> are only going to support OBR.

But using something like Segment<HL7Entity> is less than obvious, and requires the ability to TryGetEntity<T> in order to bring it back as a typed segment.

@ahives
Copy link
Contributor Author

ahives commented Nov 30, 2017

Here is what I am thinking...

Introduce a new type to provide a choice (e.g. Segment<Option<OBR, RQD, RQ1, RXO, ODS, ODT>>)

The field in the ORM_O01_ORDER_DETAIL layout could look something like this...
Segment<Option<OBR, RQD, RQ1, RXO, ODS, ODT>> OrderDetail { get; }

The corresponding map would look something like this...
public class ORM_O01_ORDER_DETAILMap : HL7V26LayoutMap<ORM_O01_ORDER_DETAIL> { public ORM_O01_ORDER_DETAILMap() { Option(x => OrderDetail, 0, x => x.Required = true); Segment(x => x.NTE, 1); Segment(x => x.CTD, 2); Segment(x => x.DG1, 3); Layout(x => x.Observation, 4); } }

The Option method would work similar to Layout in that it would allow you define at the Segment level. This would sick because we would also be able to potentially define optional layouts. The corresponding map could look something like this...

public class ORDER_DETAILMap : HL7V26SegmentOptionMap<ORDER_DETAIL> { public ORM_O01_ORDER_DETAILMap() { Segment(x => x.OBR); Segment(x => x.RQD); Segment(x => x.RQ1); Segment(x => x.RXO); Segment(x => x.ODS); Segment(x => x.ODT); } }

@phatboyg
Copy link
Owner

Well, I won't nest generic types like that, it's a train wreck of complexity.

Since the segments and maps are all generated code, it doesn't matter if the configuration of it is verbose, so I'm thinking that another type of Layout makes sense. A type that has a property for each Segment, and they're all optional, but the Option type itself is required, and an option type is valid if one of the segments is present. It's essentially how you would specify an Or condition in a layout.

    public interface OrderDetailOption {
        Segment<OBR> OBR;
        Segment<RQD> RQD;

Then in the map

    Option(x => x.OrderDetail, 0, x => x.IsRequired());

Then you could select using detail.Select(x => x.OrderDetail, x => x.OBR) and if it was present, it would continue, otherwise, HasValue would be false.

@phatboyg
Copy link
Owner

The more I think about this, the more it makes sense to just have a Segment, and provide the ability to dynamically cast it so it can be used in pattern matching rather than forcing it into a separate interface.

Then the map can specify the valid types.

Option(x => x.First, x =>
{
   x.Segment<OBR>();
   x.Segment<RQD>(); 
});

@ahives
Copy link
Contributor Author

ahives commented Dec 1, 2017

Yeah, I see your point. It would make more sense doing it at the map level.

So, the map would something like this..

Option(x => x.OrderDetail, x =>
{
x.Segment();
x.Segment();
},
0,
x.IsRequired());

So, the more I think about it, we will also need something similar on the query side as well.

How would I use this in the Query method?

How would I access it off of EntityResult?

It might make sense also thinking about it from the query perspective as well. Perhaps defining it as an interface instead of dynamically makes most sense when thinking about querying.

I can imagine that we would need to have some extension methods hanging off of the EntityResult to get at and perform work:

Select<TSegment> : need to be able to return the optional result
Is<TSegment> : need to be able to determine which of the segments (i.e. OBR, RQD, RQ1, RXO, ODS, ODT) was returned, ex: .Is<OBR>()
To<TSegment> : need to be able to cast to one of the segments in order to operate on them, ex: .To<OBR>. If this fails it would return an Empty<TSegment>

Perhaps would need to modify Translates as well to be able to get at conditional segments.

ahives added a commit to ahives/Machete that referenced this issue Dec 11, 2017
ignored test because of issue phatboyg#39
phatboyg pushed a commit to MassTransit/Machete that referenced this issue Dec 11, 2017
@ahives
Copy link
Contributor Author

ahives commented Mar 18, 2018

At this point many Layouts are not useful until this is fixed. This is a critical bug. I currently don't see this as a problem in X12. This seems to be strictly an HL7 issue for now but I think it probably should be commonly available to any Schema. @phatboyg

@ahives
Copy link
Contributor Author

ahives commented Oct 30, 2018

HL7 layouts cannot work without this functionality.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants