Pesquisar

Artigo
· Jul. 29 13min de leitura

Taking up Collections in IRIS

Imagine you’re walking down the street on a nice summer’s day, and someone walks up to you and says “Hey, you work at InterSystems, right? I’ve been hearing more and more about InterSystems IRIS lately. I know IRIS has its own programing language called ObjectBook? or InstaScript? OK, I admit it, I know it’s called ObjectScript! I know IRIS also supports Python. I’m a Python developer, so that sounds great to me. But I’m also interested in ObjectScript. For example, Python and other languages support collections. Does ObjectScript support collections?”

You’d answer “Of course!”

And then your new friend might get excited and start firing off more questions:

  • How many kinds of collections does ObjectScript support?
  • Can ObjectScript use Python collections?
  • Can Python use ObjectScript collections?
  • Which collection is best?

How would you answer? Well, you don’t have to worry about answering. All you’d have to do is send your new friend the URL of this long page.

Let’s say you have 20, 500, or 10000 items that you want to manipulate programmatically. You may want to sort them, iterate through them, perform mathematical operations on them, or do something else with them. Using a collection is an obvious choice. Let's explore the IRIS collection collection.

There are 12 kinds of collections available in IRIS. Yes, 12. Why 12? Because new collection or collection-like features have been added over time. In the beginning, there were 2 kinds of collections. Then $lists were added. Then collection classes were added. Then dynamic objects and arrays were added for handling JSON. Then the ability to use Python collections was added. Finally vectors were added. In ObjectScript, it's possible to use all 12. In Python, as of v2024.3, you can use 9 (sparse arrays, $list, and $vector are not available).

I've divided the collections into 3 groups. There are simple code examples for each collection (Python on the left, ObjectScript on the right)

  • 7 collections that use integer keys.
  • 4 collections that allow any value to be the key; these are key-value collections.
  • The Python set collection only, which has no keys.

At the bottom, after the examples of the collections, there are a few more fun facts about collections as well as a poll. Plus, there might be a treat or joke down there at the end.

The one question this article does not answer is: "Which collection performs best, especially when the number of items in the collection is large?" I intend to write some code which will time things like computations across values ($vector should win that one!), creation, searching for values, accessing values, and anything else I come up with. And I'll add that code and the results to this posting,. Maybe one of you will finish writing that code and add it to this posting before I do.

Collections with Integer Keys

1. Delimited strings

You might not think of this as a collection, but it can easily be used as one. This is a collection of pieces. The keys are the 1-based (for ObjectScript) or 0-based (for Python) positions of the pieces in the string.

# NOTE: since access to pieces uses split(),
#       which returns a Python list,
#       you'd probably use a Python list instead
#
# create
>>> c = "10,20,30,20,10"
# iterate and access
>>> i = 0
>>> for val in c.split(","):
...    print(i, "–", val)
...    i += 1
010
120
230
320
410
# return the key for a particular value (30)
>>> print(c.split(",").index('30'))
2
// create
USER>set c = "10,20,30,20,10"
// iterate and access
USER>for i = 1:1:$length(c, ",") { write !, i, " – ", $piece(c, ",", i) }
110
220
330
420
510
// returning the key for a particular value (30)
// is awkward; use a different collection if this is required

 

2.    $list

This is a $list collection of values. The keys are the 1-based positions of the values in the $list. $list is not available in Python. However, you can convert a $list into a Python list.

# assuming "lb" is a $list returned by a call
# to an ObjectScript method
# $listbuild(10,20,30,20,10)
# convert it to a Python list
>>> c = iris._SYS.Python.ToList(lb)
>>> print(c)
[10, 20, 30, 20, 10]
// create
USER>set c = $listbuild(10,20,30,20,10)
// iterate and access
USER>set ptr = 0, i = 0
USER>while $listnext(c, ptr, val) { set i = i + 1 write !, i, " – ", val }
110
220
330
420
510
// return the key for a particular value (30)
USER>write $listfind(c, 30)
3

 

3.    %DynamicArray object (JSON array)

This is a JSON array collection of values. The keys are the 0-based positions of the values. This is like a Python list. Searching for a value and returning its key requires iterating (not shown below). 

