Eduard Lebedyuk · Oct 6, 2016 go to post

You can call %KillCache method in a cubeclass. It does exactly that. For example:

write ##class(HoleFoods.Cube).%KillCache()
Eduard Lebedyuk · Oct 4, 2016 go to post

If you are on windows you may have access problems while writing into the root of system drive.

 I suggest you:

  • Provide filename pointing to your desktop directory (C:\Users\eduard\Desktop\1.xls for me, for example)
  • Instead of w ##class... save the status and decode it into a more readable form:
set sc = ##class(Utils.XLS).generateFileFromSQL(...)
write $System.Status.GetErrorText(sc)
Eduard Lebedyuk · Oct 4, 2016 go to post

I think compile should be called once after the loop. While in the loop you can build a local array of affected classes and pass it to the compiler after the loop.

Eduard Lebedyuk · Sep 27, 2016 go to post

Yes. You can use cursors for that. In the following example rowlist contains list of affected ids. You can get it all at the end or get individual ids right before or after the update, or even decide on the update based on id/val values:

Class User.NewClass1 Extends %Persistent
{

Property val;

/// do ##class(User.NewClass1).Test()
ClassMethod Test()
{
   do ..%KillExtent()
   
   &sql(INSERT INTO NewClass1 SET val = 0)
   &sql(INSERT INTO NewClass1 SET val = 3)
   
   set rowlist = ""
   &sql(DECLARE NewClass1 CURSOR FOR
        SELECT %ID,val
        INTO :id, :val
        FROM NewClass1)
   
   &sql(OPEN NewClass1)
   for {
       &sql(FETCH NewClass1)
       quit:SQLCODE'=0
       set val2 = val*2
       write "Processing id: ", id,!
       set rowlist = rowlist _ $lb(id)
       &sql(UPDATE NewClass1 SET val = :val2 WHERE CURRENT OF NewClass1)
   }
   &sql(CLOSE NewClass1)
   
   zw rowlist
}
}

It would output in a terminal:

>do ##class(User.NewClass1).Test()
Processing id: 1
Processing id: 2
rowlist=$lb("1","2")

Documentation:

Eduard Lebedyuk · Sep 27, 2016 go to post

Here's an example:

Class User.NewClass1 Extends %Persistent
{

Property streams As list Of %Stream.GlobalCharacter;

ClassMethod Test()
{
    do ..%KillExtent()
    
    set obj = ..%New()
    set stream1 = ##class(%Stream.GlobalCharacter).%New()
    do stream1.WriteLine("Hi")
    set stream2 = ##class(%Stream.GlobalCharacter).%New()
    do stream2.WriteLine(123)
    
    do obj.streams.Insert(stream1)
    do obj.streams.Insert(stream2)
    write $System.Status.GetErrorText(obj.%Save())
    
    kill
    
    set obj = ..%OpenId(1)
    for i=1:1:obj.streams.Count() {
        write "Stream #", i, ": ", obj.streams.GetAt(i).Read($$$MaxCacheInt)
    }
}
}
Eduard Lebedyuk · Sep 23, 2016 go to post

This method links stream object to an existing file:

Method imagefile()
{
  set obj = ##class(Sam.binary).%New()
  read "enter path to image: ",img
  set st = obj.Image.LinkToFile(img)
  write $System.Status.GetErrorText(st)
  set st = obj.%Save()
}
Eduard Lebedyuk · Sep 21, 2016 go to post

1. Define your collection property like this:

Class collect.arraylist Extends %Persistent
{
Property DOB As Array of %Date;
}

Instead of "Array" you can also use "List". Documentation.

Eduard Lebedyuk · Sep 21, 2016 go to post

Great article, however, I strongly disagree on the testing tools choice. Curl is not really the option, as CLI tools are really not the best for json editing. Upon the rest of your testing suggestions, I think there are better alternatives, such as:

  • REST clients: “Advanced REST Client” for Chrome and “REST Client” for Firefox, some are also available as a standalone applications
  • Debugging web proxies: Charles, Filddler etc. for the rare cases where REST clients do not offer enough information
Eduard Lebedyuk · Sep 21, 2016 go to post

