Stefan Wittmann · May 3, 2016 go to post

You have to use the WRITE command instead of DO. I/O redirection is flawed with the DO command.

But, I do not see you using the new %Object and %Array classes. Instead your code builds a proxyObject and calls $toJSON() on it. Why are you not directly building %Object and %Array instances?

Stefan Wittmann · May 2, 2016 go to post

Looking at your includes, you have to make sure that you include jQuery first and then jQM. The error signals, that jQuery is loaded fine, but jQueryMobile is not.

Stefan Wittmann · Apr 28, 2016 go to post

Steve, you've included the jQuery library twice. Only import the latest release of jQuery and you should be fine. If not, let us know.

Stefan Wittmann · Apr 27, 2016 go to post

We are working on a solution for this. We plan to automatically clear the cache of the base URL path and associated subpaths in the CSP Gateway for REST enabled CSP applications after the application got enabled.

Stefan Wittmann · Apr 27, 2016 go to post

These are the first two options I always enable in all my Studio environments. If you haven't made use of them yet, give them a try.

Stefan Wittmann · Apr 27, 2016 go to post

You are on the right path. Zen Mojo 1.1.0 prevented the drop-down menu from closing because we did not bubble up the event. We addressed this issue in Zen Mojo 1.1.1.

Make sure to upgrade to the latest version of Zen Mojo. You have to return false in your onselect event handler to allow the event to bubble up which will automatically close the drop-down menu after the user selected an item. 

Stefan Wittmann · Apr 25, 2016 go to post

If it is more complex to determine the data set, because you have specific parameters in mind it makes sense to select the data via SQL and insert the selected record into the other instance via SQL. You can either use linked tables, which allows you to write this simple logic in Caché Object Script, or you can write a simple Java application and go directly via JDBC. Obviously, any supported client-side language can solve this challenge, Java is just one option.

In case you have to migrate data where the model includes foreign-key constraints, you have to use the %NOCHECK keyword in your SQL INSERT statement: http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY…

This approach is definitely more work than just exporting/importing the data, but it allows to easily add simple logic with some benefits, e.g. anonymization, batch-loading and parallelization. Depending on your use case some of these topics may be relevant.

Stefan Wittmann · Apr 21, 2016 go to post

The $toJSONFormat() method provided a way to output a formatted (pretty-printed) JSON string/stream. There is an effort involved to make sure such a method works properly on all supported platforms (which it didn't) and in addition, there are various options that users would ask for (like omitting null values, intent or no intent, intent with spaces, etc...). We had a similar experience with the previous JSON API.

We decided to put our initial efforts into the machinery and not into pretty-printing. For that reason, we do not produce any output that is irrelevant for machine processing, which is the major task for this output as JSON is a data-interchange format.

It is very simple to post-process a JSON file or string and pretty-print or minify it. There are online tools like

http://www.freeformatter.com/json-formatter.html

and there is functionality/plugins available for popular text editors like Sublime 3:

https://github.com/dzhibas/SublimePrettyJson

Also, there are many node.js packages available that pretty-print or minify JSON files and that can be automated with a grunt/gulp task if you have to automate this for some reason. 

Personally, I just copy/paste my JSON content into Sublime3 and pretty print it.

Stefan Wittmann · Apr 19, 2016 go to post

That is correct. If you expect to serve larger JSON content you should make use of the stream interface as Dmitry has pointed out. Here is a snippet that copies the content of a dynamic object to a local file on windows:

ClassMethod WriteObjectToFile(pObject As %Object)
{

set stream=##class(%Stream.TmpCharacter).%New()
set filestream=##class(%Stream.FileCharacter).%New()
set sc=filestream.LinkToFile("c:\Temp\jsonfile.txt")
do pObject.$toJSON(stream)

do filestream.CopyFrom(stream)
do filestream.%Save()

}
Stefan Wittmann · Apr 19, 2016 go to post

Sure, that is a valid solution for a developer or test system. But we definitely need something better for production usage.

Stefan Wittmann · Apr 19, 2016 go to post

Hm, interesting. So what this basically means is that the 404 page gets cached when a URL is requested and it is not available. Re-enabling the REST application does not clear that cache and that is the reason why the REST application does not work for the URLs that have the 404 cached when it's enabled again.

Automatically clearing the cache for a REST application is not trivial, as it does not translate to a single URL. I will check back with the developers and see what we can do about this.

Stefan Wittmann · Apr 19, 2016 go to post

Well, that depends on where you did take the lock.

In your previous example you take a lock right before the try block, so you can release it directly after the try/catch block.

If you take a lock in your try block, you have to put the unlock code both in the catch block and at the end of the try block. I would not place the unlock code outside of the try/catch block. This is a case where a try/catch/finally construct would definitely help, as you could place the unlock code in the finally block. 

Stefan Wittmann · Apr 19, 2016 go to post

Not in the near-term. We are using a highly optimized in-memory and on-disk structure for our JSON support and the document data model. Providing more features and adding more optimizations to this structure stays a priority.

Our model allows us to support other serialization formats as well and we have some hooks in place we plan to leverage in the future. MessagePack and other serializations are on the tentative list for this, but nothing is carved in stone at the moment.

Do you have a specific use case where MessagePack is a requirement?

Stefan Wittmann · Apr 18, 2016 go to post

Well, I think a major question is: What do you use to return runtime information to your caller when you implement your own code? Do you return a %Status object, or something similar, or do you throw exceptions and don't return anything.

Most code snippets I have seen here make use of try/catch, but do return a status code itself. 

Personally, I prefer to use try/catch blocks and throw errors when I encounter issues at runtime. The try/catch philosophy is optimized for the case that everything goes well and exceptions are the, well, exception. Handling a status object is not as clean from a code maintenance perspective (more lines of code within your logic), but allows you to handle multiple different scenarios at once (it was okay/not okay, and this happened...)

Obviously, this is my personal preference.

Stefan Wittmann · Apr 18, 2016 go to post

do a.$toJSON() does not work properly with I/O redirection. This is a known issue and will be fixed in future releases. The workaround is very simple: use write a.$toJSON(), or write something else to the stream before (like you did in your second example).

Personally, I prefer to be explicit in my REST methods and use the write command when I want to output something to the response stream. So this code snippet will work in your REST class:

ClassMethod Test() As %Status
{
set "test":}
write a.$toJSON()
quit $$$OK
}

