Create deep entity without deep structure - odata

I want to pass an amount of storage units in one step. I need all storage units at once in the CREATE_ENTITY method in my OData service implementation (CREATE_ENTITY, or CREATE_DEEP_ENTITY, or...?), because I have to make a comparison of some values.
I tried a batch request. This doesn't work, because the CREATE_ENTITY method was called for each storage unit. So I could access only one storage unit in each call.
I also searched for tutorials concerning deep_entities. But I only find some with deep structures (head - items). But I have a flat structure (key: storage Unit) and want to pass this as table/array to my CREATE_ENTITY method. It should be possible to do this in SAPUI5.
As workaround I could pass all storage units into a string and pass this to the CREATE_ENTITY method. But that seems quite amateurish to me.
Here is how I invoke CREATE method:
onStartVert: function () {
this.oContext = this.getModel().createEntry("/LenumIPunktSet", {
success: this._successSave.bind(this),
error: this._errorSave.bind(this)
});
var oBindingPath = {
path: this.oContext.getPath()
};
this.getView().bindObject(oBindingPath);
var sLenum;
for (var i = 0; i < this._data.LePool.length; i++) {
sLenum = this._data.LePool[i].lenum;
this.getModel().create("/LenumIPunktSet", {
lenum: sLenum
});
}
this.getModel().submitChanges();
this.getRouter().navTo("iPunkt02");
},
The signature for the CHANGESET_PROCESS method is:
CT_CHANGESET_DATA TYPE /IWBEP/IF_MGW_CORE_SRV_RUNTIME=>TY_T_CHANGESET_DATA
/IWBEP/CX_MGW_BUSI_EXCEPTION Business Exception
/IWBEP/CX_MGW_TECH_EXCEPTION Technical Exception
So, by now there is no table IT_CHANGESET_REQUEST available.
My entity type has only this one field (lenum) I need as key.

The key is to implement a changeset.
In your DPC_EXT redefine the following three methods:
The method CHANGESET_BEGIN will activate the batch processing.
METHOD /iwbep/if_mgw_appl_srv_runtime~changeset_begin.
cv_defer_mode = 'X'.
ENDMETHOD.
METHOD /iwbep/if_mgw_appl_srv_runtime~changeset_end.
* empty
ENDMETHOD.
The method changeset_process will contain the logic. it_changeset_request contains all entities which are part of this batch request.
METHOD /iwbep/if_mgw_appl_srv_runtime~changeset_process.
LOOP AT it_changeset_request ASSIGNING FIELD-SYMBOL(<fs_changeset_request>).
" <fs_changeset_request>-request_context->get_request_details( ) << which entity is it?
" <fs_changeset_request>-operation_type << is it CREATE, UPDATE or DELETE?
" <fs_changeset_request>-entry_provider->read_entry_data( ... ) << read entity into structure
ENDLOOP.
ENDMETHOD.
See this blog for some details.

Related

Language-ext: chain Either<L, R> with Option?

I am just starting with language-ext, trying to use it in my Azure Function.
In this function, I first parse/validate the POSTed data from the HTTP request using some validator.
This validator returns an Either<ValidationErrors, RequestModel>.
Then I would like to chain onto the either result a service call that should use the request model to grab some data from an API an return an Option.
At the end of the chain I would then like to return an IActionResult BadRequest if there were ValidationErrors in the first step, or otherwise perform a Match on the result of the service call Option to either return a NotFoundResult or ObjectResult.
The issue I run into is that if I want to chain my service call (using Bind, or BiBind) after the Either<ValidationErrors, GetRequestModel>, then the signature of my service method must be some Either<ValidationErrors, ...>, which is incorrect, since my service method has nothing to do with ValidationErrors. It should just return an Option.
So I guess my question is how can preserve any ValidationErrors until the end of the chain, and be able to chain my service call with a Option signature onto an Either?
You have to decide what the result of your chained expression is.
Option:
var maybeResult = from validated in GetValidationResult(...).ToOption()
from apiResult in ApiCall(...)
select apiResult;
Either:
var resultOrError = from validated in GetValidationResult(...)
from apiResult in ApiCall(...).ToEither(*LEFT*)
select apiResult;
You have to replace *LEFT* by some error value or error generating function returning same type like left type of GetValidationResult.
Replace above pseudo code with your own code and look at the return types of the functions used above to see what's going on.
The reason why you need a common left type is that the bind operation can return some left (error) of first (GetValidationResult) or second (ApiCall) function call -- or right of your last (ApiCall) function if your reach successful end of your chain.
Recommendation: If you mix different left (error) return types you might want to use some thing like LanguageExt's built-in Error type or maybe just a plain string (or Exception).
Either with string as error type:
var resultOrError = from validated in GetValidationResult(...).MapLeft(Prelude.toString)
from apiResult in ApiCall(...).ToEither("api call failed")
select apiResult;
Additional note: I use LINQ style here, you can use method style:
var resultOrError = GetValidationResult(...)
.MapLeft(Prelude.toString)
.Bind(validated => ApiCall(...)
.ToEither("api call failed"));