# create
>>> c = iris._Library.DynamicArray._New()
>>> _ = c.Set(0, 10)
>>> _ = c.Set(1, 20)
>>> _ = c.Set(2, 30)
>>> _ = c.Set(3, 20)
>>> _ = c.Set(4, 10)
# iterate and access
>>> for i in range(c._Size()):
...    print(i, "-", c._Get(i))
010
120
230
320
410
// create
USER>set c = [10,20,30,20,10]
// iterate and access
USER>for i = 0:1:(c.%Size() - 1) { write !, i, " – ", c.%Get(i) }
010
120
230
320
410

 

4.    %ListOfDataTypes object

This is a list collection of values. The keys are the 1-based positions of the values. Note: when using this collection as a property in a class (Property C as list of %String), the class definition is %Collection.ListOfDT instead (all functionality is the same).

# create
>>> c = iris._Library.ListOfDataTypes._New()
>>> _ = c.Insert(10)
>>> _ = c.Insert(20)
>>> _ = c.Insert(30)
>>> _ = c.Insert(20)
>>> _ = c.Insert(10)
# iterate and access
>>> for i in range(c.Size()):
...    print((i+1), "-", c.GetAt(i+1))
110
220
330
420
510
# return the key for a particular value (30)
>>> print(c.Find(30))
3
// create
USER>set c = ##class(%ListOfDataTypes).%New()
USER>do c.Insert(10), c.Insert(20), c.Insert(30)
USER>do c.Insert(20), c.Insert(10)
// iterate and access
USER>for i = 1:1:c.Size { write !, i, " – ", c.GetAt(i) }
110
220
330
420
510
// return the key for a particular value (30)
USER>write c.Find(30)
3

 

5.    $vector

This is a vector of values of a specific declared type (integers in the example below). The keys are the 1-based positions of the values in the vector. $vector is not available in Python.

// create
USER>set $vector(c,1,"int") = 10
USER>set $vector(c,2,"int") = 20
USER>set $vector(c,3,"int") = 30
USER>set $vector(c,4,"int") = 20
USER>set $vector(c,5,"int") = 10
// iterate and access
USER>for i = 1:1:$vectorop("count",c) { write !, i, " – ", $vector(c, i) }
110
220
330
420
510
// return the key for a particular value (30)
// by creating a bitstring for matching values
// and finding the 1 bit
USER>set b = $vectorop("=", c, 30)
USER>write $bitfind(b, 1)
3

 

6.    Python list (Used in ObjectScript via Builtins())

 This is a Python list of values used within ObjectScript. The keys are the 0-based positions of the values. Since ObjectScript doesn't recognize the Python [ ] syntax, you must call the __getitem__() method.

# create
c = [10, 20, 30, 20, 10]
# iterate and access
>>> for i in range(len(c)):
...    print(i, "-", c[i])
010
120
230
320
410
# return the key for a particular value (30)
>>> print(c.index(30))
2
// create
USER>set b = $system.Python.Builtins()
USER>set c = b.list()
USER>do c.append(10), c.append(20), c.append(30)
USER>do c.append(20), c.append(10)
// display
USER>zwrite c
c=10@%SYS.Python  ; [10, 20, 30, 20, 10]  ; <OREF>
// iterate and access
USER>for i = 0:1:(b.len(c) - 1) { write !, i, " – ", c."__getitem__"(i) }
010
120
230
320
410
// return the key for a particular value (30)
write c.index(30)
2

 

7.    Python tuple (Used in ObjectScript via Builtins())

This is a Python tuple of values used within ObjectScript. The keys are the 0-based positions of the values. Since ObjectScript doesn't recognize the Python [ ] syntax, you must call the __getitem__() method. Once created, a tuple is immutable. 

# create
t = (10, 20, 30, 20, 10)
# iterate and access
>>> for i in range(len(t)):
...    print(i, "-", t[i])
010
120
230
320
410
# return the key for a particular value (30)
>>> print(t.index(30))
2
// first, create a list and add values
USER>set b = $system.Python.Builtins()
USER>set c = b.list()
USER>do c.append(10), c.append(20), c.append(30)
USER>do c.append(20), c.append(10)
// convert it to a tuple
USER>set t = b.tuple(c)
// display
USER>zwrite t
t=7@%SYS.Python  ; (10, 20, 30, 20, 10)  ; <OREF>
// iterate and access
USER>for i = 0:1:(b.len(t) - 1) { write !, i, " – ", t."__getitem__"(i) }
010
120
230
320
410
// return the key for a particular value (30)
write t.index(30)
2

 

