Here's an idea on how to do it without triggers altogether.

1. Set IsLeader property only in case member is a leader. So its 1 or NULL.

2. Add unique index on (Team, IsLeader). Unique index can have any number of NULL records.

3. If you try to add more than one leader, you'll get an error:

ERROR #5808: Key not unique: Utils.TeamMember:IsLeaderIndex:^Utils.TeamMemberI("IsLeaderIndex"," 1"," 1") [%SaveData+14^Utils.TeamMember.1:USER]

Sample code:

Class Utils.TeamMember Extends %Persistent
{

Property Team As %String;

Property Member As %String;

Property IsLeader(VALUELIST = ",1");

Index IsLeaderIndex On (Team, IsLeader) [ Unique ];

/// do ##class(Utils.TeamMember).Test()
ClassMethod Test(AddTwoLeaders = {$$$YES})
{
    do ..%KillExtent()
    write $System.Status.GetErrorText(..Add(1, "Alice"))
    write $System.Status.GetErrorText(..Add(1, "Bob"))
    write $System.Status.GetErrorText(..Add(1, "Clover"))
    write $System.Status.GetErrorText(..Add(1, "Dave", 1))
    if AddTwoLeaders {
        write $System.Status.GetErrorText(..Add(1, "Helen", 1))
    }
}

ClassMethod Add(Team, Member, IsLeader = "")
{
    set obj = ..%New()
    set obj.Team = Team
    set obj.Member = Member
    set obj.IsLeader = IsLeader
    quit obj.%Save()
}

}

On the other note, if you use REST on 2016.1+ you can enable CORS support in a more organised way:

Class cors.REST Extends %CSP.REST
{
/// This parameter influences the CORS support. The default is an empty string meaning 'not specified'.
/// If set to true (1) then CORS processing is ON. If set to false (0) then CORS processing is OFF.
/// If left unset "" then the decision to process CORS is delegated to the setting on the URL map route.
Parameter HandleCorsRequest;    

XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
<Route Url="/:test" Method="GET" Call="Test" Cors="true"/>
</Routes>
}

/// This is the CORS request handler. User should override this method in their subclass
/// if they don't want the default behavior
ClassMethod OnHandleCorsRequest(pUrl As %String) As %Status
{

    #; The default implementation is simply to dispatch to the
    #; default handler
    Quit ..HandleDefaultCorsRequest(pUrl)
}

}

Note, that if you're okay with HandleDefaultCorsRequest then you don't need to redefine  OnHandleCorsRequest method and need supply only HandleCorsRequest or Cors attribute on per path basis.

In some cases Access-Control-Allow-Origin: * is not a valid value, so I usually determine origin host and supply it:

Do %response.SetHeader("Access-Control-Allow-Origin",..GetOrigins())

And GetOrigins method:

/// Get Origin from %request object
ClassMethod GetOrigins() As %String
{
    set url = %request.GetCgiEnv("HTTP_REFERER")
    return $p(url,"/",1,3) // get http(s)://origin.com:port
}

Also, sometimes additional headers may be required, here's one of the more permissive sets:

Do %response.SetHeader("Access-Control-Allow-Origin",..GetOrigins())
Do %response.SetHeader("Access-Control-Allow-Credentials","true")
Do %response.SetHeader("Access-Control-Allow-Methods","GET, PUT, POST, DELETE, OPTIONS")
Do %response.SetHeader("Access-Control-Max-Age","10000")
Do %response.SetHeader("Access-Control-Allow-Headers","Content-Type, Authorization, Accept-Language, X-Requested-With")

is the import smart enough to figure out if a row already exists

As you can't specify an ID column during import, then no, SQL import wizard would only insert new rows.

is there some other utility that can check for keys first?

You can:

  • export/import underlying global(s)
  • use 3rd party SQL database explorers to generate UPDATE DDL statements from your data (DataGrip can do it for example), and then import this DDL into new namespace

Why not use SFTP for that?

The following method shows how you can get a list of the files on a server, via SFTP:

Method SFTPDir(ftpserver, username, password) As %Status
{
    set ssh = ##class(%Net.SSH.Session).%New()
    do ssh.Connect(ftpserver)
    do ssh.AuthenticateWithUsername(username,password)
    do ssh.OpenSFTP(.sftp)
    do sftp.Dir(".",.files)
    set i=0
    while $data(files(i))
    {
        write $listget(files(i),1),!
        set i=i+1
        // set st = sftp.Get(files(i), "C:\Temp\myfile.ext")
    }
    quit $$$OK
}

To download file(s) uncomment the line. Documentation.