What is nodeInterface, nodeField and nodeDefinitions in Relay?

I am currently doing the facebook relayjs tutorial and I need help understanding this part of the tutorial, it states
Next, let's define a node interface and type. We need only provide a
way for Relay to map from an object to the GraphQL type associated
with that object, and from a global ID to the object it points to
const {nodeInterface, nodeField} = nodeDefinitions(
(globalId) => {
const {type, id} = fromGlobalId(globalId);
if (type === 'Game') {
return getGame(id);
} else if (type === 'HidingSpot') {
return getHidingSpot(id);
} else {
return null;
}
},
(obj) => {
if (obj instanceof Game) {
return gameType;
} else if (obj instanceof HidingSpot) {
return hidingSpotType;
} else {
return null;
}
}
);
On the first argument on nodeDefinition,where did it get its' globalId? is Game and HidingSpot a name on the GraphQLSchema? What does this 'const {type, id} = fromGlobalId(globalId);' do? and also what is the 2nd argument? I need help understanding nodeDefinitions, somehow I can't find nodeDefinitions on the official documentation. Thank you.
If you were writing a GraphQL server without Relay, you'd define a number of entry points on the Query type, eg:
type Query {
picture(id: Int!): Picture
user(id: Int!): User
...etc
}
So when you want to get a User, you can easily get it because user is available as an entry point into the graph. When you build a query for your page/screen, it'll typically be several levels deep, you might go user -> followers -> pictures.
Sometimes you want to be able to refetch only part of your query, perhaps you're paginating over a connection, or you've run a mutation. What Relay's Node interface does is give you a standard way to fetch any type that implements it via a globally unique ID. Relay is capable of recognising such nodes in its queries, and will use them if possible to make refetching and paginating more efficient. We add the node type to the root Query type:
type Query {
picture(id: Int!): Picture
user(id: Int!): User
...etc
node(id: ID!): Node
}
Now for nodeDefinitions. Essentially this function lets us define two things:
How to return an object given its globalId.
How to return a type given an object.
The first is used to take the ID argument of the node field and use it to resolve an object. The second allows your GraphQL server to work out which type of object was returned - this is necessary in order for us to be able to define fragments on specific types when querying node, so that we can actually get the data we want. Without this, we couldn't be able to successfully execute a query such as this:
query Test {
node(id: 'something') {
...fragment on Picture {
url
}
...fragment on User {
username
}
}
}
Relay uses global object identification, which means, in my understanding, if your application ever try to search for an object. In your example, try to look for a game, or try to look for a hidingSpot. Relay will try to fetches objects in the standard node interface. i.e. find by {id: 123} of the Game, or find by {id:abc} of the hidingSpot. If your schema (Game, HidingSpot) doesn't set up the node interface, Relay will not be able to fetch an object.
Therefore, if your application requires a search in a "Game", in the schema, you need to define the node interfaces.
By using graphql-relay helper, use nodeDefinitions function only once in your application to basically map globally defined Ids into actual data objects and their GraphQL types.
The first argument receives the globalId, we map the globalId into its corresponding data object. And the globalId can actually be used to read the type of the object using fromGlobalId function.
The second function receives the result object and Relay uses that to map an object to its GraphQL data type. So if the object is an instance of Game, it will return gameType, etc.
Hope it will help you understand. I am on my way learning, too.

IBM Integration Bus: How to read user defined node (Java) complex (table) property in Java extension code