Key-Value Collections

Note: The examples in this section all use a mixture of integer, floating point, and string keys. This mixture would typically not occur in real code; it's used to demonstrate how the keys are treated by each kind of collection.

1.    Sparse array

This is a subscripted variable. Any string or numeric value is allowed as a subscript except for the empty string (""). The keys are the subscripts. The array is automatically sorted by the subscripts (numerically and alphabetically). Searching for a value requires iterating (not shown below). Sparse arrays are not available in Python. However, you can convert a Python dict into a sparse array reference, in order to pass it as an argument to an ObjectScript method.

# create
>>> c = {-1: 10, 2: 20, 8.5: 30, 'george': 20, 'thomas': 10}
# convert it to a sparse array
>>> sa = iris.arrayref(c)
>>> print(sa.value)
{'-1': 10, '2': 20, '8.5': 30, 'george': 20, 'thomas': 10}
# "sa" could be passed to an ObjectScript method
# that accepts a sparse array as an argument
// create (adding with keys intentionally out of order to show auto sorting)
USER>set c(-1) = 10, c(8.5) = 30, c(2) = 20
USER>set c("thomas") = 10, c("george") = 20
// iterate and access
USER>set key = ""
USER>while 1 {set key = $order(c(key)) quit:(key = "")  write !, key, " – ", c(key) }
-110
220
8.530
george – 20
thomas – 10

 

2.    %DynamicObject object (JSON object)

This is a JSON object collection of keys and values. This is like a Python dict. Searching for a value requires iterating (not shown below).

# create
>>> c = iris._Library.DynamicObject._New()
>>> _ = c._Set(-1, 10)
>>> _ = c._Set(2, 20)
>>> _ = c._Set(8.5, 30)
>>> _ = c._Set("george", 20)
>>> _ = c._Set("thomas", 10)
# iterate and access
>>> key = iris.ref()
>>> val = iris.ref()
>>> i = c._GetIterator()
>>> while i._GetNext(key, val):
...    print(key.value, "-", val.value)
-110
220
8.530
george – 20
thomas – 10
// create
USER>set c = {"-1":10, "2":20, "8.5":30, "george":20, "thomas":10}
// iterate and access
USER>set i = c.%GetIterator()
// call %GetNext() passing key and val BY REFERENCE (preceded with period)
USER>while i.%GetNext(.key, .val) { write !, key, " – ", val }
-110
220
8.530
george – 20
thomas – 10

 

3.    %ArrayOfDataTypes object

This is an array collection of keys and values. Any string or numeric value is allowed as a key except for the empty string (""). The collection is automatically sorted on the keys (numerically and alphabetically). Note: when using this collection as a property in a class (Property C as array of %String), the class definition is %Collection.ArrayOfDT instead (all functionality is the same).

# create (adding with keys intentionally out of order
# to show auto sorting)
>>> c = iris._Library.ArrayOfDataTypes._New()
>>> _ = c.SetAt(10, -1)
>>> _ = c.SetAt(30, 8.5)
>>> _ = c.SetAt(20, 2)
>>> _ = c.SetAt(10, "thomas")
>>> _ = c.SetAt(20, "george")
# iterate and access
>>> key = iris.ref("")
>>> while True:
...    val = c.GetNext(key)
...    if (key.value == ""):
...        break
...    print(key.value, "-", val)
-110
220
8.530
george – 20
thomas – 10
# return the key for a particular value (30)
>>> print(c.Find(30))
8.5
// create (adding with keys intentionally out of order to show auto sorting)
USER>set c = ##class(%ArrayOfDataTypes).%New()
USER>do c.SetAt(10, -1), c.SetAt(30, 8.5), c.SetAt(20, 2)
USER>do c.SetAt(10, "thomas"), c.SetAt(20, "george")
// iterate and access
USER>set key = ""
// call GetNext() passing key BY REFERENCE (preceded with period)
USER>while 1 { set val = c.GetNext(.key) quit:(key = "")  write !, key, " - ", val}
-110
220
8.530
george – 20
thomas – 10
// return the key for a particular value (30)
USER>write c.Find(30)
8.5

 

