Instead of your query, I would recommend using query from INFORMATION_SCHEMA.Tables table

SELECT
  TABLE_SCHEMA,
  TABLE_NAME,
  CLASSNAME
FROM INFORMATION_SCHEMA.Tables

In Cache we don't have a table with the number of rows in each table, you have to measure it by yourself for each table. But you can write SQL Function which will count it for you, and you can use this function in the query above.

SELECT count(*) FROM Sample.Person

So, it means that you don't have licence, and you have only one license unit available. You have activate licence to get it worked together.

Dmitry Maslennikov · Jan 31, 2018 go to post

Is it possible to create own image with IRIS based on Ubuntu? Currently available distributive does not support it, and where to get isc-main.

It is good that you prepared the image, but you also set a password there, so, to use this image I have to change a password, and it means that my image will be uselessly bigger with at least about 176Mb in my case. I changed a password by instruction in the documentation.

Dmitry Maslennikov · Jan 31, 2018 go to post

What happens with ZEN in IRIS? %ZEN classes hidden in Class Reference and nothing in the documentation. Is it deprecated, anything else also disappear since Caché/Ensemble?

Dmitry Maslennikov · Jan 31, 2018 go to post

This error happens because you got another error in the request, do not forget to check status.

But anyway. As you need to call https, you should first configure SSL Configuration manually through management portal. You have to fill only Name field, any name on your choice.

