:bug: Fix a bug that only fetched one single entity.

jsoniq version "1.0";
(:
 : Copyright 2013 28msec Inc.
 :)

(:~
 :
This module provides functions for retrieving information about entities.
 : Entities submit archives (see archives module),
 : for example, to a reporting authority. Entities
 : are identified with an EID (Entity ID).

 :
 :
With this module, you can retrieve all entities, or a certain number of entities
 : with their EIDs, or obtain the EID of entities you already have.

 :
 :
Entities are stored in a MongoDB datasource called xbrl.

 :
 :
Each entity can be associated with a set of tags that makes it easier
 : to manage them. The e:entities#1 function
 : allows to retrieve all entities with a given tag.

 :
 : @author Charles Hoffman
 : @author Matthias Brantner
 : @author Dennis Knochenwefel
 : @author Ghislain Fourny
 :
 :)
module namespace entities = "http://28.io/modules/xbrl/entities";

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

declare namespace ver = "http://zorba.io/options/versioning";
declare option ver:module-version "1.0";

(:~
 : Name of the collection the entities are stored in.
 :)
declare variable $entities:col as string := "entities";

(:~
 :
Return all entities.

 :
 : @return all entities.
 :)
declare function entities:entities() as object*
{
  mw:find($entities:col, {})
};

(:~
 :
Return the entities with the given EIDs.

 :
 : @param $entities-or-ids the ids of the entities (EIDs) or the entities themselves.
 :
 : @return the entities with the given EIDs
 :         the empty sequence if no entity was found or if the input is an
 : empty sequence.
 :)
declare function entities:entities($entities-or-ids as item*) as object*
{
  let $ids as string* :=
    for $s in $entities-or-ids
    where $s instance of string
    return entities:eid($s)
  let $entities as object* :=
    for $s in $entities-or-ids
    where $s instance of object
    return $s
  return
    (
      $entities,
      if (exists($ids))
      then mw:find($entities:col, {
        "$or" : [
          { "_id" : [ $ids ] },
          { "EIDs" : [ $ids ] }
        ]
      })
      else ()
    )
};

(:~
 :
 :
Converts the input to a normalized entity identifier (EID). The input
 : can be either an EID, or an entity object which contains an _id.

 :
 : @param $entity-or-id a sequence of entity objects or EIDs.
 :
 : @error entities:INVALID_PARAMETER if the EID or entity is not valid.
 :
 : @return the normalized EIDs.
 :)
declare function entities:eid($entities-or-ids as item*) as atomic*
{
  distinct-values(
    for $entity-or-id in $entities-or-ids
    return
    typeswitch ($entity-or-id)
    case $entity as object return
      let $id := ($entity._id[empty($entity.EIDs)], $entity.EIDs[])
      return if(exists($id))
             then $id
             else error(QName("entities:INVALID_PARAMETER"),
                        "Invalid entity provided (no _id or EIDs field)")
    case $id as atomic return $id
    default return error(
        QName("entities:INVALID_PARAMETER"),
        "Invalid entity or id (must be an object or an atomic): "
        || serialize($entity-or-id))
  )
};

jsoniq version "1.0";
(:
 : Copyright 2013 28msec Inc.
 :)

(:~
 :
This module provides functions for retrieving information about entities.
 : Entities submit archives (see archives module),
 : for example, to a reporting authority. Entities
 : are identified with an EID (Entity ID).

 :
 :
With this module, you can retrieve all entities, or a certain number of entities
 : with their EIDs, or obtain the EID of entities you already have.

 :
 :
Entities are stored in a MongoDB datasource called xbrl.

 :
 :
Each entity can be associated with a set of tags that makes it easier
 : to manage them. The e:entities#1 function
 : allows to retrieve all entities with a given tag.

 :
 : @author Charles Hoffman
 : @author Matthias Brantner
 : @author Dennis Knochenwefel
 : @author Ghislain Fourny
 :
 :)
module namespace entities = "http://28.io/modules/xbrl/entities";

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

declare namespace ver = "http://zorba.io/options/versioning";
declare option ver:module-version "1.0";

(:~
 : Name of the collection the entities are stored in.
 :)
declare variable $entities:col as string := "entities";

(:~
 :
Return all entities.

 :
 : @return all entities.
 :)
declare function entities:entities() as object*
{
  mw:find($entities:col, {})
};

