David Hockenbroch · Apr 2, 2024 go to post

The document's original source file name is the name the file had when it was received. %f is a shorthand for using that in the file name. If you wanted them all to be named "myfile" with the timestamp on the end, you'd change the Filename property to myfile_%Q%!+(_a)

David Hockenbroch · Apr 8, 2024 go to post

You can create a text input and write a method that sets the maxRows property based on what the user puts into that input that fires in the input's onchange.

David Hockenbroch · Apr 9, 2024 go to post

You will have to initially set it to something, yes. Once you set the value in the onchange, if you want it to also run the query again, I believe you have to tell it to do that. You could make that part of your method too, though.

David Hockenbroch · Apr 9, 2024 go to post

You can use the if $i to do some stuff within loops too. For example, if you enter the following to commands in a terminal:

set a = 5
for{if $i(a,-1){w a,!}else{quit}}

This will subtract 1 from a and write its value until it reaches 0, then quit the loop. Of course you could just as easily use for a=4:-1:1 {w a,!} to produce the same output a little more nicely, so you don't see that as much.

David Hockenbroch · Apr 16, 2024 go to post

If that's the issue, you could also try the following, and it will post to that location using the parameters you specified with InsertFormData:

set AuthToken = "/B2C_1A_client_credentials_signIn/oauth2/v2.0/token"set tSc = AuthToken.Post()
David Hockenbroch · Apr 19, 2024 go to post

If you instead use:

do attachObj.%Set("contentType","application/pdf")

Does that give you the result you expect?

David Hockenbroch · Apr 19, 2024 go to post

I've never actually used Open Exchange before. I'm going to learn how to do that, and then I will do that.

David Hockenbroch · Apr 24, 2024 go to post

@Cristiano Silva, Rochdi is using Ensemble 2018. Does that version automatically configure IIS if you install it after IIS? I could be wrong, but I thought that automatic configuration was only in more recent versions of IRIS.
 

David Hockenbroch · Apr 29, 2024 go to post

I don't think there is a really good way to do exactly this through JDBC, but you canhandle this using the JDBC URL if you do a little setup beforehand.

First, in the SMP, System Administration, Configuration, System Configuration, Namespaces, click on Create New Namespace. Give it a name - let's say "SAMPLE" and have it copy from your original namespace (probably USER).

Second, go into a terminal, switch to the new namespace and use the command:

w $SYSTEM.SQL.Schema.SetDefault("SAMPLE",.oldval,1)

You should get a 1 confirming that the change was made successfully.

At this point, when you make your JDBC connection, connecting to either namespace will work on the same database, but connecting to the SAMPLE namespace will use the sample schema, and the USER namespace will use the SQLUser schema.

David Hockenbroch · May 14, 2024 go to post

If you download the MongoDB JDBC driver, you can use it to set up an SQL Gateway connection in your system management portal. Once you've done that, you can use that to do your query, or you can link the tables in MongoDB so you can query them more directly.

David Hockenbroch · Jun 3, 2024 go to post

Are you using a CSP or a Zen page? In one of your comments you mentioned Zen.

That's also not the correct syntax for calling a class method. It would be:

#server(##class(MyOrders.WO).retGetWO(wo))#;

That's assuming this is all in the class MyOrders.WO.

David Hockenbroch · Jun 18, 2024 go to post

If you are accessing them through IIS now (i.e. using port 80) then you just need to get the SSL certificate set up in IIS and you'll be able to access those URLs using HTTPS. Keep in mind that HTTPS by default uses port 443, so you may have to make a firewall change accordingly.

You may also want to consider setting up a URL rewrite so that requests that come in as HTTP are redirected to their new HTTPS versions.

David Hockenbroch · Jun 19, 2024 go to post

I'm a big fan of try/catch, but I'm an even bigger fan of "if it ain't broke, don't fix it." This is one of those things that will sound simple, but you'll end up finding out that there are multiple different ztraps at different stack levels and an occasional etrap here and there, and then you end up rewriting way more code than you thought.

David Hockenbroch · Jul 9, 2024 go to post

These are stored as a relationship to %Dictionary.PropertyDefinition, so you can access them like this:

select * from %dictionary.propertydefinition where parent = 'Your class name here'

David Hockenbroch · Jul 11, 2024 go to post

We have an ERP system that runs on hundreds of ZEN pages, and we still love it. We just recognize that at some point, we're probably going to have to do some things to maintain it ourselves. I'd love to see it come back if that was an option.

David Hockenbroch · Jul 11, 2024 go to post

As Robert said, the data and indexes are both stored in global trees. The structure of the trees for indices and the trees for general data storage are different, though, and that's where the efficiency comes from.

The data will be stored in the ^EMPLOYEED global. You'll see a bunch of data in that global like:

^EMPLOYEED(1) = $lb("001","ABC",20)

^EMPLOYEED(2) = $ib("002","AAA",21)

Those are lists of every property of that class, indexed by the ID column.

The indexes, on the other hand, will look more like:

^EMPLOYEEI("IDX_EMPID","001",1)

^EMPLOYEEI("IDX_EMPID","002",2)

This allows for a much more efficient search to find the ID of the records that match your search criteria, similar to if you opened a terminal and put in:

write$ORDER(^EMPLOYEEI("IDX_EMPID","001",""))