For each can be implemented via macros:

#define ForEach(%in,%gn) s gn%in=$na(%gn) s %in="" f { s %in=$o(@gn%in@(%in)) q:%in=""
#define EndFor  }

$$$ForEach(key, "^global")
    Write key,!
$$$EndFor
Eduard Lebedyuk · Sep 20, 2016 go to post

Ensemble settings can be specified for a namespace. So you specify common setting values (or defaults) in production class, and in a SMP you define the instance-specific settings.

Eduard Lebedyuk · Sep 20, 2016 go to post

The problem I see here is, if only one of the data object's properties has changed, how do we know which? Or do we simply overwrite all properties? 

If you use old json classes, you can send only changed properties, for example this json payload would be converted into  Sample.Person object with id=1 and all properties taken from disk except for Name property, which would be set to Bob:

{ _class: "Sample.Person", _id: 1, Name: "Bob" }

With new json you can get dynamic object from json with only modified properties and change persistent object by iterating over defined properties of a modified object.

Eduard Lebedyuk · Sep 20, 2016 go to post

I usually write Abstract REST class for handling all REST technical checks and conversions, and inherit all the other REST brokers from it, so they only contain logic related to calling business logic and outputting the results.

Request -> Abstract REST -> REST -> Business Logic -> Data

For example check this abstract broker for json->obj conversion example.

Eduard Lebedyuk · Sep 20, 2016 go to post

In the underlying SQL write

 SELECT SUBSTRING(Comments, 1, 100) As Comments, ... FROM TABLE

to get first 100 characters from the stream. More info.

Eduard Lebedyuk · Sep 19, 2016 go to post

IF we use cookies, they will be stored in the Session Cookie Path.

Cookie has a property named path. Whed browser determines, does the cookie apply to a current page, it checks if the cookie path is less or equal to current URL.

I'm thinking that this login cookie would be used somehow if the Login Cookie is selected? Or not used? 

It would be used, if checked.

what does happen if the Login Cookie is selected in the web application?

Login Cookies hold information about the most recently logged-in user. If you want to keep your users from having to log in too often, but you want your applications to remain distinct and unconnected, use Login Cookies. For Login Cookies, place each application in a separate session. Then authentication is shared only when an application is entered for the first time. Login Cookies applications do not form a group. So after login, changes in authentication in one application do not affect the other applications. Documentation.

What could we store in a cookie? Can we possibly find out if a second tab has been opened by using a cookie?

You can store text values in cookie. I suggest you read wiki article on them.

Eduard Lebedyuk · Sep 16, 2016 go to post
  • Session Cookie Path - Scope of the session cookie. This determines which URLs the browser uses to send the session cookie back to Caché. If your application name is myapp, it defaults to /myapp/ meaning it only sends the cookie for pages under /myapp/. If you restrict this to only what is required by your application, it prevents this session cookie being used by other CSP applications on this machine, or from being seen by any other application on this web server. On the other hand, browsers and cookies are case sensitive. Setting the session cookie to '/' can prevent license or session problems if, for example, an application name changes from capital to lowercase letters.
  • Login Cookies hold information about the most recently logged-in user. If you want to keep your users from having to log in too often, but you want your applications to remain distinct and unconnected, use Login Cookies.
Eduard Lebedyuk · Sep 16, 2016 go to post

Yes, I use it for web development, when I frequently need to login as different users.

Eduard Lebedyuk · Sep 16, 2016 go to post

As every BP is also a SQL table, you can select active processes which are older than 1 day  with this query:

SELECT ID, %SessionId, %SuperSession, %TimeCreated, DATEDIFF('day',%TimeCreated, CURRENT_TIMESTAMP) AS DaysOld
FROM <business_process_table>
WHERE DATEDIFF('day', %TimeCreated, CURRENT_TIMESTAMP) > 1
      AND %TimeCompleted IS NULL

As BO messages also get logged, you can check Ens.MessageHeader table for message processing time.

Eduard Lebedyuk · Sep 16, 2016 go to post
  1. Can you access Caché studio?
  2. Do you see ApplicationID field in iSkillsetStat (or SQLUSER.iSkillsetStat) table in any database explorer application?