Define a contract using query string parameter in json path assertion - spring-cloud-contract

I'm trying to use SCC to write some contracts before I rebuild the producer side (there are no existing tests!). The examples around lists and deeper data structures in the documents are a bit thin, so I want to understand if this is feasible, or perhaps I have to drop down to calling a command to make the right assertions.
I'm using the latest version v2.11
So -
Given:
An API that will return a list of objects in its payload. The length of the list will depending on the identity of the client, i.e. client A will get 3 items, client B will get 4 items. The identity of the client isn't of interest here.
When:
A client makes a GET request, passing a querystring parameter for item selection within the list of items
Then:
I want to write a contract that takes input from request and proves that the response contains a list of objects, and the item that matches the selector has a boolean field selected:true, while the rest of the items have selected:false. There's an edge where the selector is wrong and no item is selected.
E.g. For the request GET /someapi?id=bbb
Response
{ foo: xxxy, bar: 123, baz: [
{ id: 'aaa', selected: false, .... },
{ id: 'bbb', selected: true, .... },
{ id: 'ccc', selected: false, .... }
] }
Of course the selected item can be anywhere in the list. So I had in mind an assertion like this pseudo code -
jsonPath('$.baz[?(#.id == fromRequest().query("id"))].selected', byEquality( true ) )
But I can't do that fromRequest() stuff in the JSONPath statement. Right now I guess I could simply have the whole response body as the spec, but that seems unwieldy. If it must be, that's fine I guess.
Any ideas or help appreciated.

Related

QML Firebase startAt returns undefined

I am working on a 'typeahead’ type function which will check my Database with the current typed text to provide search suggestions of users using Felgo.
Here is the link for Felgos Firebase documentation
As to not search every entry I am looking to use the startAt and limitTo for a lower data use.
However when applying the startAt my searches only return undefined, I have tried testing this by changing my startAt from a variable to explicit data but this still only returns undefined.
My function is below:
function searchUsers(searchString) {
db.getValue("public/nameList/", {
orderByChild: true,
startAt: searchString, //searchString is a variable with my .currentText to search.
limitToFirst: 10,
}, function(success, key, value) {
if(success) {
searchArr = []
searchArr = value
console.debug("Read user value for key", key, "from DB:", value)
}
})
}
I have also tried by passing my var searchString through JSON.stringify(searchString) and also return undefined!
Removing the startAt: query entirely returns the entire result of nameList as expected, but no matter how I try to implement my startAt it always returns undefined.
A sample of my nameList JSON is:
nameList: {
"EddieLaw245" : 530343772383,
"EddieLawrence91" : 530343772385,
"EdwardL91" : 530343772386,
"EdwardLaw" : 530343772384,
"Edwardlawrence91" : 530343772380,
"JoBrownLondon" : 530343772381,
"KatiePrescottHair" : 543592635596,
"Tracey-Sweeting" : 530343772382
}
So with the above example, When I type E it should remove the last 3 entries, and so on.
The problem is that you're specifying orderByChild: true. If we look at the documentation of that:
orderByChild: If present, the queried object will have its properties ordered by values at sub-paths defined by the value of this property. Ordering by child properties makes the filter properties startAt, endAt and equalTo filter by the child property values
It may not be immediately clear from this, but orderByChild allows you to order the results on a property value under each of those nodes. So your code tries to order the child nodes on the value of a property true, which isn't possible (and should actually generate a compile-time error in the library) as the nodes under nameList don't have any child properties of their own. They merely have a key and a value.
What you're looking for is orderByKeys, which orders the child nodes on their keys. So:
db.getValue("public/nameList/", {
orderByKeys: true,
startAt: searchString,
limitToFirst: 10,
}
You'll typically also want to specify an endAt value, to ensure your type-ahead only shows values that start with the search string. If you only allow ASCII values in the keys, the simplest way to do this is:
startAt: searchString,
endAt: searchString + "~",
The ~ here is no magic operator, but merely the last ASCII characters. If you want to allow a broader character set, you'll need to use the last character in that character set - for example \uF7FF is the last code point for Unicode.
Update from OP
Though I'm certian Franks correct with typical Firebase usage; I suspect due to the Felgo plugin I am using the full solution has a slight adjustment;
db.getValue("public/nameList/", {
"orderByKey": true,
"startAt": searchString,
"endAt": searchString+"~",
"limitToFirst": 10,
}, function(success, key, value) {....}
})
Notes on the above - my filters/queries are surrounded by quotation marks "startAt", also instead of orderByKeys, I have used orderByKey

