go to post Stefan Wittmann · Jun 9, 2016 Your points are well taken. I would like to add some thoughts:Parent/Child relationship is an interesting concept, but it does not do well with larger volumes of data as you can't make use of bitmap indices in the child class. Embedding documents or serial classes on the other hand fully support bitmap indices which are important if you are operating on a larger set.Data type handling can be designed in a very flexible way. Your suggestion of using generic %String properties is one option to deal with flexible data types with Caché Persistent Objects. But you get no support of the backend for any complex values you store in such a property. You have to write code to serialize/deserialize your complex values and - even more important - you can't index sub-values as they are no properties. This may be suited for some use cases, but not for others.To answer your question about documenting schemas: Many developers just document sample JSON documents and explain what their purpose is. We offer no additional tooling for this yet, but we are working on tools that allow you to understand what a collection looks like. This is an area that will improve over time.
go to post Stefan Wittmann · Jun 6, 2016 Ben, Caché Objects don't come with exact the same benefits and I am happy to briefly discuss the differences and similarities. Actually, every time I talk about Caché Objects, I mean Caché Persistent Classes. Flexibility This one is simple. Caché Objects have a fixed schema. It can be changed for sure, but you have to potentially migrate your data if you still want to access it consistently. The impact depends on the type of the schema change, of course. If you just add a property, you are fine. Even some type changes may not require a data migration. Sparseness Caché Objects are persisted by making use of a storage strategy. By default, each property gets a slot in a $List structure. $List is optimized for sequentially accessing elements, not for random access, which is fine for a fixed schema world. You usually want to load all top-level values most of the time anyway. Therefore, the $List serialization is optimized for dense data. Assume an object has 100 properties and only properties 1,10,25,50,75 and 100 are filled. That is sparse data. With the $List serialization we have to jump through the empty buckets to read the six values we actually are interested in. That is a waste of time. Also, we are storing 94 empty buckets on disk. That is a waste of space, not much, but it can add up if your data is very sparse. Document stores embrace serialization formats that are optimized for storing sparse data in a compact form and for random access. Hierarchical Caché Objects can either link to instances of other classes (persistent class includes a property where the type points to another persistent class) or they can embed instances of another class (persistent class includes a property where the type points to another serial class). A document can embed another structure, which is similar to our serial class implementation because the data is actually physically stored together. One physical read of a document can retrieve every information you are interested in if it is designed correctly. You cannot compare embedding with a link to another table/class as the data is stored separately and usually requires access to separate blocks. Dynamic Types Properties of a Caché Object have a type. I can't take a timestamp and store it in a property with the type Sample.Person. The Object and SQL layer will validate values and ensure type safety for me. Document keys are not associated with a type at all. Only a value is. I can take two documents that have different types for the same key and store them in the same collection. This is an example of such two documents: set person1 = {"name":"Stefan Wittmann"} set person2 = {"name":{"first":"Stefan","last":"Wittmann","middle":null}} I can't simply model this with classes. person1 would require a %String property while person2 requires a link to a serial class. I hope this sheds some light on the individual benefits. Obviously, this comes with a price. Your application code has to do more validation as the backend allows you to work without a schema. There is always a cost involved.
go to post Stefan Wittmann · Jun 6, 2016 Correct. Just make sure that the checkbox "Show Generated" is checked.
go to post Stefan Wittmann · Jun 6, 2016 I will check this and come back to you. What platform are you looking at?
go to post Stefan Wittmann · Jun 6, 2016 I think you have two options:Open the generated class directly (*.cls instead of *.bpl)Open the Business process and go to View->View Other Code (Control + Shift + V)
go to post Stefan Wittmann · Jun 1, 2016 Yes, it is, but I am not sure if it is applicable to Dan's use case. The biggest technical difference is that GETs are cached by clients, while POSTs must not be cached.
go to post Stefan Wittmann · Jun 1, 2016 Q2: It is against core REST architecture principles, so I hope not.That is not entirely true. Filters and action descriptions are commonly exposed as URL parameters as they serve to either specify an action or limit the working set. But you are still operating on the same resource identity.What you can observe is that REST is just a best practice leveraging HTML. You will find any possible implementation of REST interfaces out there, some are true to the original spirit, some are not.Anyway, you can fight endless wars about REST interfaces, but one thing is for sure: URL parameters are commonly used for REST interfaces.To answer the original question: I don't see a need to add URL parameters to the URL map. They would only add value if we added them as method arguments, but I think that would be very confusing as path variables are passed as arguments at the moment.You can use the %request.Data property to retrieve the URL parameters.
go to post Stefan Wittmann · Jun 1, 2016 I have never actually tried to pass slashes as parameters, but I would guess that it should work if you encode them. I am aware that some systems drop these requests, because it is easy to inject malicious code this way.Are you receiving a 404 and use Apache? If so, you may have to enable the AllowEncodedSlashes directive:http://httpd.apache.org/docs/current/mod/core.html#allowencodedslashes
go to post Stefan Wittmann · May 30, 2016 I only managed to get my code down to 207 characters and it's even missing the whitespace->0 mapping, I saw that too late. Butwhoneedswhitespacestodayanyway? In case you are curious here is my code: #define a(%x) $LG(o,$a($E(s,%x,%x))-96) s (x,o)="" f m=2:1:9{s r="" f n=1:1:$S(m=7:4,m=9:4,1:3){s r=r_m,o=o_$LB(r)}} f j=1:1:$L(s)-1{s x=x_$$$a(j) s:$E($$$a(j+1),1,1)=$E(x,$L(x),*) x=x_" "} q x_$$$a($L(s)) The first part actually builds a $LIST with the mapping from characters to the corresponding keypad sequence. The second part loops over the input string and does a lookup for the keypad sequence. A look-ahead checks if I have to add a whitespace to indicate a pause. Because of the look-ahead I have to treat the last character conversion outside of my main loop. Tricks I used: Replace if statements with $SELECTUse SET statement to set multiple variables to the same valuesBuilt a macro for code you need multiple times (I need the lookup three times, in my main loop, for the look-ahead and for the last character conversion) Not an optimal algorithm and it's even lacking a piece, but still it is a fun exercise.
go to post Stefan Wittmann · May 27, 2016 The <html> component does not handle localization for you out of the box, as you can inject arbitrary HTML into it. Most of the other components do localize their captions and titles automatically if you set the DOMAIN parameter in your Zen page. A button component automatically creates a dictionary entry for its caption property, e.g.: <button caption="Save"/>
go to post Stefan Wittmann · May 27, 2016 Indeed. Starting with Caché 2016.2 you can call $toJSON() on registered and persistent objects and we will convert it with a standard projection logic into a dynamic entity (%Object or %Array) and serialize it as JSON with a $toJSON() call.If you want to modify your object before you output it to JSON you can first call $compose on your registered object to convert it to a dynamic object, modify it to your needs and then call $toJSON() on your modified dynamic object.Later versions will introduce more sophisticated means to influence the standard behavior of $compose. The addition of the JSON_OBJECT and JSON_ARRAY SQL functions allows you to easily create JSON from a SQL query as well, as Kenneth pointed out.
go to post Stefan Wittmann · May 27, 2016 You cannot use macros in Zen runtime expression this documentation chapter covers runtime expressions:http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=...If this question is actually about localizing text in Zen, please take a look at this documentation chapter:http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=...Localize your text in %OnGetJSResources() and load it on the client-side via zenText(id).
go to post Stefan Wittmann · May 23, 2016 I would write it like this: set array = [] while (result.Next()) { set object = { "data":{ "id":result.Data("ID"), "reg":result.Data("Registration"), "snNum":result.Data("SatNavVehNumber") } } do array.$push(object) } You can directly embed your values as Caché Object Script and that makes your code look pretty close like the desired outcome. This approach makes it very simple to build complex JSON structures and still know what you are doing.
go to post Stefan Wittmann · May 23, 2016 Steve, the correct approach is to eithera) subclass the plugin in question and generate a different HTML base or invoke additional beautify codeb) build your own plugin if you want to support a new layout objectWhat you describe sounds like a specialized $navbar component, so you may want to subclass the bootstrap plugin and register a specialized $navbar widget, e.g. $mynavbar.
go to post Stefan Wittmann · May 19, 2016 I am not able to view the image, but in general Object Synchronization can be used by multiple servers. The architecture is designed in such a way, that usually one node is taking the role of a master and all other nodes become clients to this master.You can implement other schemes as well, as indicated by this paragraph in the documentation:For object synchronization, the idea of client and server is by convention only. For any two databases, you can perform bidirectional updates; if there are more than two databases, you can choose what scheme you use to update all of them (such as local databases synchronizing with a main database independently).There is no support for bi-directional updates at the same time, so you have to sync one direction first and after that happened you can sync the other way around. The more complex your mesh becomes the harder it becomes to resolve conflicts.That's why the documentation recommends staying with a master / client scheme, as this reduces the complexity of resolving conflicts.Also, you have to be aware that Object Synchronization is not built for real-time updates. You are synchronizing at discrete intervals.
go to post Stefan Wittmann · May 17, 2016 This should work in general unless you are switching your template after you set the key with the criteria. Can you provide the code section where you set the key and request the refresh?
go to post Stefan Wittmann · May 17, 2016 When the user refreshes the page, the template defined in the parameter TEMPLATECLASS is loaded. Also, the default keys as specified in your XData block will be used to retrieve your layout and our data (initialLayoutKey and initialDocumentKey). You can use the documentView's callback onload and load another template and set correct keys before the documentView actually starts the setup process. Assuming the following documentView definition: <mojo:documentView id="mainView" onload="zenPage.initPage();" initialDocumentKey="home" initialLayoutKey="home" ongetlayout = "return zenPage.getContent('layout',key,criteria);" ongetdata = "return zenPage.getContent('data',key,criteria);" > <mojo:jQM-1.3.2-PageManager jQueryAnimation="flip" onPageShow="zenPage.onPageShow(layoutkey,documentkey);"> <mojo:jQM-1.3.2-Helper/> <mojo:googleMaps-3-Helper/> <mojo:HTML5Helper/> <mojo:mojoDefaultHelper/> </mojo:jQM-1.3.2-PageManager> </mojo:documentView> You can define the following method initPage: ClientMethod initPage() [ Language = javascript ] { zenPage.gotoArea('the area identifier you want to load') zen('mainView').initialLayoutKey = 'the layout key you want to use'; zen('mainView').initalDocumentKey = 'the data key you want to use'; } Please note that you are first loading your template and then set the initialLayoutKey and initialDocumentKey values, as the documentView hasn't actually done any work yet. It is on you to store any relevant state somewhere locally, e.g. in a cookie or the localStorage. You can retrieve that state in your initPage() method and initialize your page accordingly.
go to post Stefan Wittmann · May 13, 2016 Not sure why this is happening. This is working fine for me: SELECT now() as tnow, max('2016-05-13 08:51:16') as latest, DATEDIFF (s,now(), max('2016-05-13 08:51:16')) as difference FROM Sample.Person tnow latest difference2016-05-13 13:38:08 2016-05-13 08:51:16 -172122016-05-13 13:38:42 2016-05-13 08:51:16 -172462016-05-13 13:38:56 2016-05-13 08:51:16 -17260 I am using the function now().
go to post Stefan Wittmann · May 13, 2016 Let me address your questions. The node.js module files are currently released and shipped with a Caché kit. Our mid-term goal is to make external binding files available via the native package managers of the corresponding environment. For node.js, we are talking about npm, for Java Maven and for .NET NuGet. That being said we are not there yet. I will see what we can do in the short-term.Let's talk about support for specific versions.Support for Node.js 4.2.x has been introduced with Caché 2016.2. If you grab a Windows field test kit you can find the binding file here: <install-dir>\bin\cache421.node.Support for Node.js 5.x.x is already implemented and is currently triaged for a release with Caché 2016.3. But v5 is not a very important release for production use.If you take a look at the long term support plan from the node team (https://github.com/nodejs/LTS/), there is a nice picture at the bottom describing that 4.x will be on long-term support (LTS) until April 2017. v6 becomes LTS from October 2016 until April 2018.The v6 release blog post recommends staying on 4.x if you require stability or move to 6.x if you can upgrade. Avoid 5.x. https://nodejs.org/en/blog/release/v6.0.0/We are currently working on implementing support for 6.x.x
go to post Stefan Wittmann · May 12, 2016 Just get rid of your inner for loop and you have a generic snippet that is helpful for everybody. The description doesn't speak of CSV files at all, though that may be an interesting use case as well. For CSV files, you can use the Record Mapper by the way:http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=...