4.    Python dict (Used in ObjectScript via Builtins())

This is a Python dict of values used within ObjectScript. Any string or numeric value is allowed as a key. It's included here for completeness, as it is technically possible to use it within ObjectScript. But it might seem strange to do so, given the lack of the "for keys,values in…" syntax in ObjectScript. Searching for a value requires iterating (not shown below).

# create
>>> c = {"-1":10, "2":20, "8.5":30, "george":20, "thomas":10}
# iterate and access
>>> for key, val in c.items():
...    print(key, "-", val)
-110
220
8.530
george – 20
thomas – 10
// create
USER>set b = $system.Python.Builtins()
USER>set c = b.dict()
USER>do c.setdefault(-1, 10), c.setdefault(2, 20), c.setdefault(8.5, 30)
USER>do c.setdefault("george", 20), c.setdefault("thomas", 10)
// display
USER>zwrite c
c=15@%SYS.Python  ; {-1: 10, 2: 20, 8.5: 30, 'george': 20, 'thomas': 10}  ; <OREF>
// iterate (using try/catch) and access
USER>set iter = b.iter(c)
USER>try { while 1 { set key = b.next(iter) write !, key, " – ", c.get(key)} } catch ex {}
-110
220
8.530
george – 20
thomas – 10

 

Python Set Collection

1.    Python set (Used in ObjectScript via Builtins())

This is a Python set of values used within ObjectScript. A set is non-ordered, non-indexed, and doesn't allow duplicate values. Set operations such as union and intersection are supported. 

# create
>>> c1 = {10, 20, 30, 20, 10}
>>> c2 = {25, 30, 20, 75}
# display (no duplicate values allowed)
>>> print(c1)
{10, 20, 30}
>>> print(c2)
{25, 75, 20, 30}
# create union and intersection of the sets
>>> union = c1.union(c2)
>>> inter = c1.intersection(c2)
# display
>>> print(union)
{20, 25, 10, 75, 30}
>>> print(inter)
{20, 30}
// create
USER>set b = $system.Python.Builtins()
USER>set c1 = b.set(), c2 = b.set()
USER>do c1.add(10), c1.add(20), c1.add(30), c1.add(20), c1.add(10)
USER>do c2.add(25), c2.add(30), c2.add(20), c2.add(75)
// display (no duplicate values allowed)
USER>zwrite c1, c2
c1=4@%SYS.Python  ; {10, 20, 30}  ; <OREF>
c2=8@%SYS.Python  ; {25, 75, 20, 30}  ; <OREF>
// create the union and intersection of the sets
USER>set union = c1.union(c2)
USER>set inter = c1.intersection(c2)
// display
USER>zwrite union
union=11@%SYS.Python  ; {20, 25, 10, 75, 30}  ; <OREF>
USER>zwrite int
int=9@%SYS.Python  ; {20, 30}  ; <OREF>

 

Fun Facts

  • All 12 collections can be properties of IRIS objects. However, the 4 Python collections and sparse arrays cannot be saved as part of an IRIS persistent object.
  • The %Collection.ArrayOfDT collection is used for an array property of an object. If the object is persistent, when saving the object, the collection keys and values are automatically normalized into a child table.
  • The %Collection.ListOfDT collection is used for a list property of an object. If the object is persistent, when saving the object, the collection keys and values can optionally be automatically normalized into a child table.
  • 11 of the collections allow different types of values in the same collection, such as strings, integers, and doubles. The sole exception: the values of a $vector must all be the same declared type.
  • 7 of the collections allow object references as values. Delimited strings, $list, $vector, %ListOfDataTypes, and %ArrayOfDataTypes do not allow object references. For the latter two, %ListOfObjects and %ArrayOfObjects are alternatives that allow object references as values, along with the %Collection.ListOfObj and %Collection.ArrayOfObj classes for list or array properties of objects.
  • In IRIS, globals are sparse arrays on disk. Although sparse arrays are not available in Python, using iris.gref() it is possible to manipulate globals in Python.

I hope you found this posting useful. As a treat for reading this far, here's a photo from part of my childhood rock collection, purchased for $2.25 in the early 1970s. Item #11 is uranium! The helpful description states "It is a source of radio active material, used in construction of atomic bombs." Unfortunately, there are no safe handling warnings included. I'll put it back in the attic now.

 