inserting a nested attributes array element in dynamodb table without retrieving the entire item

looking for an answer to this question if possible, not looking for a refactoring advice or redesign, i just need to understand what else I am missing here :
I have an existing item in dynamodb:
{
"CartId": 321,
"UserId": usr555,
"CartItems": [
{
"ProductId":59999,
"Quantity": 1
},
{
"ProductId": 58888,
"Quantity": 2
}
]
}
in my code I want to insert another nested attribute into the array CartItems in the item above. i can't find a way of doing this without retrieving the entire item and then inserting, which could amount to KBs in size.
all I want to do is insert a single array element in an existing nested attribute without having to retrieve the item.
the language I am using is nodejs and the function is DynamoDB.put.
UpdateExpression attribute supports SET action and SET action supports list_append function. Since list_append function operands must be list, enclose the new value within a list as below.
response = dynamodb_client.update_item(TableName='your_table',
Key={'CartId':'321'},
UpdateExpression='SET CartItems = list_append(CartItems, :val1)',
ExpressionAttributeValues = {':val1':[{'ProductId':12345, 'Quantity': 100}]})
Hope this helps

How to Deserialize null response in js-data

The find method in js-data-http appears to have a special case where if item is falsey then it will reject the promise, otherwise it returns item. My problem is that some falsey values (0, null, '') are valid responses from my API.
For example if I ask for a relation that hasn't been set then the API responds with data null wrapped in a jsonapi envelope. This follows the jsonapi spec for fetching empty relationships:
{
"links": {
"self": "/articles/1/relationships/author",
"related": "/articles/1/author"
},
"data": null
}
I'm using the js-data-jsonapi library to help js-data and jsonapi get along. In that library the DeSerializer unwraps the jsonapi envelop. At that point js-data is back in charge and the unwrapped data null is the value for item in the find promise resolve method which causes js-data-http to reject the promise.
Right now I'm taking advantage of a special case in js-data-jsonapi to deserialize null data as an array because in JS Arrays are truthy. But then I must special case the detection for hasOne relations where now an empty array must be re-converted into null.
This seems like an overly complicated way of handling things, is there a better way that I am missing?
My setup uses:
"angular": "1.5.8",
"js-data": "2.9.0",
"js-data-angular": "3.2.1",
"js-data-jsonapi": "0.0.0-alpha.21",

Registering and retrieving 'interactions' with SCORM 1.2