Stefan Wittmann · Apr 15, 2016 go to post

Jochen's approach is one way of dealing with this scenario. Another approach is to always inject the header and footer layout and drive the content with a data binding. This way you can always include your generic header/footer layout objects in all of your pages. This approach also allows you to implement your header and footer logic in a central method, so you don't duplicate code.

If you want more sophisticated control, you can easily build your own plugin and implement your own header/footer components with specialized logic and behavior.

Stefan Wittmann · Apr 7, 2016 go to post

I am not sure if this helps, but I want to mention that Ensemble comes with an option to export all classes and routines that are required to run an Ensemble production. At least, all dependencies Ensemble can resolve.

You can find the related documentation here:

http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY…

Maybe you can take a look at the code behind the scenes, or analyze the output of such an export.

Stefan Wittmann · Apr 7, 2016 go to post

We have no way to represent these special JSON values in Caché Object Script. When you access these special values they are automatically converted to a friendly Caché Object Script value. Here is some more code to describe this based on the snippets I used before:

USER>write object.$getTypeOf("boolean")
boolean
USER>write object.$getTypeOf("nullValue")
null
USER>write object.$getTypeOf("numeric")
number
USER>write object.boolean
0
USER>write object.anotherBoolean
1

You can see, that I can retrieve the type for each property using the $getTypeOf() method. The boolean property returns 0 while the anotherBoolean property returns 1. Both are Caché Object Script-friendly and allow embedding in if-statements.

We would have lost that capability if we introduced special Caché Object Script values to reference special JSON values. In addition, you have to have in mind, that we plan to introduce more serialization formats in the future, so we may not only talk about special JSON values here.

Does that make sense?

Stefan Wittmann · Apr 7, 2016 go to post

I see. Serializing registered and persistent objects to JSON is a new feature in 2016.2. $toJSON() allows you to serialize these objects using a standard projection algorithm that we provide. There are ways how you can specify your own projection logic, in case the standard logic is insufficient for your needs.

$compose() is a new method that lets you project dynamic entities (%Object and %Array instances) to registered and persistent objects (and vice-versa).

The $compose functionality is using the same standard projection logic. Later versions will allow you to specify and store projection rules for specific needs.

Stefan Wittmann · Apr 7, 2016 go to post

Absolutely. If you are using the embedded JSON-style constructor you can directly make use of special values:

USER>set object = {"boolean":false,"numeric":2.2,"nullValue":null}
 
USER>write object.$toJSON()
{"boolean":false,"numeric":2.2,"nullValue":null}

If you want to manipulate or add special values like null and true/false, you have to use the setter method $set and specify the type with the optional third argument:

USER>do object.$set("anotherBoolean",1,"boolean")
 
USER>write object.$toJSON()
{"boolean":false,"numeric":2.2,"nullValue":null,"anotherBoolean":true}
If I wouldn't have specified the type in the above sample, the value would have been set to the numeric value 1.
HTH,
Stefan
Stefan Wittmann · Apr 7, 2016 go to post

I just tested this in a 2016.2 FieldTest terminal session:

USER>set object = {"":"test"}
 
USER>w object.$toJSON()
{"":"test"}
USER>set object."" = "one more test"
 
USER>w object.$toJSON()
{"":"one more test"}

So the answer is, yes we do support empty keys.

We have and continue to test our JSON implementation heavily. If you come across anything that looks incomplete, incorrect or just behaves in unexpected ways, let us know. We are happy to take a look at it.

Many thanks, Stefan

Stefan Wittmann · Apr 7, 2016 go to post

I am not sure I understand your question. Do you want to subclass from %Object and %Array? If so for what purpose?

Stefan Wittmann · Apr 4, 2016 go to post

Mike, you can favorite a post and later on you can find them again under "My content -> my favorites". Does that help?

Stefan Wittmann · Apr 1, 2016 go to post

I think you have to manually resort the CacheTemp global into another location based on the sortColumn and sortOrder properties of your table. Some work, but doable. Timothy provided some insight to that approach.

Stefan Wittmann · Apr 1, 2016 go to post

There is no easy way to achieve this on the server side. But you can easily extract the currently displayed data set on the client. Here is a code snippet that works with the tablePane demo ZENTest.TableTest.cls in the SAMPLES namespace:

var t = zen('table')
for (var i = 0;i < t.pageSize; i++) { console.log(t.getRenderedRowData(i)) }

The code snippet will render each individual row, respecting the current filtering and order.

Stefan Wittmann · Apr 1, 2016 go to post

I used the Google Geocode API some while ago and if you call it occasionally you won't see any issues. If you want to bulk load some data and attach lat/long values during that process you have to queue your requests to Google. They only allow 3~4 requests per second for each API key otherwise, you will get a bad response.