I created Java user defined node in IntegrationToolkit (9.0.0.1) and assigned it with several properties. Two of the node properties are simple (of String type) and one property is complex (table property with predefined type of User-defined) that is consisted of another two simple properties.
By following the documentation I was able to read two simple properties in my Java extension class (that extends MbNode and implements MbNodeInterface) by making getters and setters that match the names of the two simple properties. Documentation also states that getters and setters should return and set String values whatever the real simple type of a property may be. Obviously, this would not work for my complex node property.
I was also able to read User Defined Properties that are defined on the message flow level, by using CMP (Integration Buss API) classes, which was another impossible thing to do from user defined node without CMP. At one point I began to think that my complex property would be among User Defined Properties, (although UDPs are defined on the flow level and my property is defined on the custom node level) based on some other random documentation and some other forum discussion.
I finally deduced that the complex property should map to MbTable type (as it is so stated in that type's description), but I was not able to use that.
Does anyone know how to access user defined node's complex(table) property value from Java?
I recently started working with WebSphere Message Broker v 8.0.0.5 for one of my projects and I was going to ask the same question until SO suggested your question which answered my question. It might be a little late for this question but it may help others having similar questions.
After many frustrating hours consulting IBM documentation this is what I found following your thread:
You're correct about the properties being available as user-defined properties (UDP) but only at the node level.
According to the JavaDoc for MbTable class (emphasis added to call out the relevant parts):
MbTable is a complex data type which contains one or more rows of simple data types. It structure is very similar to a * standard java record set. It can not be constructed in a node but instead is returned by the getUserDefinedAttribute() on the MbNode class. Its primary use is in allowing complex attributes to be defined on nodes instead of the normal static simple types. It can only be used in the runtime if a version of the toolkit that supports complex properties is being used.
You have to call com.ibm.broker.plugin.MbNode.getUserDefinedAttribute which will return an instance of com.ibm.broker.plugin.MbTable. However, the broker runtime doesn't call any setter methods for the complex attributes during the node initialization process like it does for simple properties. Also, you cannot access the complex attributes in either the constructor or the setter methods of other simple properties in the node class. These are available only in the run or evaluate method.
The following is the decompiled method definition of com.ibm.broker.plugin.MbNode.getUserDefinedAttribute.
public Object getUserDefinedAttribute(String string) {
Object object;
String string2 = "addDynamicTerminals";
if (Trace.isOn) {
Trace.logNamedEntry((Object)this, (String)string2);
}
if ((object = this.getUDA(string)) != null && object.getClass() == MbElement.class) {
try {
MbTable mbTable;
MbElement mbElement = (MbElement)object;
object = mbTable = new MbTable(mbElement);
}
catch (MbException var4_5) {
if (Trace.isOn) {
Trace.logStackTrace((Object)this, (String)string2, (Throwable)var4_5);
}
object = null;
}
}
if (Trace.isOn) {
Trace.logNamedExit((Object)this, (String)string2);
}
return object;
}
As you can see it always returns an instance of MbTable if the attribute is found.
I was able to access the complex attributes with the following code in my node definition:
#Override
public void evaluate(MbMessageAssembly inAssembly, MbInputTerminal inTerminal) throws MbException {
checkUserDefinedProperties();
}
/**
* #throws MbException
*/
private void checkUserDefinedProperties() throws MbException {
Object obj = getUserDefinedAttribute("geoLocations");
if (obj instanceof MbTable) {
MbTable table = (MbTable) obj;
int size = table.size();
int i = 0;
table.moveToRow(i);
for (; i < size; i++, table.next()) {
String latitude = (String) table.getValue("latitube");
String longitude = (String) table.getValue("longitude");
}
}
}
The documentation for declaring attributes for user-defined extensions in Java is surprisingly silent on this little bit of detail.
Please note that all the references and code are for WebSphere Message Broker v 8.0.0 and should be relevant for IBM Integration Bus 9.0.0.1 too.

breezejs: how to access enum metadata

I've noticed that in the metadata there's an object entityType but also an object enumType.
We use manager.metadataStore.getEntityType() to access the metadata of an Entity.
How can we do it for a given enum ? How would I create the enum on the client side out of the metadata ?
Also, when I assign an enum value to a property, I'd like to to it by name instead of by value.
For instance, assuming that Status is of type myEnum:
myEntity.Status = myEnum.Valid;
instead of
myEntity.Status = 1;
Does breeze have any helper function to access the values of an enum ?
This issue is still open as I write. But you might want to take a look at the work-around described in the answer to this SO question.
I am assuming that you are talking about data properties that are defined as .NET enums on the server, and you want additional metadata about these properties to be made available on the Breeze client.
Unfortunately, Breeze does not yet support any metadata on enum types other than the name of the .NET type backing the enum value. This is the 'enumType' property that will appear on any dataProperty that is backed by an .NET Enum on the server. (We do need to document this better)
Please add a feature request for this to the Breeze User Voice. It's a good idea and we do take these suggestions very seriously.
Well this is not exact solution to your question but definitely can help people who are generating metadata offline.
I am using NancyFx(No EF) + Breeze + AngularJS for my web project and generating breeze metadata offline(using EF methods at development) and then using it in js file.
I also encountered similar situation where I want to get all Enum values to bind dropdowns and to display EnumName corresponding to EnumValue(Id). I searched over net but there was not much as per my scenario.
So I have written raw JS methods
1. To extract all enums and their values(Id & Name) in a JS dictionary(associated array) from metadata.
var enumDictionary = {};
JSON.parse(window.app.metadata).schema.enumType.forEach(function (enumType) {
var newEnumValues = [];
enumType.member.forEach(function (enumValue) {
var newEnumValue = { id: enumValue.value, name: enumValue.name };
newEnumValues.push(newEnumValue);
});
enumDictionary[enumType.name] = newEnumValues;
});
I created a method to get all enum values for a specific enum. This will be used for binding a dropdown.
function GetEnumDictionary(enumName) {
return enumDictionary[enumName];
}
Another method I created to get specific Enum name on basis of value.
function GetEnumDictionaryValue(enumName, enumValueId) {
var result = null;
enumDictionary[enumName].some(function (enumValue) {
if (enumValue.id == enumValueId) {
result = enumValue.name;
return;
}
});
return result;
}

Breeze Entity defaultResourceName is undefined for sub-types when using inheritance

I have a Breeze Web API with a Vehicles, Cars, and Buses. Car and Bus types inherit from Vehicle type in a table per hierarchy database structure.
According to the Breeze docs one should be able to make the same query to call either the local cache (with executeQueryLocally) or the remote service (with executeQuery).
This does not work in the inheritance scenario for Buses and Cars because these types have their defaultResourceName = undefined. But it is odd that a call to the remote service works but not to the local cache. Code explains better:
var EntityQuery = breeze.EntityQuery;
var manager = new breeze.EntityManager('../../breeze/breeze');
var getRemoteCars = function() {
var query = EntityQuery.from('Cars');
return manager.executeQuery(query)
.then(querySucceeded)
.fail(queryFailed);
};
function querySucceeded(data) { console.log('Retrieved Cars from remote data source'); }
function queryFailed(data) { console.log('Failed to retrieve Cars from remote data source'); }
var getLocalCars = function () {
console.log("getLocals called");
var newQuery = new EntityQuery('Cars');
var cars = manager.executeQueryLocally(newQuery);
if (cars) console.log("retrieved some cars from local cache");
else console.log("no cars retrieved from local cache");
};
getRemoteCars().then(getLocalCars);
This code outputs:
Retrieved Cars from remote data source WebApiTest.html:26
getLocals called
Q] Unhandled rejection reasons (should be empty): []
The relevant error message is hidden by a Q.js error (which is a nuisance). Breeze.js threw an error that didn't make it to the Browser:
Cannot find an entityType for either entityTypeName: 'undefined' or resourceName: 'Cars'
It turns out the sub-types (Car and Bus) have defaultResourceName = undefined.
So I can fix the problem by adding:
manager.metadataStore.setEntityTypeForResourceName("Cars", "Car");
manager.metadataStore.setEntityTypeForResourceName("Buses", "Bus");
But that doesn't explain why the remote call worked.
So, firstly is this a bug that will be fixed and secondly, why does the remote call work when the local one does not?
EDIT 24 May 15:15 - More interesting behavior...
The above call to setEntityTypeForResourceName() must occur after the metadata has been retrieved from the server. But if you want to configure the metadataStore before this, you can use the fully qualified name like this:
manager.metadataStore.setEntityTypeForResourceName("Cars", "Car:#VerySimpleVehicleModel.Models");
manager.metadataStore.setEntityTypeForResourceName("Buses", "Bus:#VerySimpleVehicleModel.Models");
Interestingly, with this solution the defaultResourceName for Car and Bus types remain undefined, but the local call works. Strange, no??
We were able to reproduce the problem and it does appear to be a bug.
We are working on the fix.

Resources