Fixed maps.

Fixed maps.

import module namespace util = "http://secxbrl.info/modules/util";

import module namespace request = "http://www.28msec.com/modules/http-request";
import module namespace session = "http://apps.28.io/session";

import module namespace entities = "http://28.io/modules/xbrl/entities";
import module namespace hypercubes = "http://28.io/modules/xbrl/hypercubes";
import module namespace components = "http://28.io/modules/xbrl/components";
import module namespace reports = "http://28.io/modules/xbrl/reports";
import module namespace concept-maps = "http://28.io/modules/xbrl/concept-maps";

import module namespace companies = "http://28.io/modules/xbrl/profiles/sec/companies";
import module namespace fiscal-core = "http://28.io/modules/xbrl/profiles/sec/fiscal/core";

import module namespace mongo = "http://www.28msec.com/modules/mongodb";
import module namespace credentials = "http://www.28msec.com/modules/credentials";

import module namespace csv = "http://zorba.io/modules/json-csv";
import module namespace seq = "http://zorba.io/modules/sequence";

declare namespace concepts = "http://www.28msec.com/modules/bizql/concepts";

declare function local:to-csv($concepts as item*, $onlyNames as boolean) as string
{
    if ($onlyNames)
    then
        string-join(("Name", $concepts), "
")
    else
        string-join(csv:serialize($concepts, { serialize-null-as : "" }))
};

declare function local:to-xml($concepts as item*, $onlyNames as boolean) as element()*
{
    for $c in $concepts
    return
        <ReportElement>{
             if ($onlyNames)
             then
                <Name>{$c}</Name>
             else (
                <Name>{$c.Name}</Name>,
                <Label>{$c.Label}</Label>,
                <IsNillable>{$c.IsNillable}</IsNillable>,
                <IsAbstract>{$c.IsAbstract}</IsAbstract>,
                <PeriodType>{$c.PeriodType}</PeriodType>,
                <Balance>{$c.Balance}</Balance>,
                <SubstitutionGroup>{$c.SubstitutionGroup}</SubstitutionGroup>,
                <DataType>{$c.DataType}</DataType>,
                <BaseType>{$c.BaseType}</BaseType>,
                <ClosestSchemaBuiltinType>{$c.ClosestSchemaBuiltinType}</ClosestSchemaBuiltinType>,
                <IsTextBlock>{$c.IsTextBlock}</IsTextBlock>,
                <ComponentRole>{$c.ComponentRole}</ComponentRole>,
                <ComponentLabel>{$c.ComponentLabel}</ComponentLabel>,
                <AccessionNumber>{$c.AccessionNumber}</AccessionNumber>,
                <CIK>{$c.CIK}</CIK>,
                <EntityRegistrantName>{$c.EntityRegistrantName}</EntityRegistrantName>,
                <FiscalYear>{$c.FiscalYear}</FiscalYear>,
                <FiscalPeriod>{$c.FiscalPeriod}</FiscalPeriod>
             )
        }</ReportElement>
};

declare function local:concepts-for-archives(
    $aids as string*,
    $names as string*,
    $map as object?,
    $options as object?) as object*
{
    let $projection as object := if($options.OnlyNames eq true) then { Name: 1 } else {}
    let $conn as anyURI :=
      let $credentials as object? := credentials:credentials("MongoDB", "xbrl")
      return
        try {
            mongo:connect($credentials)
        } catch mongo:* {
            error(QName("concepts:CONNECTION-FAILED"), $err:description)
        }

    let $concepts-computable-by-maps as object* :=
        switch(true)
            case not exists($map) return ()
            case not exists($names) return values($map.Trees)
            default return
                let $keys as string* := keys($map.Trees)
                for $concept as string in $names[$$ = $keys]
                return $map.Trees.$concept
    let $mapped-names as string* := (keys($concepts-computable-by-maps.To ), $concepts-computable-by-maps.To [].Name)
    let $concepts-not-computable-by-maps as string* := seq:value-except($names, $mapped-names)

    let $all-results as object* := mongo:find($conn, "concepts",
        {
            "Archive": { "$in" : [ $aids ] }
        },
        $projection,
        {})
    let $results-not-computed-by-maps as object* := mongo:find($conn, "concepts",
        {
            "Name" : { "$in" : [ $concepts-not-computable-by-maps ] },
            "Archive": { "$in" : [ $aids ] }
        },
        $projection,
        {})
    let $results-computed-by-maps as object* :=
        let $all-results as object* := mongo:find($conn, "concepts",
            {
                "Name" : { "$in" : [ $mapped-names ] },
                "Archive": { "$in" : [ $aids ] }
            },
            $projection,
            {})
        for $concept as object in $concepts-computable-by-maps
        for $result as object in
            for $candidate-concept in (keys($concept.To), $concept[].Name)
            let $facts := $all-results[$$.Name = $candidate-concept]
            where exists($facts)
            count $c
            where $c eq 1
            return $facts
        let $map-concept := (for $candidate in $concepts-computable-by-maps
                            where $result.Name = (keys($candidate.To), $candidate.To[].Name)
                            return $candidate)[1]
        return
            copy $n := $result
            modify (
                replace value of json $n.Name with $map-concept.Name,
                insert json  { Origin : $result.Name } into $n)
            return $n
    return if(empty($map) and empty($names))
           then $all-results
           else ($results-not-computed-by-maps, $results-computed-by-maps)
};

declare function local:concepts-for-archives-and-labels($aids as string*, $labels as string) as object*
{
    let $conn :=
        let $credentials := credentials:credentials("MongoDB", "xbrl")
        return
            try {
                mongo:connect($credentials)
            } catch mongo:* {
                error(QName("components:CONNECTION-FAILED"), $err:description)
            }
    return mongo:run-cmd-deterministic(
        $conn,
        {
            "text" : "concepts",
            "filter" : { "Archive" : { "$in" : [ $aids ] } },
            "search" : $labels,
            "limit" : 100,
            "score" : { "$meta" : "textScore" },
            "sort" : { score: { "$meta" : "textScore" } }
        }).results[].obj
};

session:audit-call();

(: Query parameters :)
let $format as string?         := request:param-values("format")
let $ciks as string*           := distinct-values(request:param-values("cik"))
let $tags as string*           := distinct-values(request:param-values("tag"))
let $tickers as string*        := distinct-values(request:param-values("ticker"))
let $sics as string*           := distinct-values(request:param-values("sic"))
let $fiscalYears as string*    := distinct-values(request:param-values("fiscalYear", "LATEST"))
let $fiscalPeriods as string*  := distinct-values(request:param-values("fiscalPeriod", "FY"))
let $aids as string*           := distinct-values(request:param-values("aid"))
let $labels as string*         := request:param-values("label")
let $map as string?            := request:param-values("map")
let $report as string?         := request:param-values("report")
let $names as string*          := request:param-values("name")

(: Post-processing :)
let $format as string? := (: backwards compatibility, to be deprecated  :)
    lower-case(($format, substring-after(request:path(), ".jq."))[1])
let $tags as string* := (: backwards compatibility, to be deprecated :)
    distinct-values($tags ! upper-case($$))
let $fiscalYears as integer* :=
    for $fy in $fiscalYears ! upper-case($$)
    return switch($fy)
           case "LATEST" return $fiscal-core:LATEST_FISCAL_YEAR
           case "ALL" return $fiscal-core:ALL_FISCAL_YEARS
           default return if($fy castable as integer) then integer($fy) else ()
let $fiscalPeriods as string* :=
    for $fp in $fiscalPeriods ! upper-case($$)
    return switch($fp)
           case "ALL" return $fiscal-core:ALL_FISCAL_PERIODS
           default return $fp

(: Object resolution :)
let $entities as object* :=
    companies:companies(
        $ciks,
        $tags,
        $tickers,
        $sics)
let $archives as object* := fiscal-core:filings(
    $entities,
    $fiscalPeriods,
    $fiscalYears,
    $aids)
let $entities as object* :=
    ($entities[$$._id = $archives.Entity],
    let $not-found := $archives.Entity[not $entities._id = $$]
    where exists($not-found)
    return entities:entities($not-found))
let $onlyNames   := let $o := request:param-values("onlyNames")[1] return if (exists($o)) then ($o cast as boolean) else false
let $map as object? :=
    if(exists($report))
    then reports:concept-map($report)
    else concept-maps:concept-maps($map)

let $concepts := if (exists($labels))
                 then local:concepts-for-archives-and-labels($archives._id, $labels[1])
                 else local:concepts-for-archives($archives._id, $names, $map, { OnlyNames: $onlyNames })

let $result := {
    ReportElements : [
        if ($onlyNames)
        then distinct-values($concepts.Name)
        else
            let $all-aids := $concepts.Archive
            let $roles := $concepts.Role
            let $components := components:components-for-archives-and-roles($all-aids, $roles)
            return
            for $concept in $concepts
            group by $archive := $concept.Archive,  $role := $concept.Role
            let $component as object := $components[$$.Archive eq $archive and $$.Role eq $role]
            let $default-hc as object := hypercubes:hypercubes-for-components($component, "xbrl:DefaultHypercube")
            let $members as object* := $default-hc.Aspects."xbrl:Concept".Domains."xbrl:ConceptDomain".Members
            let $archive as object := $archives[$$._id eq $archive]
            let $entity as object := $entities[$$._id eq $archive.Entity]
            let $metadata := {
                ComponentRole : $component.Role,
                ComponentLabel : $component.Label,
                AccessionNumber : $archive._id,
                CIK : $entity._id,
                EntityRegistrantName : $entity.Profiles.SEC.CompanyName,
                FiscalYear : $archive.Profiles.SEC.Fiscal.DocumentFiscalYearFocus,
                FiscalPeriod : $archive.Profiles.SEC.Fiscal.DocumentFiscalPeriodFocus
            }
            for $concept in $concept
            let $original-name := ($concept.Origin, $concept.Name)[1]
            return {|
                project($concept, ("Name", "Origin")),
                trim($members.$original-name, "Name"),
                $metadata
            |}
    ]
}
let $comment := {
    NumConcepts: count($concepts),
    TotalNumConcepts: session:num-concepts()
}
let $serializers := {
    to-xml : function($res as object) as node() {
        <ReportElements>{
                    local:to-xml($res.ReportElements[], $onlyNames)
                }</ReportElements>
    },
    to-csv : function($res as object) as string {
        local:to-csv($res.ReportElements[], $onlyNames)
    }
}
let $results := util:serialize($result, $comment, $serializers, $format, "report-elements")
return
    util:check-and-return-results($entities, $results, $format)

import module namespace util = "http://secxbrl.info/modules/util";

import module namespace request = "http://www.28msec.com/modules/http-request";
import module namespace session = "http://apps.28.io/session";

import module namespace entities = "http://28.io/modules/xbrl/entities";
import module namespace hypercubes = "http://28.io/modules/xbrl/hypercubes";
import module namespace components = "http://28.io/modules/xbrl/components";
import module namespace reports = "http://28.io/modules/xbrl/reports";
import module namespace concept-maps = "http://28.io/modules/xbrl/concept-maps";

import module namespace companies = "http://28.io/modules/xbrl/profiles/sec/companies";
import module namespace fiscal-core = "http://28.io/modules/xbrl/profiles/sec/fiscal/core";

import module namespace mongo = "http://www.28msec.com/modules/mongodb";
import module namespace credentials = "http://www.28msec.com/modules/credentials";

import module namespace csv = "http://zorba.io/modules/json-csv";
import module namespace seq = "http://zorba.io/modules/sequence";

declare namespace concepts = "http://www.28msec.com/modules/bizql/concepts";

declare function local:to-csv($concepts as item*, $onlyNames as boolean) as string
{
    if ($onlyNames)
    then
        string-join(("Name", $concepts), "
")
    else
        string-join(csv:serialize($concepts, { serialize-null-as : "" }))
};

declare function local:to-xml($concepts as item*, $onlyNames as boolean) as element()*
{
    for $c in $concepts
    return
        <ReportElement>{
             if ($onlyNames)
             then
                <Name>{$c}</Name>
             else (
                <Name>{$c.Name}</Name>,
                <Label>{$c.Label}</Label>,
                <IsNillable>{$c.IsNillable}</IsNillable>,
                <IsAbstract>{$c.IsAbstract}</IsAbstract>,
                <PeriodType>{$c.PeriodType}</PeriodType>,
                <Balance>{$c.Balance}</Balance>,
                <SubstitutionGroup>{$c.SubstitutionGroup}</SubstitutionGroup>,
                <DataType>{$c.DataType}</DataType>,
                <BaseType>{$c.BaseType}</BaseType>,
                <ClosestSchemaBuiltinType>{$c.ClosestSchemaBuiltinType}</ClosestSchemaBuiltinType>,
                <IsTextBlock>{$c.IsTextBlock}</IsTextBlock>,
                <ComponentRole>{$c.ComponentRole}</ComponentRole>,
                <ComponentLabel>{$c.ComponentLabel}</ComponentLabel>,
                <AccessionNumber>{$c.AccessionNumber}</AccessionNumber>,
                <CIK>{$c.CIK}</CIK>,
                <EntityRegistrantName>{$c.EntityRegistrantName}</EntityRegistrantName>,
                <FiscalYear>{$c.FiscalYear}</FiscalYear>,
                <FiscalPeriod>{$c.FiscalPeriod}</FiscalPeriod>
             )
        }</ReportElement>
};

declare function local:concepts-for-archives($aids as string*, $projection as object) as object*
{
    let $conn :=
      let $credentials := credentials:credentials("MongoDB", "xbrl")
      return
        try {
            mongo:connect($credentials)
        } catch mongo:* {
            error(QName("concepts:CONNECTION-FAILED"), $err:description)
        }
    return
        mongo:find($conn, "concepts",
        {
            "Archive": { "$in" : [ $aids ] }
        },
        $projection,
        {})
};

declare function local:concepts-for-archives($aids as string*, $names as string*, $map as object?) as object*
{
    let $conn as anyURI :=
      let $credentials as object? := credentials:credentials("MongoDB", "xbrl")
      return
        try {
            mongo:connect($credentials)
        } catch mongo:* {
            error(QName("concepts:CONNECTION-FAILED"), $err:description)
        }

    let $concepts-computable-by-maps as object* :=
        switch(true)
            case not exists($map) return ()
            case not exists($names) return values($map.Trees)
            default return
                let $keys as string* := keys($map.Trees)
                for $concept as string in $names[$$ = $keys]
                return $map.Trees.$concept

    let $mapped-names as string* := (keys($concepts-computable-by-maps.To ), $concepts-computable-by-maps.To [].Name)

    let $concepts-not-computable-by-maps as string* := seq:value-except($names, $mapped-names)
    let $results-not-computed-by-maps as object* := mongo:find($conn, "concepts",
        {
            "Name" : { "$in" : [ $concepts-not-computable-by-maps ] },
            "Archive": { "$in" : [ $aids ] }
        })
    let $results-computed-by-maps as object* :=
        for $c in mongo:find($conn, "concepts",
            {
                "Name" : { "$in" : [ $mapped-names ] },
                "Archive": { "$in" : [ $aids ] }
            })
        group by $c.Component
        let $c := $c[1]
        let $map-concept := (for $candidate in $concepts-computable-by-maps
                            where $c.Name = (keys($candidate.To), $candidate.To[].Name)
                            return $candidate)[1]
        return
            copy $n := $c
            modify (
                replace value of json $n.Name with $map-concept.Name,
                insert json  { Origin : $c.Name } into $n)
            return $n
    return ($results-not-computed-by-maps, $results-computed-by-maps)
};

declare function local:concepts-for-archives-and-labels($aids as string*, $labels as string) as object*
{
    let $conn :=
        let $credentials := credentials:credentials("MongoDB", "xbrl")
        return
            try {
                mongo:connect($credentials)
            } catch mongo:* {
                error(QName("components:CONNECTION-FAILED"), $err:description)
            }
    return mongo:run-cmd-deterministic(
        $conn,
        {
            "text" : "concepts",
            "filter" : { "Archive" : { "$in" : [ $aids ] } },
            "search" : $labels,
            "limit" : 100,
            "score" : { "$meta" : "textScore" },
            "sort" : { score: { "$meta" : "textScore" } }
        }).results[].obj
};

session:audit-call();

(: Query parameters :)
let $format as string?         := request:param-values("format")
let $ciks as string*           := distinct-values(request:param-values("cik"))
let $tags as string*           := distinct-values(request:param-values("tag"))
let $tickers as string*        := distinct-values(request:param-values("ticker"))
let $sics as string*           := distinct-values(request:param-values("sic"))
let $fiscalYears as string*    := distinct-values(request:param-values("fiscalYear", "LATEST"))
let $fiscalPeriods as string*  := distinct-values(request:param-values("fiscalPeriod", "FY"))
let $aids as string*           := distinct-values(request:param-values("aid"))
let $labels as string*         := request:param-values("label")
let $map as string?            := request:param-values("map")
let $report as string?         := request:param-values("report")
let $names as string*          := request:param-values("name")

(: Post-processing :)
let $format as string? := (: backwards compatibility, to be deprecated  :)
    lower-case(($format, substring-after(request:path(), ".jq."))[1])
let $tags as string* := (: backwards compatibility, to be deprecated :)
    distinct-values($tags ! upper-case($$))
let $fiscalYears as integer* :=
    for $fy in $fiscalYears ! upper-case($$)
    return switch($fy)
           case "LATEST" return $fiscal-core:LATEST_FISCAL_YEAR
           case "ALL" return $fiscal-core:ALL_FISCAL_YEARS
           default return if($fy castable as integer) then integer($fy) else ()
let $fiscalPeriods as string* :=
    for $fp in $fiscalPeriods ! upper-case($$)
    return switch($fp)
           case "ALL" return $fiscal-core:ALL_FISCAL_PERIODS
           default return $fp

(: Object resolution :)
let $entities as object* :=
    companies:companies(
        $ciks,
        $tags,
        $tickers,
        $sics)
let $archives as object* := fiscal-core:filings(
    $entities,
    $fiscalPeriods,
    $fiscalYears,
    $aids)
let $entities as object* :=
    ($entities[$$._id = $archives.Entity],
    let $not-found := $archives.Entity[not $entities._id = $$]
    where exists($not-found)
    return entities:entities($not-found))
let $onlyNames   := let $o := request:param-values("onlyNames")[1] return if (exists($o)) then ($o cast as boolean) else false
let $map as object? :=
    if(exists($report))
    then reports:concept-map($report)
    else concept-maps:concept-maps($map)

let $concepts := if (exists($names))
                  then local:concepts-for-archives($archives._id, $names, $map)
                  else if (exists($labels))
                  then local:concepts-for-archives-and-labels($archives._id, $labels[1])
                  else if($onlyNames)
                  then local:concepts-for-archives($archives._id, { Name: 1 })
                  else local:concepts-for-archives($archives._id, {})
let $result := {
    ReportElements : [
        if ($onlyNames)
        then distinct-values($concepts.Name)
        else
            let $all-aids := $concepts.Archive
            let $roles := $concepts.Role
            let $components := components:components-for-archives-and-roles($all-aids, $roles)
            return
            for $concept in $concepts
            group by $archive := $concept.Archive,  $role := $concept.Role
            let $component as object := $components[$$.Archive eq $archive and $$.Role eq $role]
            let $default-hc as object := hypercubes:hypercubes-for-components($component, "xbrl:DefaultHypercube")
            let $members as object* := $default-hc.Aspects."xbrl:Concept".Domains."xbrl:ConceptDomain".Members
            let $archive as object := $archives[$$._id eq $archive]
            let $entity as object := $entities[$$._id eq $archive.Entity]
            let $metadata := {
                ComponentRole : $component.Role,
                ComponentLabel : $component.Label,
                AccessionNumber : $archive._id,
                CIK : $entity._id,
                EntityRegistrantName : $entity.Profiles.SEC.CompanyName,
                FiscalYear : $archive.Profiles.SEC.Fiscal.DocumentFiscalYearFocus,
                FiscalPeriod : $archive.Profiles.SEC.Fiscal.DocumentFiscalPeriodFocus
            }
            for $concept in $concept
            let $original-name := ($concept.Origin, $concept.Name)[1]
            return {|
                project($concept, ("Name", "Origin")),
                trim($members.$original-name, "Name"),
                $metadata
            |}
    ]
}
let $comment := {
    NumConcepts: count($concepts),
    TotalNumConcepts: session:num-concepts()
}
let $serializers := {
    to-xml : function($res as object) as node() {
        <ReportElements>{
                    local:to-xml($res.ReportElements[], $onlyNames)
                }</ReportElements>
    },
    to-csv : function($res as object) as string {
        local:to-csv($res.ReportElements[], $onlyNames)
    }
}
let $results := util:serialize($result, $comment, $serializers, $format, "report-elements")
return
    util:check-and-return-results($entities, $results, $format)


Update public/libs/bower_components/ace-builds/demo/kitchen-sink/docs/jsoniq.jq

Signed-off-by: Bernard Ojengwa <fccb4cc00c1ba7e51bf5c2b5f77130b9fe8d917e@gmail.com>


:Allow absence of entity.

:Allow absence of entity.

import module namespace api = "http://apps.28.io/api";

import module namespace session = "http://apps.28.io/session";
import module namespace backend = "http://apps.28.io/backend";

import module namespace entities = "http://28.io/modules/xbrl/entities";
import module namespace components = "http://28.io/modules/xbrl/components";
import module namespace reports = "http://28.io/modules/xbrl/reports";
import module namespace labels = "http://28.io/modules/xbrl/labels";
import module namespace config = "http://apps.28.io/config";

import module namespace multiplexer = "http://28.io/modules/xbrl/profiles/multiplexer";

import module namespace mw = "http://28.io/modules/xbrl/mongo-wrapper";

declare option rest:response "first-item";

declare function local:concepts-for-archives-and-labels($aids as string*, $labels as string) as object*
{
   mw:run-cmd-deterministic(
      {
        "text" : "concepts",
        "filter" : { "Archive" : { "$in" : [ $aids ] } },
        "search" : $labels,
        "limit" : 100,
        "score" : { "$meta" : "textScore" },
        "sort" : { score: { "$meta" : "textScore" } }
      }).results[].obj
};

(: Query parameters :)
declare  %rest:case-insensitive                 variable $token          as string?  external;
declare  %rest:case-insensitive                 variable $profile-name   as string  external := $config:profile-name;
declare  %rest:env                              variable $request-uri    as string   external;
declare  %rest:case-insensitive                 variable $format         as string?  external;
declare  %rest:case-insensitive %rest:distinct  variable $cik            as string*  external;
declare  %rest:case-insensitive %rest:distinct  variable $edinetcode     as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $tag            as string*  external;
declare  %rest:case-insensitive %rest:distinct  variable $ticker         as string*  external;
declare  %rest:case-insensitive %rest:distinct  variable $sic            as string*  external;
declare  %rest:case-insensitive %rest:distinct  variable $fiscalYear     as string*  external := "ALL";
declare  %rest:case-insensitive %rest:distinct  variable $fiscalPeriod   as string*  external := "ALL";
declare  %rest:case-insensitive %rest:distinct  variable $filingKind     as string* external := ();
declare  %rest:case-insensitive %rest:distinct  variable $aid            as string*  external;
declare  %rest:case-insensitive %rest:distinct  variable $disclosure     as string*  external;
declare  %rest:case-insensitive %rest:distinct  variable $section        as string*  external;
declare  %rest:case-insensitive %rest:distinct  variable $role           as string*  external;
declare  %rest:case-insensitive %rest:distinct  variable $eid            as string*  external;
declare  %rest:case-insensitive %rest:distinct  variable $label          as string*  external;
declare  %rest:case-insensitive                 variable $report         as string?  external;
declare  %rest:case-insensitive %rest:distinct  variable $name           as string*  external;
declare  %rest:case-insensitive                 variable $onlyNames      as boolean? external := false;
declare  %rest:case-insensitive                 variable $onlyTextBlocks as boolean? external := ();
declare  %rest:case-insensitive                 variable $abstract       as boolean? external := ();
declare  %rest:case-insensitive                 variable $kind           as string*  external := ();
declare  %rest:case-insensitive                 variable $count          as boolean external := false;
declare  %rest:case-insensitive                 variable $language           as string  external := "en-US";

(: Post-processing :)
let $format as string? := api:preprocess-format($format, $request-uri)
let $fiscalYear as integer* := api:preprocess-fiscal-years($fiscalYear)
let $fiscalPeriod as string* := api:preprocess-fiscal-periods($fiscalPeriod)
let $tag as string* := api:preprocess-tags($tag)
let $kind as string* := api:preprocess-concept-kind($kind)
let $section := distinct-values(($section, $role))

let $cik as string* :=
    switch($profile-name)
    case "sec" return $cik
    case "japan" return $edinetcode
    default return ()

(: Entity resolution :)
let $entities := multiplexer:entities(
  $profile-name,
  $eid,
  $cik,
  $tag,
  $ticker,
  $sic,
  (),
  (),
  (),
  ())

let $entities-not-found as boolean :=
  exists(($eid, $cik, $tag, $ticker, $sic)) and empty($entities)

let $archives as object* := multiplexer:filings(
  $profile-name,
  $entities,
  $fiscalPeriod,
  $fiscalYear,
  $filingKind,
  $aid)

let $archives-not-found as boolean :=
  exists(($entities, $fiscalPeriod, $fiscalYear, $filingKind, $aid)) and empty($archives)

let $entities as object* :=
    ($entities[entities:eid($$) = $archives.Entity],
    let $not-found := $archives.Entity[not entities:eid($entities) = $$]
    where exists($not-found)
    return entities:entities($not-found))

let $report as object? := reports:reports($report)

let $concepts as object* :=
    multiplexer:concepts(
      $profile-name,
      $archives,
      $name,
      $disclosure,
      $section,
      $label[$profile-name ne "sec"],
      $label[$profile-name eq "sec"],
      $report,
      $onlyNames)[
    (empty($onlyTextBlocks) or $$.IsTextBlock eq $onlyTextBlocks) and
    (empty($abstract) or $$.IsAbstract eq $abstract) and
    (empty($kind) or $$.Kind = $kind)
  ]

let $result :=
  let $all-aids as string* := distinct-values($concepts.Archive)
  let $roles as string* := distinct-values($concepts.Role)
  let $components := components:components-for-archives-and-roles($all-aids, $roles)
  return {
    ReportElements : [
      switch(true)
      case $count return ()
      case $onlyNames return distinct-values($concepts.Name)
      default return
        for $concept in $concepts
        group by $archive := $concept.Archive,  $role := $concept.Role
        let $component as object := $components[$$.Archive eq $archive and $$.Role eq $role]
        return
              let $archive-object as object := $archives[$$._id eq $archive]
              let $entity as object? := $entities[entities:eid($$) = $archive-object.Entity]
              let $metadata := {
                  Archive : $archive,
                  Section : $component.Label,
                  SectionURI : $component.Role
              }
              let $metadata-sec := {
                  CIK : entities:eid($entity),
                  EntityRegistrantName : $entity.Profiles.SEC.CompanyName,
                  FiscalYear : $archive-object.Profiles.SEC.Fiscal.DocumentFiscalYearFocus,
                  FiscalPeriod : $archive-object.Profiles.SEC.Fiscal.DocumentFiscalPeriodFocus
              }[$profile-name eq "sec"]
              for $concept in $concept
                let $original-name := ($concept.Origin, $concept.Name)[1]
                return {|
                    {
                      Label: values(labels:labels(
                        $concept.Name,
                        $labels:STANDARD_LABEL_ROLE,
                        $language,
                        $concept,
                        (),
                        ()
                      ))
                    },
                    project($concept, ("Name", "Origin")),
                    {
                      Labels: backend:url("labels", {|
                        {
                          token: $token,
                          concept: $original-name,
                          aid: $archive,
                          section: $role,
                          format: $format,
                          profile-name: $profile-name,
                          language: $language
                        }
                      |}),
                      Facts:
                        if($concept.Kind eq "Concept")
                        then backend:url("facts", {|
                          {
                            token: $token,
                            "xbrl:Concept": $original-name,
                            aid: $archive,
                            format: $format,
                            profile-name: $profile-name,
                            language: $language
                          },
                          {
                            fiscalYear: "ALL",
                            fiscalPeriod: "ALL",
                            fiscalPeriodType: "ALL"
                          }[$profile-name = ("sec", "japan")]
                        |})
                        else "None"
                    },
                    trim($concept, ("Origin", "_id", "Archive", "Role", "Name",  "Label", "Labels", "IsAbstract", "SubstitutionGroup")),
                    $metadata,
                    $metadata-sec
                |}
        ]
    }
let $comment := {
    NumConcepts: count($result.ReportElements[]),
    TotalNumConcepts: session:num-concepts()
}
let $serializers := {
    to-xml : function($res as object) as node() {
        <ReportElements>{
          if ($onlyNames)
          then
            <ReportElement>{
              for $c in $res.ReportElements[]
              return <Name>{$c}</Name>
            }</ReportElement>
          else api:json-to-xml($res.ReportElements[], "ReportElement")
        }</ReportElements>
    },
    to-csv : function($res as object) as string {
      if ($onlyNames)
      then
          string-join(("Name", $res.ReportElements[]), "
")
      else
          api:json-to-csv($res.ReportElements[])
    }
}
let $results := api:serialize($result, $comment, $serializers, $format, "report-elements")
return switch(true)
       case $entities-not-found return api:not-found("entity")
       case $archives-not-found return api:not-found("archive")
       default return api:check-and-return-results($token, $results, $format)

import module namespace api = "http://apps.28.io/api";

import module namespace session = "http://apps.28.io/session";
import module namespace backend = "http://apps.28.io/backend";

import module namespace entities = "http://28.io/modules/xbrl/entities";
import module namespace components = "http://28.io/modules/xbrl/components";
import module namespace reports = "http://28.io/modules/xbrl/reports";
import module namespace labels = "http://28.io/modules/xbrl/labels";
import module namespace config = "http://apps.28.io/config";

import module namespace multiplexer = "http://28.io/modules/xbrl/profiles/multiplexer";

import module namespace mw = "http://28.io/modules/xbrl/mongo-wrapper";

declare option rest:response "first-item";

declare function local:concepts-for-archives-and-labels($aids as string*, $labels as string) as object*
{
   mw:run-cmd-deterministic(
      {
        "text" : "concepts",
        "filter" : { "Archive" : { "$in" : [ $aids ] } },
        "search" : $labels,
        "limit" : 100,
        "score" : { "$meta" : "textScore" },
        "sort" : { score: { "$meta" : "textScore" } }
      }).results[].obj
};

(: Query parameters :)
declare  %rest:case-insensitive                 variable $token          as string?  external;
declare  %rest:case-insensitive                 variable $profile-name   as string  external := $config:profile-name;
declare  %rest:env                              variable $request-uri    as string   external;
declare  %rest:case-insensitive                 variable $format         as string?  external;
declare  %rest:case-insensitive %rest:distinct  variable $cik            as string*  external;
declare  %rest:case-insensitive %rest:distinct  variable $edinetcode     as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $tag            as string*  external;
declare  %rest:case-insensitive %rest:distinct  variable $ticker         as string*  external;
declare  %rest:case-insensitive %rest:distinct  variable $sic            as string*  external;
declare  %rest:case-insensitive %rest:distinct  variable $fiscalYear     as string*  external := "ALL";
declare  %rest:case-insensitive %rest:distinct  variable $fiscalPeriod   as string*  external := "ALL";
declare  %rest:case-insensitive %rest:distinct  variable $filingKind     as string* external := ();
declare  %rest:case-insensitive %rest:distinct  variable $aid            as string*  external;
declare  %rest:case-insensitive %rest:distinct  variable $disclosure     as string*  external;
declare  %rest:case-insensitive %rest:distinct  variable $section        as string*  external;
declare  %rest:case-insensitive %rest:distinct  variable $role           as string*  external;
declare  %rest:case-insensitive %rest:distinct  variable $eid            as string*  external;
declare  %rest:case-insensitive %rest:distinct  variable $label          as string*  external;
declare  %rest:case-insensitive                 variable $report         as string?  external;
declare  %rest:case-insensitive %rest:distinct  variable $name           as string*  external;
declare  %rest:case-insensitive                 variable $onlyNames      as boolean? external := false;
declare  %rest:case-insensitive                 variable $onlyTextBlocks as boolean? external := ();
declare  %rest:case-insensitive                 variable $abstract       as boolean? external := ();
declare  %rest:case-insensitive                 variable $kind           as string*  external := ();
declare  %rest:case-insensitive                 variable $count          as boolean external := false;
declare  %rest:case-insensitive                 variable $language           as string  external := "en-US";

(: Post-processing :)
let $format as string? := api:preprocess-format($format, $request-uri)
let $fiscalYear as integer* := api:preprocess-fiscal-years($fiscalYear)
let $fiscalPeriod as string* := api:preprocess-fiscal-periods($fiscalPeriod)
let $tag as string* := api:preprocess-tags($tag)
let $kind as string* := api:preprocess-concept-kind($kind)
let $section := distinct-values(($section, $role))

let $cik as string* :=
    switch($profile-name)
    case "sec" return $cik
    case "japan" return $edinetcode
    default return ()

(: Entity resolution :)
let $entities := multiplexer:entities(
  $profile-name,
  $eid,
  $cik,
  $tag,
  $ticker,
  $sic,
  (),
  (),
  (),
  ())

let $entities-not-found as boolean :=
  exists(($eid, $cik, $tag, $ticker, $sic)) and empty($entities)

let $archives as object* := multiplexer:filings(
  $profile-name,
  $entities,
  $fiscalPeriod,
  $fiscalYear,
  $filingKind,
  $aid)

let $archives-not-found as boolean :=
  exists(($entities, $fiscalPeriod, $fiscalYear, $filingKind, $aid)) and empty($archives)

let $entities as object* :=
    ($entities[entities:eid($$) = $archives.Entity],
    let $not-found := $archives.Entity[not entities:eid($entities) = $$]
    where exists($not-found)
    return entities:entities($not-found))

let $report as object? := reports:reports($report)

let $concepts as object* :=
    multiplexer:concepts(
      $profile-name,
      $archives,
      $name,
      $disclosure,
      $section,
      $label[$profile-name ne "sec"],
      $label[$profile-name eq "sec"],
      $report,
      $onlyNames)[
    (empty($onlyTextBlocks) or $$.IsTextBlock eq $onlyTextBlocks) and
    (empty($abstract) or $$.IsAbstract eq $abstract) and
    (empty($kind) or $$.Kind = $kind)
  ]

let $result :=
  let $all-aids as string* := distinct-values($concepts.Archive)
  let $roles as string* := distinct-values($concepts.Role)
  let $components := components:components-for-archives-and-roles($all-aids, $roles)
  return {
    ReportElements : [
      switch(true)
      case $count return ()
      case $onlyNames return distinct-values($concepts.Name)
      default return
        for $concept in $concepts
        group by $archive := $concept.Archive,  $role := $concept.Role
        let $component as object := $components[$$.Archive eq $archive and $$.Role eq $role]
        return
              let $archive-object as object := $archives[$$._id eq $archive]
              let $entity as object := $entities[entities:eid($$) = $archive-object.Entity]
              let $metadata := {
                  Archive : $archive,
                  Section : $component.Label,
                  SectionURI : $component.Role
              }
              let $metadata-sec := {
                  CIK : entities:eid($entity),
                  EntityRegistrantName : $entity.Profiles.SEC.CompanyName,
                  FiscalYear : $archive-object.Profiles.SEC.Fiscal.DocumentFiscalYearFocus,
                  FiscalPeriod : $archive-object.Profiles.SEC.Fiscal.DocumentFiscalPeriodFocus
              }[$profile-name eq "sec"]
              for $concept in $concept
                let $original-name := ($concept.Origin, $concept.Name)[1]
                return {|
                    {
                      Label: values(labels:labels(
                        $concept.Name,
                        $labels:STANDARD_LABEL_ROLE,
                        $language,
                        $concept,
                        (),
                        ()
                      ))
                    },
                    project($concept, ("Name", "Origin")),
                    {
                      Labels: backend:url("labels", {|
                        {
                          token: $token,
                          concept: $original-name,
                          aid: $archive,
                          section: $role,
                          format: $format,
                          profile-name: $profile-name,
                          language: $language
                        }
                      |}),
                      Facts:
                        if($concept.Kind eq "Concept")
                        then backend:url("facts", {|
                          {
                            token: $token,
                            "xbrl:Concept": $original-name,
                            aid: $archive,
                            format: $format,
                            profile-name: $profile-name,
                            language: $language
                          },
                          {
                            fiscalYear: "ALL",
                            fiscalPeriod: "ALL",
                            fiscalPeriodType: "ALL"
                          }[$profile-name = ("sec", "japan")]
                        |})
                        else "None"
                    },
                    trim($concept, ("Origin", "_id", "Archive", "Role", "Name",  "Label", "Labels", "IsAbstract", "SubstitutionGroup")),
                    $metadata,
                    $metadata-sec
                |}
        ]
    }
let $comment := {
    NumConcepts: count($result.ReportElements[]),
    TotalNumConcepts: session:num-concepts()
}
let $serializers := {
    to-xml : function($res as object) as node() {
        <ReportElements>{
          if ($onlyNames)
          then
            <ReportElement>{
              for $c in $res.ReportElements[]
              return <Name>{$c}</Name>
            }</ReportElement>
          else api:json-to-xml($res.ReportElements[], "ReportElement")
        }</ReportElements>
    },
    to-csv : function($res as object) as string {
      if ($onlyNames)
      then
          string-join(("Name", $res.ReportElements[]), "
")
      else
          api:json-to-csv($res.ReportElements[])
    }
}
let $results := api:serialize($result, $comment, $serializers, $format, "report-elements")
return switch(true)
       case $entities-not-found return api:not-found("entity")
       case $archives-not-found return api:not-found("archive")
       default return api:check-and-return-results($token, $results, $format)