(:~
 :
Return the entities with the given EIDs.

 :
 : @param $entities-or-ids the ids of the entities (EIDs) or the entities themselves.
 :
 : @return the entities with the given EIDs
 :         the empty sequence if no entity was found or if the input is an
 : empty sequence.
 :)
declare function entities:entities($entities-or-ids as item*) as object*
{
  let $ids as string* :=
    for $s in $entities-or-ids
    where $s instance of string
    return entities:eid($s)
  let $entities as object* :=
    for $s in $entities-or-ids
    where $s instance of object
    return $s
  return
    (
      $entities,
      if (exists($ids))
      then mw:find($entities:col, {
        "$or" : [
          { "_id" : [ $ids ] },
          { "EIDs" : [ $ids ] }
        ]
      })[1]
      else ()
    )
};

(:~
 :
 :
Converts the input to a normalized entity identifier (EID). The input
 : can be either an EID, or an entity object which contains an _id.

 :
 : @param $entity-or-id a sequence of entity objects or EIDs.
 :
 : @error entities:INVALID_PARAMETER if the EID or entity is not valid.
 :
 : @return the normalized EIDs.
 :)
declare function entities:eid($entities-or-ids as item*) as atomic*
{
  distinct-values(
    for $entity-or-id in $entities-or-ids
    return
    typeswitch ($entity-or-id)
    case $entity as object return
      let $id := ($entity._id[empty($entity.EIDs)], $entity.EIDs[])
      return if(exists($id))
             then $id
             else error(QName("entities:INVALID_PARAMETER"),
                        "Invalid entity provided (no _id or EIDs field)")
    case $id as atomic return $id
    default return error(
        QName("entities:INVALID_PARAMETER"),
        "Invalid entity or id (must be an object or an atomic): "
        || serialize($entity-or-id))
  )
};


Update filings.jq

Update filings.jq


:pencil: Add test.

:pencil: Add test.

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

test:check-all-success({
    entityNotFound: test:invoke-and-assert-status(
          "facts",
          {
              concept: [ "tse-ed-t:DividendPerShare" ],
              eid: "http://www.example.or.jp/doesntexist 666",
              format:"csv",
              fiscalYear: 2013
          },
          404
        ),
    swaggerExample1: test:invoke-and-assert-deep-equal(
          "facts",
          {
              "xbrl:Entity":"http://disclosure.edinet-fsa.go.jp E02529-000",
              "fsa:FiscalYear": 2014,
              "fsa:FiscalPeriod": "Q1",
              concept: [ "jpcrp-cor:TotalAssetsIFRSSummaryOfBusinessResults",
                         "jpcrp-cor:ProfitLossAttributableToOwnersOfParentIFRSSummaryOfBusinessResults"]
          },
          function($res as item*) as item* { count($res.FactTable[]) },
          2
        ),
    swaggerExample2: test:invoke-and-assert-deep-equal(
          "facts",
          {
              "xbrl:Entity": "http://disclosure.edinet-fsa.go.jp E02529-000",
              "fiscalPeriod": "Q2",
              "fiscalYear": 2014,
              "concept": ["jpcrp-cor:NumberOfSharesHeld", "jpcrp-cor:ShareholdingRatio"],
              "jpcrp-cor:MajorShareholdersAxis": "ALL",
              "jpcrp-cor:MajorShareholdersAxis::default": "NONE"
          },
          function($res as item*) as item* { count($res.FactTable[]) },
          22
        ),
    inter-generation: test:invoke-and-assert-deep-equal(
          "facts",
          {
              "edinetcode" : "E04147",
              "fiscalPeriod": "FY",
              "fiscalYear": [ (2008 to 2013) ! string($$) ],
              "concept": ["jppfs-cor:Assets", "jp-t-cte:Assets"],
              "jppfs-cor:ConsolidatedOrNonConsolidatedAxis": "ALL",
              "xbrl:Scenario": "ALL"
          },
          function($res as item*) as item* { count($res.FactTable[]) },
          15
        ),
    open: test:invoke-and-assert-deep-equal(
          "facts",
          {
              "ticker" : "7751",
              "fiscalPeriod": "FY",
              "fiscalYear": 2014,
              "concept": "tse-ed-t:DividendPerShare",
              "open" : "true"
          },
          function($res as item*) as item* { count($res.FactTable[]) },
          69
        )
})

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