Which would give you row 1, then it could more easily look up row 1 in the original without having to go through every record in the table in order searching for it.

In your system management portal, you can run your query and check the query plan, then run it again telling it to ignore indexes like this:

SELECT * FROM %IGNOREINDEX * EMPLOYEE WHERE EMPID="005"

This will tell it to ignore all indexes on the table. You can check that query plan and compare it to the original to see the differences in how the query finds data and how well it performs.

David Hockenbroch · Jul 11, 2024 go to post

Rich, I understand all of that. Why, though, do answers to those of us who like Zen always including language like:

". . . could never hope to reach feature parity with more broadly accepted frame works like Angular and the others listed above . . ."

". . . that could never achieve feature parity with those mass market offerings. . ."

I know I'm newer than a lot of people here, but I have yet to see anyone asking about Zen asking for feature parity with any of those other front ends. Meanwhile, the part that actually matters gets discounted:

". . . could only beat them in providing faster, more efficient access to the data layer."

There doesn't seem to be a very good understanding of why some of us are still as attached to Zen as we are (other than momentum). That fast, efficient access to the data layer is extremely important, and we like being able to handle the front end and back end together, seemlessly writing the code it takes to do whatever we need to do on both at once. Zen also allowed us to do all of this using the same skill set that we used for everything else in our projects instead of having to learn two entirely different things for the front and back.

Absolutely none of this has anything to do with a desire for something Zen-like with all the bells and whistles of something like Angular.

David Hockenbroch · Jul 11, 2024 go to post

And it's not only on the development end. It's also when you're educating and training. With Zen, it was all about ObjectScript and defining a class, plus a little javascript here and there. You didn't have to devote extra training and learning to the second system.

David Hockenbroch · Jul 17, 2024 go to post

You haven't added your hgroup to your page anywhere. You'll need to figure out what its parent element should be and use the %AddChild method of that Zen component to add the hgroup somewhere, just like you added your maxData to the hgroup.

David Hockenbroch · Jul 24, 2024 go to post

There isn't a consistent mapping for everything, but if you're in the %SYS namespace, you can query the tables %SYS.Task and %SYS_Task.History to find these specific things. Some of the security related things are in the Security scheme, like Security.Roles and Security.Users.

When you're in the SQL part of the system management portal, if you check the box to show system tables on the left, you can see a lot of these then under tables, and you'll be able to guess what a lot of them are just based on the names.

David Hockenbroch · Jul 25, 2024 go to post

Also note that if you do it this way, your tag for the custom component will be RC:imageclickbutton with the XML namespace and a colon on the front.

David Hockenbroch · Jul 31, 2024 go to post

A task expires if it can't run when it was scheduled. This could be because your Ensemble instance was down when the task started, or it could be because a previous instance of the task was still running when it was supposed to start again. For example, if you have a task set to run every minute but it takes the task 90 seconds to complete, then when it run at 12:00, it will be supposed to start again at 12:01, but since it will still be running, the 12:01 task will expire and the task will run again at 12:02.

David Hockenbroch · Aug 1, 2024 go to post

No, it doesn't run as soon as the previous task ends. It runs at the next scheduled time. So in my example above, if your task runs at 12:00:00 and doesn't finish until 12:01:30, the next scheduled time is 12:02:00, so that's when it'll run next. I'm not sure how far back in versions this goes, but you might be able to change that behavior so it's more like what you're expecting.

David Hockenbroch · Aug 1, 2024 go to post

Glad you got an answer to your main question. To answer your other question about how to check a status, the Execute and Prepare methods of the %ResultSet class return a %Status. Where you have do Rs.Prepare(SQL) and do Rs.Execute(), you could use:

set sc = Rs.Prepare(SQL)
if$$$ISERR(sc) {$$$ThrowStatus(sc)}
set sc = Rs.Execute()
if$$$ISERR(sc) {$$$ThrowStatus(sc)}

Then if there was an error doing either of those things, it would get passed off to your catch block. In your case, there would've been an error indicating your permissions issue.

David Hockenbroch · Aug 23, 2024 go to post

Are you trying to get all of the classes that a class extends? You can do that like this:

set classname = $CLASSNAME($THIS)
	&sql(select primarysuper into :super from %dictionary.compiledclass whereid=:classname)
	w super,!

If you do that, super is a ~ separated list of the class and everything that it inherits from, which is probably actually more information than you need.

David Hockenbroch · Aug 23, 2024 go to post

If you are looking for the class name where a currently-running method originates, you could also try:

set method = $CLASSNAME($THIS)_"||"_$P($Stack($stack,"PLACE"),"+",1)
	&sql(select Origin into :origin from %Dictionary.CompiledMethod where ID1 = :method)
	w origin,!
David Hockenbroch · Aug 28, 2024 go to post

Just FYI, CSP sessions are instances of %CSP.Session. You could do ##class(%CSP.Session).%OpenId("wuuZ2Gwgxw") to get the session and use some of the properties and functions there to get more information on what's going on. And since they extend %Persistent, you can also use %DeleteId (at your own risk, of course).

David Hockenbroch · Sep 30, 2024 go to post

When you're using a REST API, you're sending an HTTP or HTTPS response, so all of the typical HTTP headers apply. This includes the content type and the disposition header. The content type, as Rodolfo mentioned, can be set using %response.ContentType. Others can be set using %response.SetHeader.