Discussão (0)1
Entre ou crie uma conta para continuar
Anúncio
· Jul. 29

[Vídeo Demo] Care Compass – Assistente de IA RAG com tecnologia InterSystems IRIS para gerentes de cuidados

#InterSystems Demo Games entry


⏯️ Care Compass – Assistente de IA RAG com tecnologia InterSystems IRIS para gerentes de cuidados

O Care Compass é um protótipo de assistente de IA que auxilia assistentes sociais a priorizar clientes por meio da análise de dados clínicos e sociais. Utilizando a Geração Aumentada de Recuperação (RAG) e modelos de linguagem de grande porte, ele gera resumos narrativos de risco, calcula pontuações de risco dinâmicas e recomenda os próximos passos. O objetivo é reduzir as visitas evitáveis ao pronto-socorro e apoiar intervenções precoces e informadas.

Apresentadores:
🗣 @Brad Nissenbaum, Sales Engineer, InterSystems
🗣 @Andrew Wardly, Sales Engineer, InterSystems
🗣 @Fan Ji, Solution Developer, InterSystems
🗣 @Lynn Wu, Sales Engineer, InterSystems

🔗  Recursos Relacionados:

👉 Gostou deste Demo? Apoie a equipe votando nela nos Jogos de Demonstração

Discussão (0)1
Entre ou crie uma conta para continuar
Discussão (3)3
Entre ou crie uma conta para continuar
InterSystems Oficial
· Jul. 29

官方公告:InterSystems IRIS 2025.2 引入 IRISSECURITY

InterSystems IRIS 2025.2 引入了 IRISSECURITY 数据库,用于存储安全数据。 与之前用于存储安全数据的数据库 IRISSYS 不同,IRISSECURITY 支持加密,可以保护静态敏感数据。 在今后的版本中,IRISSECURITY 将可实现镜像。

此版本还引入了可以执行常规安全管理任务的 %SecurityAdministrator 角色。

本文中介绍的更改将影响持续交付 (CD) 和扩展维护 (EM) 版本通道。 也就是说,从版本 2025.2(CD,于 2025 年 7 月 23 日发布)和 2026.1 (EM) 开始,InterSystems IRIS 将包含 IRISSECURITY 数据库,并且在升级时,所有安全数据会自动从 IRISSYS 迁移到 IRISSECURITY。

虽然 InterSystems IRIS 2025.2 预计于 2025 年 7 月 23 日发布,但我们暂缓了 InterSystems IRIS for Health 和 HealthShare Health Connect 2025.2 的公开发布,原因是我们正在着手完成针对已知镜像问题的修复计划,该问题会影响 OAuth 配置数据。

升级须知

IRISSECURITY 对用户与安全数据的交互方式做出了多处可能导致功能中断的更改:

  • 用户无法再直接访问安全global,而必须使用各种安全类提供的 API。
  • OAuth2  Global无法再映射到其他数据库。
  • 用户无法再随意查询安全表,即使在 SQL 安全已禁用的情况下也是如此。
  • 系统数据库现在使用的预定义资源无法更改。 在 Unix 上,如果为之前版本的系统数据库创建并指定了新资源,在升级时,该新资源将被预定义资源替代(但如果有任何角色引用了非默认资源,则必须手动将其更改为使用默认资源,以保持数据库访问权限)。 在 Windows 上,必须将资源更改回默认资源。 如果您尝试在 Windows 上升级,而数据库具有非默认资源,升级将停止(实例不会修改),并会显示错误消息“Database must have a resource label of…”

以下各部分将详细介绍这些更改,以及在您依赖原始行为的情况下应采取的替代措施,但总体而言,在您进行升级之前,应当验证并测试您的应用程序和宏:

  • 使用提供的安全 API 管理安全功能(而非直接访问global)。
  • 拥有使用这些 API 所必需的权限(%DB_IRISSYS:RAdmin_Secure:U)。

Global 访问

之前,当安全global存储在 IRISSYS 数据库中时,用户可以通过以下权限访问安全数据:

  • %DB_IRISSYS:R:直接读取和通过安全 API 读取安全global。
  • %DB_IRISSYS:RW:读取和写入安全global。
  • %DB_IRISSYS:RWAdmin_Secure:U:通过安全 API 管理安全功能。