test:check-all-success({
    entityNotFound: test:invoke-and-assert-status(
          "facts",
          {
              concept: [ "tse-ed-t:DividendPerShare" ],
              eid: "http://www.example.or.jp/doesntexist 666",
              format:"csv",
              fiscalYear: 2013
          },
          404
        ),
    swaggerExample1: test:invoke-and-assert-deep-equal(
          "facts",
          {
              "xbrl:Entity":"http://disclosure.edinet-fsa.go.jp E02529-000",
              "fsa:FiscalYear": 2014,
              "fsa:FiscalPeriod": "Q1",
              concept: [ "jpcrp-cor:TotalAssetsIFRSSummaryOfBusinessResults",
                         "jpcrp-cor:ProfitLossAttributableToOwnersOfParentIFRSSummaryOfBusinessResults"]
          },
          function($res as item*) as item* { count($res.FactTable[]) },
          2
        ),
    swaggerExample2: test:invoke-and-assert-deep-equal(
          "facts",
          {
              "xbrl:Entity": "http://disclosure.edinet-fsa.go.jp E02529-000",
              "fiscalPeriod": "Q2",
              "fiscalYear": 2014,
              "concept": ["jpcrp-cor:NumberOfSharesHeld", "jpcrp-cor:ShareholdingRatio"],
              "jpcrp-cor:MajorShareholdersAxis": "ALL",
              "jpcrp-cor:MajorShareholdersAxis::default": "NONE"
          },
          function($res as item*) as item* { count($res.FactTable[]) },
          22
        ),
    inter-generation: test:invoke-and-assert-deep-equal(
          "facts",
          {
              "edinetcode" : "E04147",
              "fiscalPeriod": "FY",
              "fiscalYear": [ (2008 to 2013) ! string($$) ],
              "concept": ["jppfs-cor:Assets", "jp-t-cte:Assets"],
              "jppfs-cor:ConsolidatedOrNonConsolidatedAxis": "ALL",
              "xbrl:Scenario": "ALL"
          },
          function($res as item*) as item* { count($res.FactTable[]) },
          15
        )
})


Fixed warning.

Fixed warning.

import module namespace config = "http://apps.28.io/config";
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/test";

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

import module namespace sec-filings = "http://28.io/modules/xbrl/profiles/sec/filings";
import module namespace sec-networks = "http://28.io/modules/xbrl/profiles/sec/networks";
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 response = "http://www.28msec.com/modules/http-response";

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

declare function local:to-csv($res as object*) as string*
{
    csv:serialize(
        for $a in $res
        for $c in $a.Components[]
        return {
            AcessionNumber : $a.AccessionNumber,
            NetworkIdentifier : $c.NetworkIdentifier,
            FactTable: $c.FactTable,
            SpreadSheet: $c.SpreadSheet,
            EntityRegistrantName : $a.EntityRegistrantName,
            CIK : $a.CIK,
            FiscalYear : $a.FiscalYear,
            FiscalPeriod : $a.FiscalPeriod,
            AcceptanceDateTime : $a.AcceptanceDatetime,
            FormType : $a.FormType,
            NetworkLabel : $c.NetworkLabel,
            Category : $c.Category,
            SubCategory : $c.SubCategory,
            Table : flatten($c.Table),
            Disclosure : $c.Disclosure,
            ReportElements : $c.ReportElements,
            Tables : $c.Tables,
            Axis : $c.Axis,
            Members : $c.Members,
            LineItems : $c.LineItems,
            Concepts : $c.Concepts,
            Abstracts : $c.Abstracts
        },
    { serialize-null-as : "" })
};

declare function local:to-csv-generic($res as object*) as string*
{
    csv:serialize(
        for $a in $res
        return {
            Archive: $a.Archive,
            Role: $a.Role,
            FactTable: $a.FactTable,
            SpreadSheet: $a.SpreadSheet,
            NumRules: $a.NumRules,
            NumNetworks: $a.NumNetworks,
            NumHypercubes: size($a.Hypercubes)
        },
    { serialize-null-as : "" })
};

(: Query parameters :)
declare  %rest:case-insensitive                 variable $token              as string? external;
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 $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 := "LATEST";
declare  %rest:case-insensitive %rest:distinct  variable $fiscalPeriod       as string* external := "FY";
declare  %rest:case-insensitive %rest:distinct  variable $aid                as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $networkIdentifier  as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $role               as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $cid                as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $reportElement      as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $concept            as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $disclosure         as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $label              as string* external;
declare  %rest:case-insensitive                 variable $profile-name       as string  external := $config:profile-name;