Or the same but programmatically.

 ClassMethod GetSSLConfiguration(Server As %String) As %String
{
  new $namespace
  znspace "%SYS"
  do {
    quit:##class(Security.SSLConfigs).Exists(Server)

    set tSC=##class(Security.SSLConfigs).Create(Server)
    $$$ThrowOnError(tSC)
  while 0
  
  quit Server
}

And full working example 

 Class User.Google Extends %RegisteredObject
{

/// Google API key
Parameter KEY = "Put Your Google Maps API Key here";

ClassMethod GetDistanceMatrix(Origins As %String, Destinations As %String, Output Status As %Status) As %DynamicObject
{
  set params("origins")=Origins
  set params("destinations")=Destinations
  set Status=..CallGoogleMapsAPI("/maps/api/distancematrix/json", .params, .data) 
  quit data
}

ClassMethod CallGoogleMapsAPI(Url As %String, ByRef Params, Output Data) As %Status
{
  set Data={}
  set ht=##class(%Net.HttpRequest).%New()
  set ht.Server="maps.googleapis.com"
  set ht.Https=1
  set ht.SSLConfiguration=..GetSSLConfiguration(ht.Server)
  
  set param=""
  for {
    set param=$order(Params(param),1,value)
    quit:param=""
    do ht.SetParam(param, value)
  }
  do ht.SetParam("key", ..#KEY)
  
  set sc=ht.Get(Url)
  if $$$ISERR(sc) quit sc
  
  set Data={}.%FromJSON(ht.HttpResponse.Data)

  quit $$$OK
}

ClassMethod GetSSLConfiguration(Server As %String) As %String
{
  new $namespace
  znspace "%SYS"
  do {
    quit:##class(Security.SSLConfigs).Exists(Server)

    set tSC=##class(Security.SSLConfigs).Create(Server)
    $$$ThrowOnError(tSC)
  while 0
  
  quit Server
}

}

And call in terminal

USER>set data=##class(Google).GetDistanceMatrix("BRISTOL", "LONDON", .sc)

USER>w data.%ToJSON()
{"destination_addresses":["London, UK"],"origin_addresses":["Bristol, UK"],"rows":[{"elements":[{"distance":{"text":"190 km","value":189925},"duration":{"text":"2 hours 23 mins","value":8582},"status":"OK"}]}],"status":"OK"}

My example should work on versions 2016.2 and later, tested on 2017.2

Dmitry Maslennikov · Jan 30, 2018 go to post

It's quite easy to do so. You have to use %Net.HttpRequest class for this. I think it would be better if you try to do it yourself first with knowing how to start. You can find some simple examples in documentation by provided link. And you don't need Ensemble.

Dmitry Maslennikov · Jan 29, 2018 go to post

Right, the problem was in the compilation. In this case, you can't see this property, but you can have access to book from the chapter. Look at this article in the documentation to get more information about SQL access with relationships

Dmitry Maslennikov · Jan 29, 2018 go to post

Could you repeat my commands?

USER>do $system.OBJ.Compile("Test.*","cdk-u")

Compilation started on 01/29/2018 08:42:30 with qualifiers 'cdk-u'
Compiling 2 classes, using 2 worker jobs
Compiling class Test.Book
Compiling class Test.Chapter
Compiling table Test.Book
Compiling table Test.Chapter
Compiling routine Test.Book.1
Compiling routine Test.Chapter.1
Compilation finished successfully in 0.691s.

USER>set b = ##class(Test.Book).%New()

USER>w b.Chapters
7@%Library.RelationshipObject

If you got almost the same, your Insert should work

Dmitry Maslennikov · Jan 29, 2018 go to post

It would be better if you would show the original error message. Something like this

 ​W b.Chapters1.Insert(c1)
^
<PROPERTY DOES NOT EXIST> *Chapters1,Test.Book

I see only that the problem may happen only if you have not compiled sources. 

Dmitry Maslennikov · Jan 28, 2018 go to post

It does not matter where you edit your code, only matter where your Caché server installed. Because all code will be executed only on the server, not on your machine. And if you installed Caché on your mac as well, so, you should use UNIX way for the path.

Dmitry Maslennikov · Jan 27, 2018 go to post

In first you used wrong slashes for windows and macOS. For windows should be "\" and for macOS "/"

For macOS you should use Unix style, where did you find this macOS style with colons? I have never seen such way.

And do not forget, that you can use methods NormalizeFilename and NormalizeDirectory in the class %File. These methods can help you to fix platform differences.

Dmitry Maslennikov · Jan 19, 2018 go to post

In the web world, you don't have access to files on the client's machine, only if a user will give you this particular file. So, if a user manually downloaded your file, changed it. He should interact with your application again, to select and upload it back.

But, there is another way, how to achieve what you want. If I understood you correctly, you need a way to edit MSWord files stored in your application. In this case, instead of the download file, edit and upload back, we have now two ways.

  • WebDAV: it is an extension for HTTP for editing files through the network. You can make a special link which will be opened by MS Word, and after save, it will save this file back to the server, without storing it locally.
  • Office Online: it is almost the same office but which is working online installed on company`s server. It obviously has less functionality than the desktop version, but in most cases, it could be enough. And if online version does not support something in your file it will offer to open it through WebDAV, if you as a developer support it. As an example how it works, you can go to OneDrive, upload some office file, and edit it right there. Almost the same version available to install on your server.

In my previous company, I realized both ways, it was quite tricky but it still works.

Dmitry Maslennikov · Jan 16, 2018 go to post

date in Cache stored in $horolog, which is just number of days from 01/01/1841. So to get the last day of the month you need the date for the first day of next month minus 1.

USER>set y=2018 for m=1:1:12 set d=$zdh(m_"/01/"_y) w !,$zd(d-1, 4)

31/12/2017
31/01/2018
28/02/2018
31/03/2018
30/04/2018
31/05/2018
30/06/2018
31/07/2018
31/08/2018
30/09/2018
31/10/2018
30/11/2018
Dmitry Maslennikov · Jan 16, 2018 go to post

I think the problem is, that REST server is not so clear in error information. And maybe it just expects something else in your data. For example "PaymentRecordTransactionD" expects to get some Date, but you send string.

Some fields may also have max length check.

Dmitry Maslennikov · Jan 15, 2018 go to post

In HTML world, we have two sides. Server and Browser. Upload means that some users far from our server can choose the file on their machines and upload it to the server through the network. The server will get full this file and only filename. You can't get file path because it is useless to you. If you would run this file in a browser and try to choose any your local file then push upload file button. You will get some information about this file, like for me.

Dmitry Maslennikov · Jan 15, 2018 go to post

You want to call method SetHeader, so, you should use DO command instead of SET

Do Request.SetHeader("Source","Civicview")
Dmitry Maslennikov · Jan 12, 2018 go to post

Second parameter test flag in method Post can help you to understand what you send and what do you receive from the destination server.

 If test is 1 then instead of connecting to a remote machine it will just output what it would have send to the web server to the current device, if test is 2 then it will output the response to the current device after the Post.

s sc = httprequest.Post("/api/v0/bwxpert/visiocheck/account", 1)

should show something like

POST /api/v0/bwxpert/visiocheck/account HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; Cache;)
Host: 194.2.225.126
Accept-Encoding: gzip
Authorization: Basic X1N5c3RlbTpTWVM=
Content-Length: 2
Content-Type: application/json
 
{}

And I think in your case error in this line

d httprequest.EntityBody.Write(json)

Write method expects to see string, but I think you put some JSON object here. So, you have to change it.

d httprequest.EntityBody.Write(json.%ToJSON())

Some notice, put full address with server name and port to Post is redundant, while you already use this address for particular properties.

PS: It is not secure to publish IP to your publicly available server. As a moderator I replaced your IP to localhost, and fixed formatting.

Dmitry Maslennikov · Jan 11, 2018 go to post

It is very interesting and quite difficult question. Depends on how modern your application and how you build it.

The modern way to build web-application means that you use some web-frameworks such as Angular, React and so on. In this case, most of you frontend staff in Javascript/Typescript and even such pages can be already on the client side when user open your application. And it means that you can use some guardians to prevent access to some pages. But how to decide which user can have access which not. You have to ask about permissions from your server. And on server-side, you will have REST service which should AccessToken from browser to authorize all requests and return data which available by permissions for this user. REST service can even use or not session because with every request you will get information about the user from Access-Token. 

Dmitry Maslennikov · Jan 10, 2018 go to post

Do not forget that you can name container manually with flag --name

And also look at docker-compose, the very useful tool, you can just define multiple services and call it by name.

Dmitry Maslennikov · Jan 10, 2018 go to post

 I am having only one issue related to getting the SSH daemon to run on when the container starts.

Dou you need it for local use, just to have access to the console or you have to share console access outside?

In case if you need local access, you can use docker exec command to get access inside of your container and run command.

docker exec -it 'container_name' csession 'instance_name' -UUSER

if you have to share access, I think it is also possible to achieve but with the second container and links between.

CACHELIB as you already mentioned read-only by default and will be replaced during update.

But %z classes routines and globals will be stored in CACHESYS

Naming classes and routines with '%z' or '%Z' recommended way, because in this case, such code will be stored in writable database and safe with updating Cache.

Robert, yes, I have the plan to upgrade support to the newest versions, but unfortunately the problem with time, yet.