在 InterSystems IRIS 2025.2 中:

  • 用户无法再直接访问安全global。
  • %DB_IRISSYS:R%Admin_Secure:U 这两个权限是访问安全数据(通过提供的安全 API)以及通过各种安全类管理安全功能所需的最低权限。
  • 对于常规安全管理,您可以使用新的 %SecurityAdministrator 角色。
  • 已移除对安全数据的只读访问权限(之前可以通过 %DB_IRISSYS:R 实现)。

Global 存储位置

在 InterSystems IRIS 2025.2 中,以下安全global已从 IRISSYS 迁移到 IRISSECURITY 中的 ^SECURITY

  • ^SYS("SECURITY")
  • ^OAuth2.*
  • ^PKI.*
  • ^SYS.TokenAuthD

下表列出了已迁移的最关键的global及其安全类、原存储位置和新存储位置:

安全类 原存储位置 (IRISSYS) 新存储位置 (IRISSECURITY)
不适用 ^SYS("Security","Version") ^SECURITY("Version")
Security.Applications ^SYS("Security","ApplicationsD") ^SECURITY("ApplicationsD")
Security.DocDBs ^SYS("Security","DocDBsD") ^SECURITY("DocDBsD")
Security.Events ^SYS("Security","EventsD") ^SECURITY("EventsD")
Security.LDAPConfigs ^SYS("Security","LDAPConfigsD") ^SECURITY("LDAPConfigsD")
Security.KMIPServers ^SYS("Security","KMIPServerD") ^SECURITY("KMIPServerD")
Security.Resources ^SYS("Security","ResourcesD") ^SECURITY("ResourcesD")
Security.Roles ^SYS("Security","RolesD") ^SECURITY("RolesD")
Security.Services ^SYS("Security","ServicesD") ^SECURITY("ServicesD")
Security.SSLConfigs ^SYS("Security","SSLConfigsD") ^SECURITY("SSLConfigsD")
Security.System ^SYS("Security","SystemD") ^SECURITY("SystemD")
Security.Users ^SYS("Security","UsersD") ^SECURITY("UsersD")
%SYS.PhoneProviders ^SYS("Security","PhoneProvidersD") ^SECURITY("PhoneProvidersD ")
%SYS.X509Credentials ^SYS("Security","X509CredentialsD") ^SECURITY("X509CredentialsD ")
%SYS.OpenAIM.IdentityServices ^SYS("Security","OpenAIMIdentityServersD") ^SECURITY("OpenAIMIdentityServersD")
OAuth2.AccessToken ^OAuth2. AccessTokenD ^SECURITY("OAuth2.AccessToken ")
OAuth2.Client ^OAuth2.ClientD ^SECURITY("OAuth2.Client")
OAuth2.ServerDefinition ^OAuth2.ServerDefinitionD ^SECURITY("OAuth2.ServerDefinitionD")
OAuth2.Client.MetaData ^OAuth2.Client.MetaDataD ^SECURITY("OAuth2.Client.MetaDataD")
OAuth2.Server.AccessToken ^OAuth2.Server.AccessTokenD ^SECURITY("OAuth2.Server.AccessTokenD")
OAuth2.Server.Client ^OAuth2.Server.ClientD ^SECURITY("OAuth2.Server.ClientD")
OAuth2.Server.Configuration ^OAuth2.Server.ConfigurationD ^SECURITY("OAuth2.Server.ConfigurationD")
OAuth2.Server.JWTid ^OAuth2.Server.JWTidD ^SECURITY("OAuth2.Server.JWTidD")
OAuth2.Server.Metadata ^OAuth2.Server.MetadataD ^SECURITY("OAuth2.Server.MetadataD")
PKI.CAClient ^PKI.CAClientD ^SECURITY("PKI.CAClient")
PKI.CAServer ^PKI.CAServerD ^SECURITY("PKI.CAServer")
PKI.Certificate ^PKI.CertificateD ^SECURITY("PKI.Certificate")
%SYS.TokenAuth ^SYS.TokenAuthD ^SECURITY("TokenAuthD")

OAuth2 Global 映射

之前,可以将 OAuth2 Global映射到其他数据库,从而可以镜像 OAuth2 配置。