We've been using SCORM in our previous e-learning 'engine' but we want to change the elements our Managed Learning Environment (MLE) tracks, namely each completable component in an e-learning module.
At runtime, we run the following code to set up our SCORM connection:
var vault = {}; //vault 'namespace' helps ensure no conflicts with possible other "SCORM" variables
vault.UTILS = {}; //For holding UTILS functions
vault.debug = { isActive: true }; //Enable (true) or disable (false) for debug mode
vault.SCORM = { //Define the SCORM object
version: null, //Store SCORM version.
handleCompletionStatus: true, //Whether or not the wrapper should automatically handle the initial completion status
handleExitMode: true, //Whether or not the wrapper should automatically handle the exit mode
API:{handle: null, isFound: false}, //Create API child object
connection: { isActive: false }, //Create connection child object
data: { completionStatus: null, exitStatus: null}, //Create data child object
debug:{} //Create debug child object
};
vault.SCORM.API.find('win');
vault.SCORM.connection.initialize();
if (vault.SCORM.data.get("cmi.core.lesson_status")=="not attempted") {
vault.SCORM.data.set("cmi.core.lesson_status" , "incomplete");
vault.SCORM.data.save();
}
There are many more functions in the SCORM.js file, but the point is this all works; When the module is loaded into our MLE, the following code triggers course completion:
vault.SCORM.data.set("cmi.core.lesson_status" , "completed");
So how would we register a completable component with SCORM? (Components in our 'engine' are jQuery objects usually called 'element'). Would something like the following work, or are custom calls in SCORM not possible?
vault.SCORM.data.set("cmi.interactions.n."+element.componentId() , "incomplete");
But then if I registered an interaction by specifying an id, as follows...
vault.SCORM.data.set("cmi.interactions.n.id", element.componentId());
...how do I then set or access 'completion' on that component?
I've been reading posts and pdf specs from various sites, but the explanations are sparse at best.
I know there aren't a lot of SCORM followers here, but if you have any info, I'd be keen to hear it.
FWIW, that's my pipwerks SCORM wrapper, but with the variable pipwerks changed to ncalt.
There is documentation on how to use my wrapper at http://pipwerks.com (search for "scorm wrapper" in the search field). The original source code can be found at https://github.com/pipwerks/scorm-api-wrapper.
Note your sample code is not using the wrapper the way it was intended to be used. For example, this:
ncalt.SCORM.data.set("cmi.core.lesson_status" , "completed");
should be this (data is an internal helper and not necessary):
ncalt.SCORM.set("cmi.core.lesson_status" , "completed");
You can shorten it even further via a reference variable, like so:
var scorm = ncalt.SCORM;
scorm.set("cmi.core.lesson_status" , "completed");
scorm.save();
scorm.get("cmi.core.lesson_status"); //returns "completed"
As for your 'components', if you'd like to use SCORM's cmi.interactions model, be sure you're using the correct syntax. The "n" in the SCORM documentation (cmi.interactions.n.id) is meant to represent a number, it's not a literal "n".
scorm.set("cmi.interactions.0.id", "myfirstinteraction");
scorm.save();
To retrieve data from that interaction, you need to specify the number in place of the n:
scorm.get("cmi.interactions.0.id"); //returns "myfirstinteraction"
Note the CMI data model doesn't provide a 'status' field for cmi.interactions. You'd need to use cmi.objectives.
scorm.set("cmi.objectives.0.status", "completed");
scorm.save();
scorm.get("cmi.objectives.0.status"); // returns "completed"
The CMI data model (as available in SCORM) is spelled out here: http://scorm.com/scorm-explained/technical-scorm/run-time/run-time-reference/

Identity in ractive data arrays