session:audit-call($token);

(: 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 $reportElement := ($reportElement, $concept)
let $networkIdentifier := distinct-values(($networkIdentifier, $role))

(: Object resolution :)
let $entities :=
    companies:companies(
        $cik,
        $tag,
        $ticker,
        $sic)
let $archives as object* := fiscal-core:filings(
    $entities,
    $fiscalPeriod,
    $fiscalYear,
    $aid)
let $entities as object*  := entities:entities($archives.Entity)
let $components as object* :=
    switch($profile-name)
    case "sec" return sec-networks:components(
        $archives,
        $cid,
        $reportElement,
        $disclosure,
        $networkIdentifier,
        $label)
    default return
        switch(true)
        case (exists($networkIdentifier) and exists($aid))
        return components:components-for-archives-and-roles($aid, $networkIdentifier)
        case exists($aid)
        return components:components-for-archives($aid)
        default
        return if($profile-name eq "sec") then {
          response:status-code(400);
          session:error("Archive ID missing.", $format)
        } else components:components()
let $res as object* :=
    switch($profile-name)
    case "sec" return
        for $r in $components
        let $disclosure := sec-networks:disclosures($r)
        where $disclosure ne "DefaultComponent"
        order by $r.Label
        group by $archive := $r.Archive
        let $archive := $archives[$$._id eq $archive]
        let $e := $entities[$$._id eq $archive.Entity]
        return
            {
               AccessionNumber : $archive._id,
               EntityRegistrantName : $e.Profiles.SEC.CompanyName,
               CIK : $e._id,
               FiscalYear :$archive.Profiles.SEC.Fiscal.DocumentFiscalYearFocus,
               FiscalPeriod :$archive.Profiles.SEC.Fiscal.DocumentFiscalPeriodFocus,
               AcceptanceDatetime : sec-filings:acceptance-dateTimes($archive),
               FormType : $archive.Profiles.SEC.FormType,
               Components : [
                    for $component in sec-networks:summaries($r)
                    return copy $c := $component
                    modify insert json {
                        FactTable: backend:url("facttable-for-component", {
                            aid: $archive._id,
                            format: $format,
                            role: $component.NetworkIdentifier,
                            profile-name: $profile-name
                            }, true),
                        SpreadSheet: "http://rendering.secxbrl.info/#?url=" || encode-for-uri(
                            backend:url("spreadsheet-for-component", {
                            aid: $archive._id,
                            format: $format,
                            role: $component.NetworkIdentifier,
                            profile-name: $profile-name
                            }, true)
                        )
                    } into $c
                    return $c
               ]
           }
    default return
        for $r in $components
        return {
            Archive: $r.Archive,
            Role: $r.Role,
            NumRules: size($r.Rules),
            NumNetworks: size($r.Networks),
            Hypercubes: [ keys($r.Hypercubes) ],
            FactTable: backend:url("facttable-for-component", {
                            aid: $r.Archive,
                            format: $format,
                            role: $r.Role,
                            profile-name: $profile-name
                            }, true),
            SpreadSheet: "http://rendering.secxbrl.info/#?url=" || encode-for-uri(
                        backend:url("spreadsheet-for-component", {
                            aid: $r.Archive,
                            format: $format,
                            role: $r.Role,
                            profile-name: $profile-name
                        }, true))
        }
let $result := switch($profile-name) case "sec" return { Archives: [ $res ] } default return { Components : [ $res ] }
let $comment :=
 {
    NumComponents : count($components),
    TotalNumComponents: session:num-components(),
    TotalNumArchives: session:num-archives()
}
let $serializers := {
    to-xml : switch($profile-name)
        case "sec"
        return function($res as object) as node() {
        <Archives>{
                  for $r in flatten($res.Archives)
                  return
                      <Archive id="{$r.AccessionNumber}">
                         <EntityRegistrantName>{$r.EntityRegistrantName}</EntityRegistrantName>
                         <CIK>{$r.CIK}</CIK>
                         <FiscalYear>{$r.FiscalYear}</FiscalYear>
                         <FiscalPeriod>{$r.FiscalPeriod}</FiscalPeriod>
                         <AcceptanceDatetime>{$r.AcceptanceDatetime}</AcceptanceDatetime>
                         <FormType>{$r.FormType}</FormType>
                         <Components>{
                             sec-networks:summaries-to-xml(flatten($r.Components))
                         }</Components>
                     </Archive>
             }</Archives>
        }
        default return function($res as object) as node() {
        <Components>{
                  for $r in $res.Components[]
                  return
                    <Component>
                         <Archive>{$r.Archive}</Archive>
                         <Role>{$r.Role}</Role>
                         <NumRules>{$r.NumRules}</NumRules>
                         <NumNetworks>{$r.NumNetworks}</NumNetworks>
                         <Hypercubes>{$r.Hypercubes[] ! <Hypercube>{$$}</Hypercube>}</Hypercubes>
                    </Component>
             }</Components>
    },
    to-csv : function($res as object) as string {
        switch($profile-name)
        case "sec" return string-join(local:to-csv($res.Archives[]), "")
        default return string-join(local:to-csv-generic($res.Components[]), "")
    }
}

let $results := api:serialize($result, $comment, $serializers, $format, "components")
return api:check-and-return-results($token, $results, $format)

import module namespace config = "http://apps.28.io/config";
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/test";

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

import module namespace sec-filings = "http://28.io/modules/xbrl/profiles/sec/filings";
import module namespace sec-networks = "http://28.io/modules/xbrl/profiles/sec/networks";
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 http-request = "http://www.28msec.com/modules/http/request";

import module namespace response = "http://www.28msec.com/modules/http-response";

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

declare function local:to-csv($res as object*) as string*
{
    csv:serialize(
        for $a in $res
        for $c in $a.Components[]
        return {
            AcessionNumber : $a.AccessionNumber,
            NetworkIdentifier : $c.NetworkIdentifier,
            FactTable: $c.FactTable,
            SpreadSheet: $c.SpreadSheet,
            EntityRegistrantName : $a.EntityRegistrantName,
            CIK : $a.CIK,
            FiscalYear : $a.FiscalYear,
            FiscalPeriod : $a.FiscalPeriod,
            AcceptanceDateTime : $a.AcceptanceDatetime,
            FormType : $a.FormType,
            NetworkLabel : $c.NetworkLabel,
            Category : $c.Category,
            SubCategory : $c.SubCategory,
            Table : flatten($c.Table),
            Disclosure : $c.Disclosure,
            ReportElements : $c.ReportElements,
            Tables : $c.Tables,
            Axis : $c.Axis,
            Members : $c.Members,
            LineItems : $c.LineItems,
            Concepts : $c.Concepts,
            Abstracts : $c.Abstracts
        },
    { serialize-null-as : "" })
};

declare function local:to-csv-generic($res as object*) as string*
{
    csv:serialize(
        for $a in $res
        return {
            Archive: $a.Archive,
            Role: $a.Role,
            FactTable: $a.FactTable,
            SpreadSheet: $a.SpreadSheet,
            NumRules: $a.NumRules,
            NumNetworks: $a.NumNetworks,
            NumHypercubes: size($a.Hypercubes)
        },
    { serialize-null-as : "" })
};

(: Query parameters :)
declare  %rest:case-insensitive                 variable $token              as string? external;
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 $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 := "LATEST";
declare  %rest:case-insensitive %rest:distinct  variable $fiscalPeriod       as string* external := "FY";
declare  %rest:case-insensitive %rest:distinct  variable $aid                as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $networkIdentifier  as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $role               as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $cid                as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $reportElement      as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $concept            as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $disclosure         as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $label              as string* external;
declare  %rest:case-insensitive                 variable $profile-name       as string  external := $config:profile-name;

session:audit-call($token);

(: 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 $reportElement := ($reportElement, $concept)
let $networkIdentifier := distinct-values(($networkIdentifier, $role))

(: Object resolution :)
let $entities :=
    companies:companies(
        $cik,
        $tag,
        $ticker,
        $sic)
let $archives as object* := fiscal-core:filings(
    $entities,
    $fiscalPeriod,
    $fiscalYear,
    $aid)
let $entities as object*  := entities:entities($archives.Entity)
let $components as object* :=
    switch($profile-name)
    case "sec" return sec-networks:components(
        $archives,
        $cid,
        $reportElement,
        $disclosure,
        $networkIdentifier,
        $label)
    default return
        switch(true)
        case (exists($networkIdentifier) and exists($aid))
        return components:components-for-archives-and-roles($aid, $networkIdentifier)
        case exists($aid)
        return components:components-for-archives($aid)
        default
        return if($profile-name eq "sec") then {
          response:status-code(400);
          session:error("Archive ID missing.", $format)
        } else components:components()
let $res as object* :=
    switch($profile-name)
    case "sec" return
        for $r in $components
        let $disclosure := sec-networks:disclosures($r)
        where $disclosure ne "DefaultComponent"
        order by $r.Label
        group by $archive := $r.Archive
        let $archive := $archives[$$._id eq $archive]
        let $e := $entities[$$._id eq $archive.Entity]
        return
            {
               AccessionNumber : $archive._id,
               EntityRegistrantName : $e.Profiles.SEC.CompanyName,
               CIK : $e._id,
               FiscalYear :$archive.Profiles.SEC.Fiscal.DocumentFiscalYearFocus,
               FiscalPeriod :$archive.Profiles.SEC.Fiscal.DocumentFiscalPeriodFocus,
               AcceptanceDatetime : sec-filings:acceptance-dateTimes($archive),
               FormType : $archive.Profiles.SEC.FormType,
               Components : [
                    for $component in sec-networks:summaries($r)
                    return copy $c := $component
                    modify insert json {
                        FactTable: backend:url("facttable-for-component", {
                            aid: $archive._id,
                            format: $format,
                            role: $component.NetworkIdentifier,
                            profile-name: $profile-name
                            }, true),
                        SpreadSheet: "http://rendering.secxbrl.info/#?url=" || encode-for-uri(
                            backend:url("spreadsheet-for-component", {
                            aid: $archive._id,
                            format: $format,
                            role: $component.NetworkIdentifier,
                            profile-name: $profile-name
                            }, true)
                        )
                    } into $c
                    return $c
               ]
           }
    default return
        for $r in $components
        return {
            Archive: $r.Archive,
            Role: $r.Role,
            NumRules: size($r.Rules),
            NumNetworks: size($r.Networks),
            Hypercubes: [ keys($r.Hypercubes) ],
            FactTable: backend:url("facttable-for-component", {
                            aid: $r.Archive,
                            format: $format,
                            role: $r.Role,
                            profile-name: $profile-name
                            }, true),
            SpreadSheet: "http://rendering.secxbrl.info/#?url=" || encode-for-uri(
                        backend:url("spreadsheet-for-component", {
                            aid: $r.Archive,
                            format: $format,
                            role: $r.Role,
                            profile-name: $profile-name
                        }, true))
        }
let $result := switch($profile-name) case "sec" return { Archives: [ $res ] } default return { Components : [ $res ] }
let $comment :=
 {
    NumComponents : count($components),
    TotalNumComponents: session:num-components(),
    TotalNumArchives: session:num-archives()
}
let $serializers := {
    to-xml : switch($profile-name)
        case "sec"
        return function($res as object) as node() {
        <Archives>{
                  for $r in flatten($res.Archives)
                  return
                      <Archive id="{$r.AccessionNumber}">
                         <EntityRegistrantName>{$r.EntityRegistrantName}</EntityRegistrantName>
                         <CIK>{$r.CIK}</CIK>
                         <FiscalYear>{$r.FiscalYear}</FiscalYear>
                         <FiscalPeriod>{$r.FiscalPeriod}</FiscalPeriod>
                         <AcceptanceDatetime>{$r.AcceptanceDatetime}</AcceptanceDatetime>
                         <FormType>{$r.FormType}</FormType>
                         <Components>{
                             sec-networks:summaries-to-xml(flatten($r.Components))
                         }</Components>
                     </Archive>
             }</Archives>
        }
        default return function($res as object) as node() {
        <Components>{
                  for $r in $res.Components[]
                  return
                    <Component>
                         <Archive>{$r.Archive}</Archive>
                         <Role>{$r.Role}</Role>
                         <NumRules>{$r.NumRules}</NumRules>
                         <NumNetworks>{$r.NumNetworks}</NumNetworks>
                         <Hypercubes>{$r.Hypercubes[] ! <Hypercube>{$$}</Hypercube>}</Hypercubes>
                    </Component>
             }</Components>
    },
    to-csv : function($res as object) as string {
        switch($profile-name)
        case "sec" return string-join(local:to-csv($res.Archives[]), "")
        default return string-join(local:to-csv-generic($res.Components[]), "")
    }
}

let $results := api:serialize($result, $comment, $serializers, $format, "components")
return api:check-and-return-results($token, $results, $format)