在 InterSystems IRIS 2025.2 中,无法再映射 OAuth2 global,且不能镜像 IRISSECURITY。 如果您过去依赖此行为进行镜像,可以使用以下任何替代方法:

  • 手动对主节点和故障转移节点进行更改。
  • 从主节点导出设置,然后将其导入到故障转移节点(需要 % ALL 权限)。

导出 OAuth2 配置数据:

set items = $name(^|"^^:ds:IRISSECURITY"|SECURITY("OAuth2"))_".gbl"
set filename = "/home/oauth2data.gbl"
do $SYSTEM.OBJ.Export(items,filename)

导入 OAuth2 配置数据:

do $SYSTEM.OBJ.Import(filename)

SQL 安全

之前,SQL 安全由 CPF 参数 DBMSSecurity 控制。 当 DBMSSecurity 禁用时,拥有 SQL 权限的用户可以随意查询数据库中的所有表。

在 InterSystems IRIS 2025.2 中:

  • DBMSSecurity CPF 参数已被替换为系统范围的 SQL 安全属性。 可以通过多种方式对此进行设置:
    • 管理门户:System Administration > Security > System Security > System-wide Security Parameters > Enable SQL security(系统管理 > 安全 > 系统安全 > 系统范围的安全参数 > 启用 SQL 安全)
    • SetOption##class(%SYSTEM.SQL.Util).SetOption("SQLSecurity", "1")
    • Security.System.Modify: ##Class(Security.System).Modify(,.properties),其中,properties 为 properties("SQLSecurity")=1
  • 安全表(security table)现只能通过 Detail 和 List API 进行查询,即使在 SQL 安全处于禁用状态的情况下,也需要同时具有 %DB_IRISSYS:R%Admin_Secure:U 权限才能进行查询。

例如,要获取角色列表,无法再直接查询 Security.Roles 表, 而应使用 Security.Roles_List() 查询:

SELECT Name, Description FROM Security.Roles_List()

加密 IRISSECURITY

要加密 IRISSECURITY,请按以下步骤操作:

  1. 创建新的加密密钥。 转到 System Administration > Encryption > Create New Encryption Key File(系统管理 > 加密 > 创建新的加密密钥文件),并指定以下设置:
    • Key File(密钥文件)– 加密密钥的名称。
    • Administrator Name(管理员名称)– 管理员的名称。
    • Password(密码)– 密钥文件的密码。
  2. 激活加密密钥。 转到 System Administration > Encryption > Database Encryption(系统管理 > 加密 > 数据库加密),并选择 Activate Key(激活密钥),指定第 1 步中的 Key File(密钥文件)、Administrator Name(管理员名称)和 Password(密码)。
  3. 转到 System Administration > Encryption > Database Encryption(系统管理 > 加密 > 数据库加密),并选择 Configure Startup Settings(配置启动设置)。
  4. Key Activation at Startup(启动时的密钥激活)下拉菜单中选择一种密钥激活方法。 InterSystems 强烈建议选择 Interactive(交互式)密钥激活。
  5. Encrypt IRISSECURITY Database(加密 IRISSECURITY 数据库)下拉列表中,选择 Yes(是)。
  6. 重新启动系统,以加密 IRISSECURITY。

百分比类(那些类名以%开头的类,可以在任何命名空间访问)访问规则

之前版本的 InterSystems IRIS 中,管理 Web 应用程序对附加百分比类的访问权限的过程涉及到对安全global进行写入操作。 在 InterSystems IRIS 2025.2 中,可以通过管理门户或 ^SECURITY 例程完成此过程。

管理门户(Management Portal)

通过管理门户创建百分比类访问规则:

  1. 转到 System Administration > Security > Web Applications(系统管理 > 安全 > Web 应用程序)。
  2. 选择您的 Web 应用程序。
  3. Percent Class Access(百分比类访问)选项卡中设置以下选项:
    • Type(类型):控制该规则是仅适用于应用程序对指定百分比类的访问 (AllowClass),还是适用于包含指定前缀的所有类 (AllowPrefix)。
    • Class name(类名称):允许应用程序访问的百分比类或前缀。
    • Allow access(允许访问):是否允许应用程序访问指定的百分比类或软件包。
    • Add this same access to ALL applications(为所有应用程序添加相同的访问权限):是否为所有应用程序应用此规则。