I have an object of message streams that looks like this:
ractive.data.messages:
{
stream_id1: {
some_stream_metadata: "foo",
stream: [
{id: "someid1", message: "message1"},
{id: "someid2", message: "message2"}
]
},
stream_id2: {
some_stream_metadata: "bar",
stream: [
{id: "someid3", message: "message3"},
{id: "someid4", message: "message4"}
]
}
}
main_template:
{{#messages[ current_stream_id ]}}
{{>render_message_stream}}
{{/messages[ current_stream_id ]}}
render_message_stream:
{{#stream}}
<div class="stream">
...someotherstuff...
{{>render_message}}
</div>
{{/stream}}
render_message:
<div class="message">
...someotherstuff...
{{message}}
</div>
I change "current_stream_id" to change the rendered stream of messages.
On updates, i change the contents of the message streams like this:
ractive.merge(
"messages.stream_id1.stream",
new_message_stream,
{
compare: function ( item ) { return item.id; }
});
I also tried the compare: true option instead of the function, with the same results:
Ractive always thinks that these two messages belong effectively to the same DOM element, even though they live in a completely different message stream:
ractive.data.messages[ "stream_id1" ].stream[1].message
ractive.data.messages[ "stream_id2" ].stream[1].message
Problems:
When there are intro/outro animations ractive animates always just the end of the messages stream, even when a message in the middle of the stream was deleted, i need help to make ractive understand which messages are identical.
When i change the current_stream_id, ractive does not rerender the complete {{>render_message_stream}} partial, but goes inside the existing dom and changes the {{message}} field in all existing messages, though this might be good for dom element reuse, this triggers a lot of animations that are wrong. (Eg. it triggers intro/outro animations for the last message in the stream if stream1 has one message more than stream2).
One of these issues has a straightforward answer; unfortunately the other one doesn't.
I'll start with the easy one - the fact that
ractive.data.messages[ "stream_id1" ].stream[1].message
ractive.data.messages[ "stream_id2" ].stream[1].message
belong to the same DOM element. You're correct in that Ractive updates the existing elements rather than removing them and creating new ones - this is a core part of its design. In this case that's undesirable behaviour, but you can work around it like so:
// instead of immediately switching to a new stream ID like this...
ractive.set( 'current_stream_id', 'stream_id2' );
// you can set it to a non-existent ID. That will cause the existing DOM
// to be removed. When you set it to an ID that *does* exist, new DOM
// will be created:
ractive.set( 'current_stream_id', null );
ractive.set( 'current_stream_id', 'stream_id2' );
// or, if you'd like the initial transitions to complete first...
ractive.set( 'current_stream_id', null ).then(function () {
ractive.set( 'current_stream_id', 'stream_id2' );
});
The other issue - that merge() isn't merging, but is instead behaving as though you were doing ractive.set('messages.stream_id1.stream', new_message_stream) - is tougher. The problem is that while you and I know that {{#messages[ current_stream_id ]}} equates to messages.stream_id1 when current_stream_id === 'stream_id1, Ractive doesn't.
What it does know is that we have an expression whose value is determined by messages and current_stream_id. When the value of either of those references changes, the expression is re-evaluated, and if that value changes, the DOM gets updated - but using a standard set(). When you do ractive.merge('messages.stream_id1.stream', ...), Ractive updates all the things that depend on keypaths that are 'upstream' or 'downstream' of messages.stream_id1.stream - which includes messages. So that's how the expression knows that it needs to re-evaluate.
It's possible that a future version of Ractive will be able to handle this case in a smarter fashion. Perhaps it could make a note of arrays that are subject to merge operations, and check evaluator results to see if they're identical to one of those arrays, and if so use merge() rather than set(). Perhaps it could analyse the function in some way to see if the {{#messages[ current_stream_id ]}} section should register itself as a dependant of messages.stream_id1 for as long as current_stream_id === 'stream_id1', rather than the internally-generated ${messages-current_stream_id-} keypath.
None of that helps you in the meantime though. The only way to use merge() in your current situation is to have a separate reference that doesn't use an expression, and a bit of magic with pattern observers:
main_template:
{{#current_messages}} <!-- rather than `messages[ current_stream_id ]` -->
{{>render_message_stream}}
{{/current_messages}}
render_message_stream:
{{#current_message_stream}} <!-- rather than `stream` -->
<div class="stream">
{{>render_message}}
</div>
{{/current_message_stream}}
code:
ractive.observe( 'current_stream_id', function ( id ) {
var current_messages = this.get( 'messages.' + id );
this.set( 'current_messages', current_messages );
// hide existing stream, then show new stream
this.set( 'current_message_stream', null ).then(function () {
this.set( 'current_message_stream', current_messages.stream );
});
});
// when ANY message stream changes, we see if it's the current one - if so, we
// perform a merge on the top-level `current_message_stream` array
ractive.observe( 'messages.*.stream', function ( new_stream, old_stream, keypath, id ) {
// the value of any * characters are passed in as extra arguments, hence `id`
if ( id === this.get( 'current_stream_id' ) ) {
this.merge( 'current_message_stream', new_stream, {
compare: function ( item ) {
return item.id;
}
});
}
});
I've set up a JSFiddle demonstrating this. I hope it makes sense, let me know if not - and sorry I didn't get round to answering this question much sooner.

Resources