I completely agree, and to get to

 standard installing mechanism 

for USERS, we need to zpm-enable as many existing projects as possible. To enable these projects we need to simplify the zpm-enabling, leveraging existing code if possible (or not preventing developers from leveraging the existing code). I think allowing developers to use already existing installers (whatever form they may take) would help with this goal.

I completely support inclusion of projections.

ObjectScript Language allows execution of arbitrary code at compile time through three different mechanisms:

  • Projections
  • Code generators
  • Macros

All these instruments are entirely unlimited in their scope, so I don't see why we need to prohibit one way of executing code at compilation.

Furthermore ZPM itself uses Projections to install itself so closing this avenue to other projects seems strange.

I have found a workaround.

1. Create task class as usual.

2. Create this subclass extending (1)

/// Run it daily but it would actually run only on Dates
Class util.CustomDatesTask Extends util.BaseTask
{

Parameter TaskName = "BaseTask (random dates)";

/// Comma separated Dates in YYYY-MM-DD format
/// Example: 2019-12-11,2020-01-17,2020-02-11,2020-03-10,2020-04-09,2020-05-12
Property Dates As %VarString;

/// Check that Dates is valid
Method %OnValidateObject() As %Status
{
    #dim sc As %Status = $$$OK
    set sc = ##super()
    quit:$$$ISERR(sc) sc
    try {
        set dates = $lfs(..Dates)
    } catch ex {
        set sc = ex.AsStatus()
        set sc = $$$ADDSC($$$ERROR($$$GeneralError, "Incorrect Dates value: " _ ..Dates), sc)
    }
    quit:$$$ISERR(sc) sc
    for i=1:1:$ll(dates) {
        try {
            set date = $lg(dates, i)
            set temp = $zdh(date, 3)
        } catch ex {
            set sc = ex.AsStatus()
            set sc = $$$ADDSC($$$ERROR($$$GeneralError, "Incorrect Date value: " _ date), sc)
        }
        quit:$$$ISERR(sc)
    }
    quit sc
}

Method OnTask() As %Status
{
    #dim sc As %Status = $$$OK
    set dates = $lfs(..Dates)
    set curDate = $zd($h, 3)
    if $lf(dates, curDate) {
        // Execute the task
        set sc = ##super()
    }
    quit sc
}
}

The advantage is that schedule is easy to set as a task config property. Drawback is that logs would be created for each day.

For example:

set maxrows = 1000
set currentrow = 0
while (ind '= ""){
    set row = ^CacheTemp(repid,"MAIN",ind)
    if currentrow>maxrows  {
        set currentrow = 0
       // swap files
    }
    set currentrow  = currentrow  + 1
    use filemain write row,!
    ; Get next row index for MAIN report
    set ind = $order(^CacheTemp(repid,"MAIN",ind))
}
close filemain

Are you by chance exporting SQL queries to CSV? If so it can be done automatically:

do ##class(%SQL.Statement).%ExecDirect(,"select * from ...")).%DisplayFormatted(100, filename)

You need to specify pFormat parameter, it defaults to aceloqtw, where:

  • 1-9 : indent with this number of spaces (4 is the default with the 'i' format specifier)
  • a - output null arrays/objects
  • b - line break before opening { of objects
  • c - output the Caché-specific "_class" and "_id" properties
  • d - output Caché numeric properties that have value "" as null
  • e - output empty object properties
  • i - indent with 4 spaces unless 't' or 1-9
  • l - output empty lists
  • n - newline (lf)
  • o - output empty arrays/objects
  • q - output numeric values unquoted even when they come from a non-numeric property
  • s - use strict JSON output - NOTE: special care should be taken when sending data to a browser, as using this flag may expose you to cross site scripting (XSS) vulnerabilities if the data is sent inside <script> tags. Zen uses this technique extensively, so this flag should NOT be specified for jsonProviders in Zen pages.
  • t - indent with tab character
  • u - output pre-converted to UTF-8 instead of in native internal format
  • w - Windows-style cr/lf newline

In your case explicitly remove c: aeloqtw. This is quoted from documentation.

Additionally if you want to output json to the current device it would be better to use %WriteJSONFromObject - it has the same arguments, except stream, so there's no extra object and io redirect costs:

$$$TOE(tSC, ##class(%ZEN.Auxiliary.jsonProvider).%WriteJSONFromObject(,Store,,,,"aeloqtw")