^SECURITY

通过 ^SECURITY 例程创建类访问规则:

  1. 在 %SYS 命名空间中,运行 ^SECURITY 例程:
    DO ^SECURITY
  2. 选择选项 5, 1, 8, 和 1,以输入类访问规则提示。
  3. 按照提示指定以下内容:
    • Application?(应用程序?)– 应用程序名称。
    • Allow type?(允许类型?)– 该规则是适用于应用程序访问特定类 (AllowClass) 还是访问包含指定前缀的所有类 (AllowPrefix)。
    • Class or package name?(类或软件包名称?)– 允许应用程序访问的类或前缀。
    • Allow access?(允许访问?)– 是否允许应用程序访问指定类或软件包。
Discussão (0)0
Entre ou crie uma conta para continuar
Artigo
· Jul. 29 3min de leitura

Dynamic Templated Emails in InterSystems IRIS with templated_email


Sending emails is a common requirement in integration scenarios — whether for client reminders, automatic reports, or transaction confirmations. Static messages quickly become hard to maintain and personalize. This is where the templated_email module comes in, combining InterSystems IRIS Interoperability with the power of Jinja2 templates.

Why Jinja2 for Emails

Jinja2 is a popular templating engine from the Python ecosystem that enables fully dynamic content generation. It supports:

  • Variables — inject dynamic data from integration messages or external sources
  • Conditions (if/else) — change the content based on runtime data
  • Loops (for) — generate tables, lists of items, or repeatable sections
  • Filters and macros — format dates, numbers, and reuse template blocks

Example of a simple email body template:

 


Hello {{ user.name }}!

{% if orders %}
You have {{ orders|length }} new orders:
{% for o in orders %}
 - Order #{{ o.id }}: {{ o.amount }} USD
{% endfor %}
{% else %}
You have no new orders today.
{% endif %}
 

With this approach, your email content becomes dynamic, reusable, and easier to maintain.

Email Styling and Rendering Considerations

Different email clients (Gmail, Outlook, Apple Mail, and others) may render the same HTML in slightly different ways. To achieve a consistent appearance across platforms, it is recommended to:

  • Use inline CSS instead of relying on external stylesheets
  • Prefer table‑based layouts for the overall structure, as modern CSS features such as flexbox or grid may not be fully supported
  • Avoid script and complex CSS rules, as many email clients block or ignore them
  • Test emails in multiple clients and on mobile devices

Capabilities of the templated_email Module

The templated_email module is designed to simplify creating and sending dynamic, professional emails in InterSystems IRIS. Its key capabilities include:

  • render Jinja2 templates to generate dynamic email content
  • Flexible usage — can be used both from Interoperability productions and directly from ObjectScript code
  • Built‑in Business Operation — ready‑to‑use operation for production scenarios with SMTP integration
  • Automatic inline styling — converts CSS styles into inline attributes for better email client compatibility
  • Markdown support — allows creating clean, maintainable templates that are rendered to HTML before sending

These features make it easy to produce dynamic, well‑formatted emails that display consistently across clients.

Module templated_email

The module provides the following key components:

  • TemplatedEmail.BusinessOperation — a Business Operation to send templated emails via SMTP
  • TemplatedEmail.EmailRequest — an Interoperability Message for triggering email sends, with fields for templates, data, and recipients
  • TemplatedEmail.MailMessage — an extension of %Net.MailMessage that adds:
    • applyBodyTemplate() — renders and sets the email body using a Jinja2 + Markdown template
    • applySubjectTemplate() — renders and sets the email subject using a Jinja2 template

This allows you to replace %Net.MailMessage with TemplatedEmail.MailMessage in ObjectScript and gain dynamic templating:


set msg = ##class(TemplatedEmail.MailMessage).%New()
do msg.applySubjectTemplate(data,"New order from {{ customer.name }}")
do msg.applyBodyTemplate(data,,"order_template.tpl")

More details and usage examples can be found in the GitHub repository.

Templates Are Not Just for Emails

The template rendering methods can also be used for generating HTML reports, making it easy to reuse the same templating approach outside of email.

With templated_email, you can create dynamic, professional, and maintainable emails for InterSystems IRIS — while leveraging the full flexibility of Jinja2 templates.

Discussão (0)1
Entre ou crie uma conta para continuar