@milaboratories/pl-model-common 1.25.3 → 1.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/drivers/pframe/query/query_spec.d.ts +2 -2
- package/dist/drivers/pframe/spec/anchored.cjs +58 -0
- package/dist/drivers/pframe/spec/anchored.cjs.map +1 -1
- package/dist/drivers/pframe/spec/anchored.d.ts +3 -0
- package/dist/drivers/pframe/spec/anchored.js +58 -0
- package/dist/drivers/pframe/spec/anchored.js.map +1 -1
- package/dist/drivers/pframe/spec/native_id.cjs +1 -0
- package/dist/drivers/pframe/spec/native_id.cjs.map +1 -1
- package/dist/drivers/pframe/spec/native_id.js +1 -0
- package/dist/drivers/pframe/spec/native_id.js.map +1 -1
- package/dist/drivers/pframe/spec/selectors.cjs +8 -0
- package/dist/drivers/pframe/spec/selectors.cjs.map +1 -1
- package/dist/drivers/pframe/spec/selectors.d.ts +13 -0
- package/dist/drivers/pframe/spec/selectors.js +8 -0
- package/dist/drivers/pframe/spec/selectors.js.map +1 -1
- package/dist/drivers/pframe/spec/spec.cjs +7 -2
- package/dist/drivers/pframe/spec/spec.cjs.map +1 -1
- package/dist/drivers/pframe/spec/spec.d.ts +13 -1
- package/dist/drivers/pframe/spec/spec.js +7 -2
- package/dist/drivers/pframe/spec/spec.js.map +1 -1
- package/dist/pool/query.cjs +1 -1
- package/dist/pool/query.cjs.map +1 -1
- package/dist/pool/query.js +1 -1
- package/dist/pool/query.js.map +1 -1
- package/dist/pool/spec.cjs.map +1 -1
- package/dist/pool/spec.d.ts +4 -1
- package/dist/pool/spec.js.map +1 -1
- package/package.json +3 -3
- package/src/drivers/pframe/query/query_spec.ts +2 -2
- package/src/drivers/pframe/query/utils.test.ts +2 -2
- package/src/drivers/pframe/spec/anchored.ts +73 -0
- package/src/drivers/pframe/spec/native_id.ts +1 -0
- package/src/drivers/pframe/spec/selectors.ts +28 -0
- package/src/drivers/pframe/spec/spec.ts +33 -3
- package/src/pool/query.ts +6 -0
- package/src/pool/spec.ts +4 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selectors.js","names":[],"sources":["../../../../src/drivers/pframe/spec/selectors.ts"],"sourcesContent":["import { isPColumnSpec, type PObjectSpec } from \"../../../pool\";\nimport type { AxisId, AxisValueType, Domain, PColumnSpec, ValueType } from \"./spec\";\nimport { getAxisId } from \"./spec\";\n\n/**\n * Defines a pattern for matching axes within the PFrame data model.\n *\n * AxisSelector provides a flexible way to identify axes based on their\n * properties. All fields are optional, allowing for partial matching.\n * When multiple properties are specified, all must match for an axis\n * to be selected (logical AND).\n *\n * This interface is used in various selection and matching operations\n * throughout the PFrame system, such as column queries and axis lookups.\n */\nexport interface AxisSelector {\n /**\n * Optional value type to match against.\n * When specified, only axes with this exact type will match.\n * Can be a single type or an array of types to match against any of them.\n * Valid types include: 'Int', 'Long', 'Float', 'Double', 'String', 'Bytes'.\n */\n type?: ValueType | ValueType[];\n\n /**\n * Optional name to match against.\n * When specified, only axes with this exact name will match.\n */\n name?: string;\n\n /**\n * Optional domain key-value pairs to match against.\n * Domains provide additional context to uniquely identify an axis beyond its name and type.\n * When specified, an axis will match only if it contains all the key-value pairs defined here.\n * An axis with additional domain entries not present in this selector will still match.\n */\n domain?: Record<string, string>;\n}\n\n/** Single axis selector */\nexport interface SingleAxisSelector {\n /** Axis name (required) */\n name: string;\n /** Axis type (optional) */\n type?: AxisValueType;\n /** Domain requirements (optional) */\n domain?: Domain;\n /** Parent axes requirements (optional) */\n parentAxes?: SingleAxisSelector[];\n}\n\n/**\n * Reference to an axis by its numerical index within the anchor column's axes array\n * Format: [anchorId, axisIndex]\n */\nexport type AnchorAxisRefByIdx = { anchor: string; idx: number };\n\n/**\n * Reference to an axis by its name within the anchor column\n * Format: [anchorId, axisName]\n */\nexport type AnchorAxisRefByName = { anchor: string; name: string };\n\n/**\n * Reference to an axis using an AxisId matcher within the anchor\n * Format: [anchorId, axisMatcher]\n */\nexport type AnchorAxisRefByMatcher = { anchor: string; id: AxisId };\n\n/**\n * Basic anchor axis reference that can be either by index or a direct AxisId\n */\nexport type AnchorAxisIdOrRefBasic = AnchorAxisRefByIdx | AxisId;\n\n/** Union of all possible ways to reference an axis in an anchored context */\nexport type AnchorAxisRef = AnchorAxisRefByIdx | AnchorAxisRefByName | AnchorAxisRefByMatcher;\n\n/** Reference to a domain value through an anchor */\nexport type AnchorDomainRef = { anchor: string };\n\n/**\n * Domain value that can be either a direct string value or a reference to a domain through an anchor\n * Used to establish domain context that can be resolved relative to other anchored columns\n */\nexport type ADomain = string | AnchorDomainRef;\n/**\n * Axis identifier that can be either a direct AxisId or a reference to an axis through an anchor\n * Allows referring to axes in a way that can be resolved in different contexts\n */\nexport type AAxisSelector = AxisSelector | AnchorAxisRef;\n\n/**\n * Match resolution strategy for PColumns\n * Specifies how to handle when multiple columns match the criteria\n * (default is \"expectSingle\")\n */\nexport type AnchoredColumnMatchStrategy = \"expectSingle\" | \"expectMultiple\" | \"takeFirst\";\n\n/**\n * Matcher for PColumns in an anchored context\n * Supports partial matching on axes, allowing for flexible column discovery\n */\nexport interface AnchoredPColumnSelector {\n /** Optional name of the column to match; can't be used together with namePattern */\n name?: string;\n /** Optional regexp pattern for column name matching; can't be used together with name */\n namePattern?: string;\n /** Optional value type to match. If an array is provided, matches if the column's type is any of the specified types */\n type?: ValueType | ValueType[];\n /** If specified, the domain values must be anchored to this anchor */\n domainAnchor?: string;\n /** Optional domain values to match, can include anchored references, if domainAnchor is specified,\n * interpreted as additional domains to domain from the anchor */\n domain?: Record<string, ADomain>;\n /** Optional axes to match, can include anchored references */\n axes?: AAxisSelector[];\n /** When true, allows matching if only a subset of axes match */\n partialAxesMatch?: boolean;\n /** Optional annotations to match with exact values */\n annotations?: Record<string, string>;\n /** Optional annotation patterns to match with regex patterns */\n annotationPatterns?: Record<string, string>;\n /** Match resolution strategy, default is \"expectSingle\" */\n matchStrategy?: AnchoredColumnMatchStrategy;\n}\n\n/**\n * Matcher for PColumns in a non-anchored context\n */\nexport interface PColumnSelector extends AnchoredPColumnSelector {\n domainAnchor?: never;\n domain?: Record<string, string>;\n axes?: AxisSelector[];\n}\n\n/**\n * Strict identifier for PColumns in an anchored context\n * Unlike APColumnMatcher, this requires exact matches on domain and axes\n */\nexport interface AnchoredPColumnId extends AnchoredPColumnSelector {\n /** Name is required for exact column identification */\n name: string;\n /** No namePattern in ID */\n namePattern?: never;\n /** Type is not used in exact column identification */\n type?: never;\n /** Full axes specification using only basic references */\n axes: AnchorAxisIdOrRefBasic[];\n /** Partial axes matching is not allowed for exact identification */\n partialAxesMatch?: never;\n /** Annotations are not used in exact column identification */\n annotations?: never;\n /** Annotation patterns are not used in exact column identification */\n annotationPatterns?: never;\n /** \"Id\" implies single match strategy */\n matchStrategy?: never;\n}\n\n/**\n * Checks if a given value is an anchored column identifier\n * @param id - The value to check\n * @returns True if the value is an anchored column identifier, false otherwise\n */\nexport function isAnchoredPColumnId(id: unknown): id is AnchoredPColumnId {\n // basic check, can be extended if needed\n return typeof id === \"object\" && id !== null && \"name\" in id && \"axes\" in id;\n}\n\n/**\n * Determines if an axis ID matches an axis selector.\n *\n * @param selector - The selector with criteria to match against\n * @param axis - The AxisId to check against the selector\n * @returns true if the AxisId matches all specified criteria in the selector, false otherwise\n */\nexport function matchAxis(selector: AxisSelector, axis: AxisId): boolean {\n // Match name if specified\n if (selector.name !== undefined && selector.name !== axis.name) return false;\n\n // Match type if specified\n if (selector.type !== undefined) {\n if (Array.isArray(selector.type)) {\n if (!selector.type.includes(axis.type)) return false;\n } else if (selector.type !== axis.type) {\n return false;\n }\n }\n\n // Match domain if specified - using existing logic from matchAxisId\n if (selector.domain !== undefined) {\n const axisDomain = axis.domain || {};\n for (const [key, value] of Object.entries(selector.domain))\n if (axisDomain[key] !== value) return false;\n }\n\n return true;\n}\n\n/**\n * Determines if a given PColumnSpec matches a selector.\n *\n * @param pcolumn - The PColumnSpec to check against the selector\n * @param selector - The selector criteria to match against\n * @returns true if the PColumnSpec matches all criteria in the selector, false otherwise\n */\nexport function matchPColumn(pcolumn: PColumnSpec, selector: PColumnSelector): boolean {\n // Match name if specified\n if (selector.name !== undefined && pcolumn.name !== selector.name) return false;\n\n // Match name pattern if specified\n if (selector.namePattern !== undefined && !new RegExp(selector.namePattern).test(pcolumn.name))\n return false;\n\n // Match type if specified\n if (selector.type !== undefined) {\n if (Array.isArray(selector.type)) {\n if (!selector.type.includes(pcolumn.valueType)) return false;\n } else if (selector.type !== pcolumn.valueType) {\n return false;\n }\n }\n\n // Match domain if specified\n if (selector.domain !== undefined) {\n const columnDomain = pcolumn.domain || {};\n for (const [key, value] of Object.entries(selector.domain))\n if (columnDomain[key] !== value) return false;\n }\n\n // Match axes if specified\n if (selector.axes !== undefined) {\n const pcolumnAxes = pcolumn.axesSpec.map(getAxisId);\n\n if (selector.partialAxesMatch) {\n // For partial matching, all selector axes must match at least one column axis\n for (const selectorAxis of selector.axes)\n if (!pcolumnAxes.some((columnAxis) => matchAxis(selectorAxis, columnAxis))) return false;\n } else {\n // For exact matching, column must have the same number of axes and all must match\n if (pcolumnAxes.length !== selector.axes.length) return false;\n\n // Each selector axis must match a corresponding column axis\n for (let i = 0; i < selector.axes.length; i++)\n if (!matchAxis(selector.axes[i], pcolumnAxes[i])) return false;\n }\n }\n\n // Match annotations if specified\n if (selector.annotations !== undefined) {\n const columnAnnotations = pcolumn.annotations || {};\n for (const [key, value] of Object.entries(selector.annotations))\n if (columnAnnotations[key] !== value) return false;\n }\n\n // Match annotation patterns if specified\n if (selector.annotationPatterns !== undefined) {\n const columnAnnotations = pcolumn.annotations || {};\n for (const [key, pattern] of Object.entries(selector.annotationPatterns)) {\n const value = columnAnnotations[key];\n if (value === undefined || !new RegExp(pattern).test(value)) return false;\n }\n }\n\n return true;\n}\n\n/**\n * Convert a predicate or array of selectors to a single predicate function\n * @param predicateOrSelectors - Either a function that takes a PColumnSpec and returns a boolean,\n * or an array of PColumnSelectors, or a single PColumnSelector\n * @returns A function that takes a PColumnSpec and returns a boolean\n */\nexport function selectorsToPredicate(\n predicateOrSelectors: PColumnSelector | PColumnSelector[],\n): (spec: PObjectSpec) => boolean {\n if (Array.isArray(predicateOrSelectors))\n return (spec) =>\n predicateOrSelectors.some((selector) => isPColumnSpec(spec) && matchPColumn(spec, selector));\n else return (spec) => isPColumnSpec(spec) && matchPColumn(spec, predicateOrSelectors);\n}\n"],"mappings":";;;;;;;;;AAmKA,SAAgB,oBAAoB,IAAsC;AAExE,QAAO,OAAO,OAAO,YAAY,OAAO,QAAQ,UAAU,MAAM,UAAU;;;;;;;;;AAU5E,SAAgB,UAAU,UAAwB,MAAuB;AAEvE,KAAI,SAAS,SAAS,UAAa,SAAS,SAAS,KAAK,KAAM,QAAO;AAGvE,KAAI,SAAS,SAAS,QACpB;MAAI,MAAM,QAAQ,SAAS,KAAK,EAC9B;OAAI,CAAC,SAAS,KAAK,SAAS,KAAK,KAAK,CAAE,QAAO;aACtC,SAAS,SAAS,KAAK,KAChC,QAAO;;AAKX,KAAI,SAAS,WAAW,QAAW;EACjC,MAAM,aAAa,KAAK,UAAU,EAAE;AACpC,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,OAAO,CACxD,KAAI,WAAW,SAAS,MAAO,QAAO;;AAG1C,QAAO;;;;;;;;;AAUT,SAAgB,aAAa,SAAsB,UAAoC;AAErF,KAAI,SAAS,SAAS,UAAa,QAAQ,SAAS,SAAS,KAAM,QAAO;AAG1E,KAAI,SAAS,gBAAgB,UAAa,CAAC,IAAI,OAAO,SAAS,YAAY,CAAC,KAAK,QAAQ,KAAK,CAC5F,QAAO;AAGT,KAAI,SAAS,SAAS,QACpB;MAAI,MAAM,QAAQ,SAAS,KAAK,EAC9B;OAAI,CAAC,SAAS,KAAK,SAAS,QAAQ,UAAU,CAAE,QAAO;aAC9C,SAAS,SAAS,QAAQ,UACnC,QAAO;;AAKX,KAAI,SAAS,WAAW,QAAW;EACjC,MAAM,eAAe,QAAQ,UAAU,EAAE;AACzC,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,OAAO,CACxD,KAAI,aAAa,SAAS,MAAO,QAAO;;AAI5C,KAAI,SAAS,SAAS,QAAW;EAC/B,MAAM,cAAc,QAAQ,SAAS,IAAI,UAAU;AAEnD,MAAI,SAAS,kBAEX;QAAK,MAAM,gBAAgB,SAAS,KAClC,KAAI,CAAC,YAAY,MAAM,eAAe,UAAU,cAAc,WAAW,CAAC,CAAE,QAAO;SAChF;AAEL,OAAI,YAAY,WAAW,SAAS,KAAK,OAAQ,QAAO;AAGxD,QAAK,IAAI,IAAI,GAAG,IAAI,SAAS,KAAK,QAAQ,IACxC,KAAI,CAAC,UAAU,SAAS,KAAK,IAAI,YAAY,GAAG,CAAE,QAAO;;;AAK/D,KAAI,SAAS,gBAAgB,QAAW;EACtC,MAAM,oBAAoB,QAAQ,eAAe,EAAE;AACnD,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,YAAY,CAC7D,KAAI,kBAAkB,SAAS,MAAO,QAAO;;AAIjD,KAAI,SAAS,uBAAuB,QAAW;EAC7C,MAAM,oBAAoB,QAAQ,eAAe,EAAE;AACnD,OAAK,MAAM,CAAC,KAAK,YAAY,OAAO,QAAQ,SAAS,mBAAmB,EAAE;GACxE,MAAM,QAAQ,kBAAkB;AAChC,OAAI,UAAU,UAAa,CAAC,IAAI,OAAO,QAAQ,CAAC,KAAK,MAAM,CAAE,QAAO;;;AAIxE,QAAO;;;;;;;;AAST,SAAgB,qBACd,sBACgC;AAChC,KAAI,MAAM,QAAQ,qBAAqB,CACrC,SAAQ,SACN,qBAAqB,MAAM,aAAa,cAAc,KAAK,IAAI,aAAa,MAAM,SAAS,CAAC;KAC3F,SAAQ,SAAS,cAAc,KAAK,IAAI,aAAa,MAAM,qBAAqB"}
|
|
1
|
+
{"version":3,"file":"selectors.js","names":[],"sources":["../../../../src/drivers/pframe/spec/selectors.ts"],"sourcesContent":["import { isPColumnSpec, type PObjectSpec } from \"../../../pool\";\nimport type { AxisId, AxisValueType, Domain, PColumnSpec, ValueType } from \"./spec\";\nimport { getAxisId } from \"./spec\";\n\n/**\n * Defines a pattern for matching axes within the PFrame data model.\n *\n * AxisSelector provides a flexible way to identify axes based on their\n * properties. All fields are optional, allowing for partial matching.\n * When multiple properties are specified, all must match for an axis\n * to be selected (logical AND).\n *\n * This interface is used in various selection and matching operations\n * throughout the PFrame system, such as column queries and axis lookups.\n */\nexport interface AxisSelector {\n /**\n * Optional value type to match against.\n * When specified, only axes with this exact type will match.\n * Can be a single type or an array of types to match against any of them.\n * Valid types include: 'Int', 'Long', 'Float', 'Double', 'String', 'Bytes'.\n */\n type?: ValueType | ValueType[];\n\n /**\n * Optional name to match against.\n * When specified, only axes with this exact name will match.\n */\n name?: string;\n\n /**\n * Optional domain key-value pairs to match against.\n * Domains provide additional context to uniquely identify an axis beyond its name and type.\n * When specified, an axis will match only if it contains all the key-value pairs defined here.\n * An axis with additional domain entries not present in this selector will still match.\n */\n domain?: Record<string, string>;\n\n /**\n * Optional context domain key-value pairs to match against.\n * Context domains are matched by kinship rules (subset/superset/overlap) rather than exact equality.\n * When specified, an axis will match only if it contains all the key-value pairs defined here.\n */\n contextDomain?: Record<string, string>;\n}\n\n/** Single axis selector */\nexport interface SingleAxisSelector {\n /** Axis name (required) */\n name: string;\n /** Axis type (optional) */\n type?: AxisValueType;\n /** Domain requirements (optional) */\n domain?: Domain;\n /** Parent axes requirements (optional) */\n parentAxes?: SingleAxisSelector[];\n}\n\n/**\n * Reference to an axis by its numerical index within the anchor column's axes array\n * Format: [anchorId, axisIndex]\n */\nexport type AnchorAxisRefByIdx = { anchor: string; idx: number };\n\n/**\n * Reference to an axis by its name within the anchor column\n * Format: [anchorId, axisName]\n */\nexport type AnchorAxisRefByName = { anchor: string; name: string };\n\n/**\n * Reference to an axis using an AxisId matcher within the anchor\n * Format: [anchorId, axisMatcher]\n */\nexport type AnchorAxisRefByMatcher = { anchor: string; id: AxisId };\n\n/**\n * Basic anchor axis reference that can be either by index or a direct AxisId\n */\nexport type AnchorAxisIdOrRefBasic = AnchorAxisRefByIdx | AxisId;\n\n/** Union of all possible ways to reference an axis in an anchored context */\nexport type AnchorAxisRef = AnchorAxisRefByIdx | AnchorAxisRefByName | AnchorAxisRefByMatcher;\n\n/** Reference to a domain value through an anchor */\nexport type AnchorDomainRef = { anchor: string };\n\n/**\n * Domain value that can be either a direct string value or a reference to a domain through an anchor\n * Used to establish domain context that can be resolved relative to other anchored columns\n */\nexport type ADomain = string | AnchorDomainRef;\n/**\n * Axis identifier that can be either a direct AxisId or a reference to an axis through an anchor\n * Allows referring to axes in a way that can be resolved in different contexts\n */\nexport type AAxisSelector = AxisSelector | AnchorAxisRef;\n\n/**\n * Match resolution strategy for PColumns\n * Specifies how to handle when multiple columns match the criteria\n * (default is \"expectSingle\")\n */\nexport type AnchoredColumnMatchStrategy = \"expectSingle\" | \"expectMultiple\" | \"takeFirst\";\n\n/**\n * Matcher for PColumns in an anchored context\n * Supports partial matching on axes, allowing for flexible column discovery\n */\nexport interface AnchoredPColumnSelector {\n /** Optional name of the column to match; can't be used together with namePattern */\n name?: string;\n /** Optional regexp pattern for column name matching; can't be used together with name */\n namePattern?: string;\n /** Optional value type to match. If an array is provided, matches if the column's type is any of the specified types */\n type?: ValueType | ValueType[];\n /** If specified, the domain values must be anchored to this anchor */\n domainAnchor?: string;\n /** Optional domain values to match, can include anchored references, if domainAnchor is specified,\n * interpreted as additional domains to domain from the anchor */\n domain?: Record<string, ADomain>;\n /** If specified, the context domain values must be anchored to this anchor */\n contextDomainAnchor?: string;\n /** Optional context domain values to match, can include anchored references, if contextDomainAnchor is specified,\n * interpreted as additional context domains to context domain from the anchor */\n contextDomain?: Record<string, ADomain>;\n /** Optional axes to match, can include anchored references */\n axes?: AAxisSelector[];\n /** When true, allows matching if only a subset of axes match */\n partialAxesMatch?: boolean;\n /** Optional annotations to match with exact values */\n annotations?: Record<string, string>;\n /** Optional annotation patterns to match with regex patterns */\n annotationPatterns?: Record<string, string>;\n /** Match resolution strategy, default is \"expectSingle\" */\n matchStrategy?: AnchoredColumnMatchStrategy;\n}\n\n/**\n * Matcher for PColumns in a non-anchored context\n */\nexport interface PColumnSelector extends AnchoredPColumnSelector {\n domainAnchor?: never;\n domain?: Record<string, string>;\n contextDomainAnchor?: never;\n contextDomain?: Record<string, string>;\n axes?: AxisSelector[];\n}\n\n/**\n * Strict identifier for PColumns in an anchored context\n * Unlike APColumnMatcher, this requires exact matches on domain and axes\n */\nexport interface AnchoredPColumnId extends AnchoredPColumnSelector {\n /** Name is required for exact column identification */\n name: string;\n /** No namePattern in ID */\n namePattern?: never;\n /** Type is not used in exact column identification */\n type?: never;\n /** Full axes specification using only basic references */\n axes: AnchorAxisIdOrRefBasic[];\n /** Partial axes matching is not allowed for exact identification */\n partialAxesMatch?: never;\n /** Annotations are not used in exact column identification */\n annotations?: never;\n /** Annotation patterns are not used in exact column identification */\n annotationPatterns?: never;\n /** \"Id\" implies single match strategy */\n matchStrategy?: never;\n}\n\n/**\n * Checks if a given value is an anchored column identifier\n * @param id - The value to check\n * @returns True if the value is an anchored column identifier, false otherwise\n */\nexport function isAnchoredPColumnId(id: unknown): id is AnchoredPColumnId {\n // basic check, can be extended if needed\n return typeof id === \"object\" && id !== null && \"name\" in id && \"axes\" in id;\n}\n\n/**\n * Determines if an axis ID matches an axis selector.\n *\n * @param selector - The selector with criteria to match against\n * @param axis - The AxisId to check against the selector\n * @returns true if the AxisId matches all specified criteria in the selector, false otherwise\n */\nexport function matchAxis(selector: AxisSelector, axis: AxisId): boolean {\n // Match name if specified\n if (selector.name !== undefined && selector.name !== axis.name) return false;\n\n // Match type if specified\n if (selector.type !== undefined) {\n if (Array.isArray(selector.type)) {\n if (!selector.type.includes(axis.type)) return false;\n } else if (selector.type !== axis.type) {\n return false;\n }\n }\n\n // Match domain if specified - using existing logic from matchAxisId\n if (selector.domain !== undefined) {\n const axisDomain = axis.domain || {};\n for (const [key, value] of Object.entries(selector.domain))\n if (axisDomain[key] !== value) return false;\n }\n\n // Match contextDomain if specified\n if (selector.contextDomain !== undefined) {\n const axisContextDomain = axis.contextDomain || {};\n for (const [key, value] of Object.entries(selector.contextDomain))\n if (axisContextDomain[key] !== value) return false;\n }\n\n return true;\n}\n\n/**\n * Determines if a given PColumnSpec matches a selector.\n *\n * @param pcolumn - The PColumnSpec to check against the selector\n * @param selector - The selector criteria to match against\n * @returns true if the PColumnSpec matches all criteria in the selector, false otherwise\n */\nexport function matchPColumn(pcolumn: PColumnSpec, selector: PColumnSelector): boolean {\n // Match name if specified\n if (selector.name !== undefined && pcolumn.name !== selector.name) return false;\n\n // Match name pattern if specified\n if (selector.namePattern !== undefined && !new RegExp(selector.namePattern).test(pcolumn.name))\n return false;\n\n // Match type if specified\n if (selector.type !== undefined) {\n if (Array.isArray(selector.type)) {\n if (!selector.type.includes(pcolumn.valueType)) return false;\n } else if (selector.type !== pcolumn.valueType) {\n return false;\n }\n }\n\n // Match domain if specified\n if (selector.domain !== undefined) {\n const columnDomain = pcolumn.domain || {};\n for (const [key, value] of Object.entries(selector.domain))\n if (columnDomain[key] !== value) return false;\n }\n\n // Match contextDomain if specified\n if (selector.contextDomain !== undefined) {\n const columnContextDomain = pcolumn.contextDomain || {};\n for (const [key, value] of Object.entries(selector.contextDomain))\n if (columnContextDomain[key] !== value) return false;\n }\n\n // Match axes if specified\n if (selector.axes !== undefined) {\n const pcolumnAxes = pcolumn.axesSpec.map(getAxisId);\n\n if (selector.partialAxesMatch) {\n // For partial matching, all selector axes must match at least one column axis\n for (const selectorAxis of selector.axes)\n if (!pcolumnAxes.some((columnAxis) => matchAxis(selectorAxis, columnAxis))) return false;\n } else {\n // For exact matching, column must have the same number of axes and all must match\n if (pcolumnAxes.length !== selector.axes.length) return false;\n\n // Each selector axis must match a corresponding column axis\n for (let i = 0; i < selector.axes.length; i++)\n if (!matchAxis(selector.axes[i], pcolumnAxes[i])) return false;\n }\n }\n\n // Match annotations if specified\n if (selector.annotations !== undefined) {\n const columnAnnotations = pcolumn.annotations || {};\n for (const [key, value] of Object.entries(selector.annotations))\n if (columnAnnotations[key] !== value) return false;\n }\n\n // Match annotation patterns if specified\n if (selector.annotationPatterns !== undefined) {\n const columnAnnotations = pcolumn.annotations || {};\n for (const [key, pattern] of Object.entries(selector.annotationPatterns)) {\n const value = columnAnnotations[key];\n if (value === undefined || !new RegExp(pattern).test(value)) return false;\n }\n }\n\n return true;\n}\n\n/**\n * Convert a predicate or array of selectors to a single predicate function\n * @param predicateOrSelectors - Either a function that takes a PColumnSpec and returns a boolean,\n * or an array of PColumnSelectors, or a single PColumnSelector\n * @returns A function that takes a PColumnSpec and returns a boolean\n */\nexport function selectorsToPredicate(\n predicateOrSelectors: PColumnSelector | PColumnSelector[],\n): (spec: PObjectSpec) => boolean {\n if (Array.isArray(predicateOrSelectors))\n return (spec) =>\n predicateOrSelectors.some((selector) => isPColumnSpec(spec) && matchPColumn(spec, selector));\n else return (spec) => isPColumnSpec(spec) && matchPColumn(spec, predicateOrSelectors);\n}\n"],"mappings":";;;;;;;;;AAiLA,SAAgB,oBAAoB,IAAsC;AAExE,QAAO,OAAO,OAAO,YAAY,OAAO,QAAQ,UAAU,MAAM,UAAU;;;;;;;;;AAU5E,SAAgB,UAAU,UAAwB,MAAuB;AAEvE,KAAI,SAAS,SAAS,UAAa,SAAS,SAAS,KAAK,KAAM,QAAO;AAGvE,KAAI,SAAS,SAAS,QACpB;MAAI,MAAM,QAAQ,SAAS,KAAK,EAC9B;OAAI,CAAC,SAAS,KAAK,SAAS,KAAK,KAAK,CAAE,QAAO;aACtC,SAAS,SAAS,KAAK,KAChC,QAAO;;AAKX,KAAI,SAAS,WAAW,QAAW;EACjC,MAAM,aAAa,KAAK,UAAU,EAAE;AACpC,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,OAAO,CACxD,KAAI,WAAW,SAAS,MAAO,QAAO;;AAI1C,KAAI,SAAS,kBAAkB,QAAW;EACxC,MAAM,oBAAoB,KAAK,iBAAiB,EAAE;AAClD,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,cAAc,CAC/D,KAAI,kBAAkB,SAAS,MAAO,QAAO;;AAGjD,QAAO;;;;;;;;;AAUT,SAAgB,aAAa,SAAsB,UAAoC;AAErF,KAAI,SAAS,SAAS,UAAa,QAAQ,SAAS,SAAS,KAAM,QAAO;AAG1E,KAAI,SAAS,gBAAgB,UAAa,CAAC,IAAI,OAAO,SAAS,YAAY,CAAC,KAAK,QAAQ,KAAK,CAC5F,QAAO;AAGT,KAAI,SAAS,SAAS,QACpB;MAAI,MAAM,QAAQ,SAAS,KAAK,EAC9B;OAAI,CAAC,SAAS,KAAK,SAAS,QAAQ,UAAU,CAAE,QAAO;aAC9C,SAAS,SAAS,QAAQ,UACnC,QAAO;;AAKX,KAAI,SAAS,WAAW,QAAW;EACjC,MAAM,eAAe,QAAQ,UAAU,EAAE;AACzC,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,OAAO,CACxD,KAAI,aAAa,SAAS,MAAO,QAAO;;AAI5C,KAAI,SAAS,kBAAkB,QAAW;EACxC,MAAM,sBAAsB,QAAQ,iBAAiB,EAAE;AACvD,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,cAAc,CAC/D,KAAI,oBAAoB,SAAS,MAAO,QAAO;;AAInD,KAAI,SAAS,SAAS,QAAW;EAC/B,MAAM,cAAc,QAAQ,SAAS,IAAI,UAAU;AAEnD,MAAI,SAAS,kBAEX;QAAK,MAAM,gBAAgB,SAAS,KAClC,KAAI,CAAC,YAAY,MAAM,eAAe,UAAU,cAAc,WAAW,CAAC,CAAE,QAAO;SAChF;AAEL,OAAI,YAAY,WAAW,SAAS,KAAK,OAAQ,QAAO;AAGxD,QAAK,IAAI,IAAI,GAAG,IAAI,SAAS,KAAK,QAAQ,IACxC,KAAI,CAAC,UAAU,SAAS,KAAK,IAAI,YAAY,GAAG,CAAE,QAAO;;;AAK/D,KAAI,SAAS,gBAAgB,QAAW;EACtC,MAAM,oBAAoB,QAAQ,eAAe,EAAE;AACnD,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,YAAY,CAC7D,KAAI,kBAAkB,SAAS,MAAO,QAAO;;AAIjD,KAAI,SAAS,uBAAuB,QAAW;EAC7C,MAAM,oBAAoB,QAAQ,eAAe,EAAE;AACnD,OAAK,MAAM,CAAC,KAAK,YAAY,OAAO,QAAQ,SAAS,mBAAmB,EAAE;GACxE,MAAM,QAAQ,kBAAkB;AAChC,OAAI,UAAU,UAAa,CAAC,IAAI,OAAO,QAAQ,CAAC,KAAK,MAAM,CAAE,QAAO;;;AAIxE,QAAO;;;;;;;;AAST,SAAgB,qBACd,sBACgC;AAChC,KAAI,MAAM,QAAQ,qBAAqB,CACrC,SAAQ,SACN,qBAAqB,MAAM,aAAa,cAAc,KAAK,IAAI,aAAa,MAAM,SAAS,CAAC;KAC3F,SAAQ,SAAS,cAAc,KAAK,IAAI,aAAa,MAAM,qBAAqB"}
|
|
@@ -212,6 +212,9 @@ function normalizingAxesComparator(axis1, axis2) {
|
|
|
212
212
|
const domain1 = require_json.canonicalizeJson(axis1.domain ?? {});
|
|
213
213
|
const domain2 = require_json.canonicalizeJson(axis2.domain ?? {});
|
|
214
214
|
if (domain1 !== domain2) return domain1 < domain2 ? 1 : -1;
|
|
215
|
+
const contextDomain1 = require_json.canonicalizeJson(axis1.contextDomain ?? {});
|
|
216
|
+
const contextDomain2 = require_json.canonicalizeJson(axis2.contextDomain ?? {});
|
|
217
|
+
if (contextDomain1 !== contextDomain2) return contextDomain1 < contextDomain2 ? 1 : -1;
|
|
215
218
|
const parents1 = canonicalizeAxisWithParents(axis1);
|
|
216
219
|
const parents2 = canonicalizeAxisWithParents(axis2);
|
|
217
220
|
if (parents1 !== parents2) return parents1 < parents2 ? 1 : -1;
|
|
@@ -319,6 +322,7 @@ function getPColumnSpecId(spec) {
|
|
|
319
322
|
valueType: spec.valueType,
|
|
320
323
|
name: spec.name,
|
|
321
324
|
domain: spec.domain,
|
|
325
|
+
contextDomain: spec.contextDomain,
|
|
322
326
|
parentAxes: spec.parentAxes,
|
|
323
327
|
axesId: getAxesId(spec.axesSpec)
|
|
324
328
|
};
|
|
@@ -332,12 +336,13 @@ function getColumnIdAndSpec(column) {
|
|
|
332
336
|
}
|
|
333
337
|
/** Extracts axis ids from axis spec */
|
|
334
338
|
function getAxisId(spec) {
|
|
335
|
-
const { type, name, domain } = spec;
|
|
339
|
+
const { type, name, domain, contextDomain } = spec;
|
|
336
340
|
const result = {
|
|
337
341
|
type,
|
|
338
342
|
name
|
|
339
343
|
};
|
|
340
344
|
if (domain && Object.entries(domain).length > 0) Object.assign(result, { domain });
|
|
345
|
+
if (contextDomain && Object.entries(contextDomain).length > 0) Object.assign(result, { contextDomain });
|
|
341
346
|
return result;
|
|
342
347
|
}
|
|
343
348
|
/** Extracts axes ids from axes spec array from column spec */
|
|
@@ -357,7 +362,7 @@ function matchDomain(query, target) {
|
|
|
357
362
|
}
|
|
358
363
|
/** Returns whether "match" axis id is compatible with the "query" */
|
|
359
364
|
function matchAxisId(query, target) {
|
|
360
|
-
return query.name === target.name && matchDomain(query.domain, target.domain);
|
|
365
|
+
return query.name === target.name && matchDomain(query.domain, target.domain) && matchDomain(query.contextDomain, target.contextDomain);
|
|
361
366
|
}
|
|
362
367
|
function getTypeFromPColumnOrAxisSpec(spec) {
|
|
363
368
|
return "valueType" in spec ? spec.valueType : spec.type;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec.cjs","names":["ensureError","z","canonicalizeJson"],"sources":["../../../../src/drivers/pframe/spec/spec.ts"],"sourcesContent":["import { ensureError } from \"../../../errors\";\nimport { canonicalizeJson, type CanonicalizedJson, type StringifiedJson } from \"../../../json\";\nimport type { PObject, PObjectId, PObjectSpec } from \"../../../pool\";\nimport { z } from \"zod\";\n\nexport const ValueType = {\n Int: \"Int\",\n Long: \"Long\",\n Float: \"Float\",\n Double: \"Double\",\n String: \"String\",\n Bytes: \"Bytes\",\n} as const;\n\nexport type AxisValueType = Extract<ValueType, \"Int\" | \"Long\" | \"String\">;\nexport type ColumnValueType = ValueType;\n\n/** PFrame columns and axes within them may store one of these types. */\nexport type ValueType = (typeof ValueType)[keyof typeof ValueType];\n\nexport type Metadata = Record<string, string>;\n\nexport function readMetadata<U extends Metadata, T extends keyof U = keyof U>(\n metadata: Metadata | undefined,\n key: T,\n): U[T] | undefined {\n return (metadata as U | undefined)?.[key];\n}\n\ntype MetadataJsonImpl<M> = {\n [P in keyof M as M[P] extends StringifiedJson ? P : never]: M[P] extends StringifiedJson<infer U>\n ? z.ZodType<U>\n : never;\n};\nexport type MetadataJson<M> = MetadataJsonImpl<Required<M>>;\n\nexport function readMetadataJsonOrThrow<M extends Metadata, T extends keyof MetadataJson<M>>(\n metadata: Metadata | undefined,\n metadataJson: MetadataJson<M>,\n key: T,\n methodNameInError: string = \"readMetadataJsonOrThrow\",\n): z.infer<MetadataJson<M>[T]> | undefined {\n const json = readMetadata<M, T>(metadata, key);\n if (json === undefined) return undefined;\n\n const schema = metadataJson[key];\n try {\n const value = JSON.parse(json);\n return schema.parse(value);\n } catch (error: unknown) {\n throw new Error(\n `${methodNameInError} failed, ` +\n `key: ${String(key)}, ` +\n `value: ${json}, ` +\n `error: ${ensureError(error)}`,\n );\n }\n}\n\nexport function readMetadataJson<M extends Metadata, T extends keyof MetadataJson<M>>(\n metadata: Metadata | undefined,\n metadataJson: MetadataJson<M>,\n key: T,\n): z.infer<MetadataJson<M>[T]> | undefined {\n try {\n return readMetadataJsonOrThrow(metadata, metadataJson, key);\n } catch {\n return undefined; // treat invalid values as unset\n }\n}\n\n/// Well-known domains\nexport const Domain = {\n Alphabet: \"pl7.app/alphabet\",\n BlockId: \"pl7.app/blockId\",\n VDJ: {\n Clustering: {\n BlockId: \"pl7.app/vdj/clustering/blockId\",\n },\n ScClonotypeChain: {\n Index: \"pl7.app/vdj/scClonotypeChain/index\",\n },\n },\n} as const;\n\nexport type Domain = Metadata &\n Partial<{\n [Domain.Alphabet]: \"nucleotide\" | \"aminoacid\" | (string & {});\n [Domain.BlockId]: string;\n [Domain.VDJ.ScClonotypeChain.Index]: \"primary\" | \"secondary\" | (string & {});\n }>;\n\nexport type DomainJson = MetadataJson<Domain>;\nexport const DomainJson: DomainJson = {};\n\n/// Helper function for reading plain domain values\nexport function readDomain<T extends keyof Domain>(\n spec: { domain?: Metadata | undefined } | undefined,\n key: T,\n): Domain[T] | undefined {\n return readMetadata<Domain, T>(spec?.domain, key);\n}\n\n/// Helper function for reading json-encoded domain values, throws on JSON parsing error\nexport function readDomainJsonOrThrow<T extends keyof DomainJson>(\n spec: { domain?: Metadata | undefined } | undefined,\n key: T,\n): z.infer<DomainJson[T]> | undefined {\n return readMetadataJsonOrThrow<Domain, T>(spec?.domain, DomainJson, key, \"readDomainJsonOrThrow\");\n}\n\n/// Helper function for reading json-encoded domain values, returns undefined on JSON parsing error\nexport function readDomainJson<T extends keyof DomainJson>(\n spec: { domain?: Metadata | undefined } | undefined,\n key: T,\n): z.infer<DomainJson[T]> | undefined {\n return readMetadataJson<Domain, T>(spec?.domain, DomainJson, key);\n}\n\n/// Well-known annotations\nexport const Annotation = {\n AxisNature: \"pl7.app/axisNature\",\n Alphabet: \"pl7.app/alphabet\",\n Description: \"pl7.app/description\",\n DiscreteValues: \"pl7.app/discreteValues\",\n Format: \"pl7.app/format\",\n Graph: {\n Axis: {\n HighCardinality: \"pl7.app/graph/axis/highCardinality\",\n LowerLimit: \"pl7.app/graph/axis/lowerLimit\",\n SymmetricRange: \"pl7.app/graph/axis/symmetricRange\",\n UpperLimit: \"pl7.app/graph/axis/upperLimit\",\n },\n IsDenseAxis: \"pl7.app/graph/isDenseAxis\",\n IsVirtual: \"pl7.app/graph/isVirtual\",\n Palette: \"pl7.app/graph/palette\",\n Thresholds: \"pl7.app/graph/thresholds\",\n TreatAbsentValuesAs: \"pl7.app/graph/treatAbsentValuesAs\",\n },\n HideDataFromUi: \"pl7.app/hideDataFromUi\",\n HideDataFromGraphs: \"pl7.app/hideDataFromGraphs\",\n IsDiscreteFilter: \"pl7.app/isDiscreteFilter\",\n IsAnchor: \"pl7.app/isAnchor\",\n IsLinkerColumn: \"pl7.app/isLinkerColumn\",\n IsScore: \"pl7.app/isScore\",\n IsSubset: \"pl7.app/isSubset\",\n Label: \"pl7.app/label\",\n Max: \"pl7.app/max\",\n Min: \"pl7.app/min\",\n MultipliesBy: \"pl7.app/multipliesBy\",\n Parents: \"pl7.app/parents\",\n Score: {\n DefaultCutoff: \"pl7.app/score/defaultCutoff\",\n RankingOrder: \"pl7.app/score/rankingOrder\",\n },\n Sequence: {\n Annotation: {\n Mapping: \"pl7.app/sequence/annotation/mapping\",\n },\n IsAnnotation: \"pl7.app/sequence/isAnnotation\",\n },\n Table: {\n FontFamily: \"pl7.app/table/fontFamily\",\n OrderPriority: \"pl7.app/table/orderPriority\",\n Visibility: \"pl7.app/table/visibility\",\n },\n Trace: \"pl7.app/trace\",\n VDJ: {\n IsAssemblingFeature: \"pl7.app/vdj/isAssemblingFeature\",\n IsMainSequence: \"pl7.app/vdj/isMainSequence\",\n },\n} as const;\n\nexport type Annotation = Metadata &\n Partial<{\n [Annotation.Alphabet]: \"nucleotide\" | \"aminoacid\" | (string & {});\n [Annotation.AxisNature]: \"homogeneous\" | \"heterogeneous\" | \"scaleCompatible\" | (string & {});\n [Annotation.Description]: string;\n [Annotation.DiscreteValues]: StringifiedJson<number[]> | StringifiedJson<string[]>;\n [Annotation.Format]: string;\n [Annotation.Graph.Axis.HighCardinality]: StringifiedJson<boolean>;\n [Annotation.Graph.Axis.LowerLimit]: StringifiedJson<number>;\n [Annotation.Graph.Axis.SymmetricRange]: StringifiedJson<boolean>;\n [Annotation.Graph.Axis.UpperLimit]: StringifiedJson<number>;\n [Annotation.Graph.IsDenseAxis]: StringifiedJson<boolean>;\n [Annotation.Graph.IsVirtual]: StringifiedJson<boolean>;\n [Annotation.Graph.Palette]: StringifiedJson<{ mapping: Record<string, number>; name: string }>;\n [Annotation.Graph.Thresholds]: StringifiedJson<\n { columnId: { valueType: ValueType; name: string }; value: number }[]\n >;\n [Annotation.Graph.TreatAbsentValuesAs]: StringifiedJson<number>;\n [Annotation.HideDataFromGraphs]: StringifiedJson<boolean>;\n [Annotation.HideDataFromUi]: StringifiedJson<boolean>;\n [Annotation.IsDiscreteFilter]: StringifiedJson<boolean>;\n [Annotation.IsLinkerColumn]: StringifiedJson<boolean>;\n [Annotation.IsSubset]: StringifiedJson<boolean>;\n [Annotation.Label]: string;\n [Annotation.Max]: StringifiedJson<number>;\n [Annotation.Min]: StringifiedJson<number>;\n [Annotation.MultipliesBy]: StringifiedJson<AxisSpec[\"name\"][]>;\n [Annotation.Parents]: StringifiedJson<AxisSpec[\"name\"][]>;\n [Annotation.Sequence.Annotation.Mapping]: StringifiedJson<Record<string, string>>;\n [Annotation.Sequence.IsAnnotation]: StringifiedJson<boolean>;\n [Annotation.Table.FontFamily]: string;\n [Annotation.Table.OrderPriority]: StringifiedJson<number>;\n [Annotation.Table.Visibility]: \"hidden\" | \"optional\" | (string & {});\n [Annotation.Trace]: StringifiedJson<Record<string, unknown>>;\n [Annotation.VDJ.IsAssemblingFeature]: StringifiedJson<boolean>;\n }>;\n\n// export const AxisSpec = z.object({\n// type: z.nativeEnum(ValueType),\n// name: z.string(),\n// domain: z.record(z.string(), z.string()).optional(),\n// annotations: z.record(z.string(), z.string()).optional(),\n// parentAxes: z.array(z.number()).optional(),\n// }).passthrough();\n//\n// type Expect<T extends true> = T;\n// type Equal<X, Y> =\n// (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false;\n//\n// type _test = Expect<Equal<\n// Readonly<z.infer<typeof AxisSpec>>,\n// Readonly<AxisSpec & Record<string, unknown>>\n// >>;\n\nexport type AnnotationJson = MetadataJson<Annotation>;\n\nconst ValueTypeSchema = z.enum([\"Int\", \"Long\", \"Float\", \"Double\", \"String\"] as const);\nexport const AnnotationJson: AnnotationJson = {\n [Annotation.DiscreteValues]: z.array(z.string()).or(z.array(z.number())),\n [Annotation.Graph.Axis.HighCardinality]: z.boolean(),\n [Annotation.Graph.Axis.LowerLimit]: z.number(),\n [Annotation.Graph.Axis.UpperLimit]: z.number(),\n [Annotation.Graph.Axis.SymmetricRange]: z.boolean(),\n [Annotation.Graph.IsDenseAxis]: z.boolean(),\n [Annotation.Graph.Palette]: z.object({ mapping: z.record(z.number()), name: z.string() }),\n [Annotation.Graph.Thresholds]: z.array(\n z.object({\n columnId: z.object({ valueType: ValueTypeSchema, name: z.string() }),\n value: z.number(),\n }),\n ),\n [Annotation.Graph.TreatAbsentValuesAs]: z.number(),\n [Annotation.Graph.IsVirtual]: z.boolean(),\n [Annotation.HideDataFromUi]: z.boolean(),\n [Annotation.HideDataFromGraphs]: z.boolean(),\n [Annotation.IsDiscreteFilter]: z.boolean(),\n [Annotation.IsLinkerColumn]: z.boolean(),\n [Annotation.IsSubset]: z.boolean(),\n [Annotation.Max]: z.number(),\n [Annotation.Min]: z.number(),\n [Annotation.MultipliesBy]: z.array(z.string()),\n [Annotation.Parents]: z.array(z.string()),\n [Annotation.Sequence.Annotation.Mapping]: z.record(z.string(), z.string()),\n [Annotation.Sequence.IsAnnotation]: z.boolean(),\n [Annotation.Table.OrderPriority]: z.number(),\n [Annotation.Trace]: z.record(z.string(), z.unknown()),\n [Annotation.VDJ.IsAssemblingFeature]: z.boolean(),\n};\n\n/// Helper function for reading plain annotation values\nexport function readAnnotation<T extends keyof Annotation>(\n spec: { annotations?: Metadata | undefined } | undefined,\n key: T,\n): Annotation[T] | undefined {\n return readMetadata<Annotation, T>(spec?.annotations, key);\n}\n\n/// Helper function for reading json-encoded annotation values, throws on JSON parsing error\nexport function readAnnotationJsonOrThrow<T extends keyof AnnotationJson>(\n spec: { annotations?: Metadata | undefined } | undefined,\n key: T,\n): z.infer<AnnotationJson[T]> | undefined {\n return readMetadataJsonOrThrow<Annotation, T>(\n spec?.annotations,\n AnnotationJson,\n key,\n \"readAnnotationJsonOrThrow\",\n );\n}\n\n/// Helper function for reading json-encoded annotation values, returns undefined on JSON parsing error\nexport function readAnnotationJson<T extends keyof AnnotationJson>(\n spec: { annotations?: Metadata | undefined } | undefined,\n key: T,\n): z.infer<AnnotationJson[T]> | undefined {\n return readMetadataJson<Annotation, T>(spec?.annotations, AnnotationJson, key);\n}\n\nexport function isLinkerColumn(column: PColumnSpec): boolean {\n return !!readAnnotationJson(column, Annotation.IsLinkerColumn);\n}\n\n/**\n * Specification of an individual axis.\n *\n * Each axis is a part of a composite key that addresses data inside the PColumn.\n *\n * Each record inside a PColumn is addressed by a unique tuple of values set for\n * all the axes specified in the column spec.\n */\nexport type AxisSpec = {\n /** Type of the axis value. Should not use non-key types like float or double. */\n readonly type: ValueType;\n\n /** Name of the axis */\n readonly name: string;\n\n /** Adds auxiliary information to the axis name, type and parents to form a\n * unique identifier */\n readonly domain?: Record<string, string>;\n\n /** Any additional information attached to the axis that does not affect its\n * identifier */\n readonly annotations?: Record<string, string>;\n\n /**\n * Parent axes provide contextual grouping for the axis in question, establishing\n * a hierarchy where the current axis is dependent on one or more axes for its\n * full definition and meaning. For instance, in a data structure where each\n * \"container\" axis may contain multiple \"item\" axes, the `item` axis would\n * list the index of the `container` axis in this field to denote its dependency.\n *\n * This means that the identity or significance of the `item` axis is only\n * interpretable when combined with its parent `container` axis. An `item` axis\n * index by itself may be non-unique and only gains uniqueness within the context\n * of its parent `container`. Therefore, the `parentAxes` field is essential for\n * mapping these relationships and ensuring data coherence across nested or\n * multi-level data models.\n *\n * A list of zero-based indices of parent axes in the overall axes specification\n * from the column spec. Each index corresponds to the position of a parent axis\n * in the list that defines the structure of the data model.\n */\n readonly parentAxes?: number[];\n};\n\n/** Parents are specs, not indexes; normalized axis can be used considering its parents independently from column */\nexport interface AxisSpecNormalized extends Omit<AxisSpec, \"parentAxes\"> {\n parentAxesSpec: AxisSpecNormalized[];\n}\n\n/** Tree: axis is a root, its parents are children */\nexport type AxisTree = {\n axis: AxisSpecNormalized;\n children: AxisTree[]; // parents\n};\n\nfunction makeAxisTree(axis: AxisSpecNormalized): AxisTree {\n return { axis, children: [] };\n}\n\n/** Build tree by axis parents annotations */\nexport function getAxesTree(rootAxis: AxisSpecNormalized): AxisTree {\n const root = makeAxisTree(rootAxis);\n let nodesQ = [root];\n while (nodesQ.length) {\n const nextNodes: AxisTree[] = [];\n for (const node of nodesQ) {\n node.children = node.axis.parentAxesSpec.map(makeAxisTree);\n nextNodes.push(...node.children);\n }\n nodesQ = nextNodes;\n }\n return root;\n}\n\n/** Get set of canonicalized axisIds from axisTree */\nexport function getSetFromAxisTree(tree: AxisTree): Set<CanonicalizedJson<AxisId>> {\n const set = new Set([canonicalizeJson(getAxisId(tree.axis))]);\n let nodesQ = [tree];\n while (nodesQ.length) {\n const nextNodes = [];\n for (const node of nodesQ) {\n for (const parent of node.children) {\n set.add(canonicalizeJson(getAxisId(parent.axis)));\n nextNodes.push(parent);\n }\n }\n nodesQ = nextNodes;\n }\n return set;\n}\n\n/** Get array of axisSpecs from axisTree */\nexport function getArrayFromAxisTree(tree: AxisTree): AxisSpecNormalized[] {\n const res = [tree.axis];\n let nodesQ = [tree];\n while (nodesQ.length) {\n const nextNodes = [];\n for (const node of nodesQ) {\n for (const parent of node.children) {\n res.push(parent.axis);\n nextNodes.push(parent);\n }\n }\n nodesQ = nextNodes;\n }\n return res;\n}\n\nexport function canonicalizeAxisWithParents(axis: AxisSpecNormalized) {\n return canonicalizeJson(getArrayFromAxisTree(getAxesTree(axis)).map(getAxisId));\n}\n\nfunction normalizingAxesComparator(\n axis1: AxisSpecNormalized,\n axis2: AxisSpecNormalized,\n): 1 | -1 | 0 {\n if (axis1.name !== axis2.name) {\n return axis1.name < axis2.name ? 1 : -1;\n }\n if (axis1.type !== axis2.type) {\n return axis1.type < axis2.type ? 1 : -1;\n }\n const domain1 = canonicalizeJson(axis1.domain ?? {});\n const domain2 = canonicalizeJson(axis2.domain ?? {});\n if (domain1 !== domain2) {\n return domain1 < domain2 ? 1 : -1;\n }\n\n const parents1 = canonicalizeAxisWithParents(axis1);\n const parents2 = canonicalizeAxisWithParents(axis2);\n\n if (parents1 !== parents2) {\n return parents1 < parents2 ? 1 : -1;\n }\n\n const annotation1 = canonicalizeJson(axis1.annotations ?? {});\n const annotation2 = canonicalizeJson(axis2.annotations ?? {});\n if (annotation1 !== annotation2) {\n return annotation1 < annotation2 ? 1 : -1;\n }\n return 0;\n}\n\nfunction parseParentsFromAnnotations(axis: AxisSpec) {\n const parentsList = readAnnotationJson(axis, Annotation.Parents);\n if (parentsList === undefined) {\n return [];\n }\n return parentsList;\n}\n\nfunction sortParentsDeep(axisSpec: AxisSpecNormalized) {\n axisSpec.parentAxesSpec.forEach(sortParentsDeep);\n axisSpec.parentAxesSpec.sort(normalizingAxesComparator);\n}\n\nfunction hasCycleOfParents(axisSpec: AxisSpecNormalized) {\n const root = makeAxisTree(axisSpec);\n let nodesQ = [root];\n const ancestors = new Set(canonicalizeJson(getAxisId(axisSpec)));\n while (nodesQ.length) {\n const nextNodes: AxisTree[] = [];\n const levelIds = new Set<CanonicalizedJson<AxisId>>();\n for (const node of nodesQ) {\n node.children = node.axis.parentAxesSpec.map(makeAxisTree);\n for (const child of node.children) {\n const childId = canonicalizeJson(getAxisId(child.axis));\n if (!levelIds.has(childId)) {\n nextNodes.push(child);\n levelIds.add(childId);\n if (ancestors.has(childId)) {\n return true;\n }\n ancestors.add(childId);\n }\n }\n }\n nodesQ = nextNodes;\n }\n return false;\n}\n\n/** Create list of normalized axisSpec (parents are in array of specs, not indexes) */\nexport function getNormalizedAxesList(axes: AxisSpec[]): AxisSpecNormalized[] {\n if (!axes.length) {\n return [];\n }\n const modifiedAxes: AxisSpecNormalized[] = axes.map((axis) => {\n const { parentAxes: _, ...copiedRest } = axis;\n return { ...copiedRest, annotations: { ...copiedRest.annotations }, parentAxesSpec: [] };\n });\n\n axes.forEach((axis, idx) => {\n const modifiedAxis = modifiedAxes[idx];\n if (axis.parentAxes) {\n // if we have parents by indexes then take from the list\n modifiedAxis.parentAxesSpec = axis.parentAxes.map((idx) => modifiedAxes[idx]);\n } else {\n // else try to parse from annotation name\n const parents = parseParentsFromAnnotations(axis).map((name) =>\n modifiedAxes.find((axis) => axis.name === name),\n );\n modifiedAxis.parentAxesSpec = parents.some((p) => p === undefined)\n ? []\n : (parents as AxisSpecNormalized[]);\n\n delete modifiedAxis.annotations?.[Annotation.Parents];\n }\n });\n\n if (modifiedAxes.some(hasCycleOfParents)) {\n // Axes list is broken\n modifiedAxes.forEach((axis) => {\n axis.parentAxesSpec = [];\n });\n } else {\n modifiedAxes.forEach((axis) => {\n sortParentsDeep(axis);\n });\n }\n\n return modifiedAxes;\n}\n\n/** Create list of regular axisSpec from normalized (parents are indexes, inside of current axes list) */\nexport function getDenormalizedAxesList(axesSpec: AxisSpecNormalized[]): AxisSpec[] {\n const idsList = axesSpec.map((axisSpec) => canonicalizeJson(getAxisId(axisSpec)));\n return axesSpec.map((axisSpec) => {\n const parentsIds = axisSpec.parentAxesSpec.map((axisSpec) =>\n canonicalizeJson(getAxisId(axisSpec)),\n );\n const parentIdxs = parentsIds.map((id) => idsList.indexOf(id));\n const { parentAxesSpec: _, ...copiedRest } = axisSpec;\n if (parentIdxs.length) {\n return { ...copiedRest, parentAxes: parentIdxs } as AxisSpec;\n }\n return copiedRest;\n });\n}\n\n/** Common type representing spec for all the axes in a column */\nexport type AxesSpec = AxisSpec[];\n\n/// Well-known column names\nexport const PColumnName = {\n Label: \"pl7.app/label\",\n Table: {\n RowSelection: \"pl7.app/table/row-selection\",\n },\n VDJ: {\n LeadSelection: \"pl7.app/vdj/lead-selection\",\n RankingOrder: \"pl7.app/vdj/ranking-order\",\n Sequence: \"pl7.app/vdj/sequence\",\n },\n} as const;\n\n/// Well-known axis names\nexport const PAxisName = {\n SampleId: \"pl7.app/sampleId\",\n VDJ: {\n Assay: {\n SequenceId: \"pl7.app/vdj/assay/sequenceId\",\n },\n ClusterId: \"pl7.app/vdj/clusterId\",\n ClonotypeKey: \"pl7.app/vdj/clonotypeKey\",\n ScClonotypeKey: \"pl7.app/vdj/scClonotypeKey\",\n },\n} as const;\n\nexport function isLabelColumn(column: PColumnSpec) {\n return column.axesSpec.length === 1 && column.name === PColumnName.Label;\n}\n\n/**\n * Full column specification including all axes specs and specs of the column\n * itself.\n *\n * A PColumn in its essence represents a mapping from a fixed size, explicitly\n * typed tuple to an explicitly typed value.\n *\n * (axis1Value1, axis2Value1, ...) -> columnValue\n *\n * Each element in tuple correspond to the axis having the same index in axesSpec.\n */\nexport type PUniversalColumnSpec = PObjectSpec & {\n /** Defines specific type of BObject, the most generic type of unit of\n * information in Platforma Project. */\n readonly kind: \"PColumn\";\n\n /** Type of column values */\n readonly valueType: string;\n\n /** Column name */\n readonly name: string;\n\n /** Adds auxiliary information to the axis name, type and parents to form a\n * unique identifier */\n readonly domain?: Record<string, string>;\n\n /** Any additional information attached to the column that does not affect its\n * identifier */\n readonly annotations?: Record<string, string>;\n\n /** A list of zero-based indices of parent axes from the {@link axesSpec} array. */\n readonly parentAxes?: number[];\n\n /** Axes specifications */\n readonly axesSpec: AxesSpec;\n};\n\n/**\n * Specification of a data column.\n *\n * Data column is a specialized type of PColumn that stores only simple values (strings and numbers)\n * addressed by multiple keys. This is in contrast to other PColumn variants that can store more complex\n * values like files or other abstract data types. Data columns are optimized for storing and processing\n * basic tabular data.\n */\nexport type PDataColumnSpec = PUniversalColumnSpec & {\n /** Type of column values */\n readonly valueType: ValueType;\n};\n\n// @todo: change this to PUniversalColumnSpec\nexport type PColumnSpec = PDataColumnSpec;\n\n/** Unique PColumnSpec identifier */\nexport type PColumnSpecId = {\n /** Defines specific type of BObject, the most generic type of unit of\n * information in Platforma Project. */\n readonly kind: \"PColumn\";\n\n /** Type of column values */\n readonly valueType: ValueType;\n\n /** Column name */\n readonly name: string;\n\n /** Adds auxiliary information to the axis name, type and parents to form a\n * unique identifier */\n readonly domain?: Record<string, string>;\n\n /** A list of zero-based indices of parent axes from the {@link axesSpec} array. */\n readonly parentAxes?: number[];\n\n /** Axes id */\n readonly axesId: AxesId;\n};\n\nexport function getPColumnSpecId(spec: PColumnSpec): PColumnSpecId {\n return {\n kind: spec.kind,\n valueType: spec.valueType,\n name: spec.name,\n domain: spec.domain,\n parentAxes: spec.parentAxes,\n axesId: getAxesId(spec.axesSpec),\n };\n}\n\nexport interface PColumn<Data> extends PObject<Data> {\n /** PColumn spec, allowing it to be found among other PObjects */\n readonly spec: PColumnSpec;\n}\n\nexport type PColumnLazy<T> = PColumn<() => T>;\n\n/** Columns in a PFrame also have internal identifier, this object represents\n * combination of specs and such id */\nexport interface PColumnIdAndSpec {\n /** Internal column id within the PFrame */\n readonly columnId: PObjectId;\n\n /** Column spec */\n readonly spec: PColumnSpec;\n}\n\n/** Get column id and spec from a column */\nexport function getColumnIdAndSpec<Data>(column: PColumn<Data>): PColumnIdAndSpec {\n return {\n columnId: column.id,\n spec: column.spec,\n };\n}\n\n/** Information returned by {@link PFrame.listColumns} method */\nexport interface PColumnInfo extends PColumnIdAndSpec {\n /** True if data was associated with this PColumn */\n readonly hasData: boolean;\n}\n\nexport interface AxisId {\n /** Type of the axis or column value. For an axis should not use non-key\n * types like float or double. */\n readonly type: ValueType;\n\n /** Name of the axis or column */\n readonly name: string;\n\n /** Adds auxiliary information to the axis or column name and type to form a\n * unique identifier */\n readonly domain?: Record<string, string>;\n}\n\n/** Array of axis ids */\nexport type AxesId = AxisId[];\n\n/** Extracts axis ids from axis spec */\nexport function getAxisId(spec: AxisSpec): AxisId {\n const { type, name, domain } = spec;\n const result = { type, name };\n if (domain && Object.entries(domain).length > 0) {\n Object.assign(result, { domain });\n }\n return result;\n}\n\n/** Extracts axes ids from axes spec array from column spec */\nexport function getAxesId(spec: AxesSpec): AxesId {\n return spec.map(getAxisId);\n}\n\n/** Canonicalizes axis id */\nexport function canonicalizeAxisId(id: AxisId): CanonicalizedJson<AxisId> {\n return canonicalizeJson(getAxisId(id));\n}\n\n/** Returns true if all domains from query are found in target */\nfunction matchDomain(query?: Record<string, string>, target?: Record<string, string>) {\n if (query === undefined) return target === undefined;\n if (target === undefined) return true;\n for (const k in target) {\n if (query[k] !== target[k]) return false;\n }\n return true;\n}\n\n/** Returns whether \"match\" axis id is compatible with the \"query\" */\nexport function matchAxisId(query: AxisId, target: AxisId): boolean {\n return query.name === target.name && matchDomain(query.domain, target.domain);\n}\n\nexport function getTypeFromPColumnOrAxisSpec(spec: PColumnSpec | AxisSpec): ValueType {\n return \"valueType\" in spec ? spec.valueType : spec.type;\n}\n\nexport function isAxisId(id: unknown): id is AxisId {\n return typeof id === \"object\" && id !== null && \"name\" in id && \"type\" in id;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"spec.cjs","names":["ensureError","z","canonicalizeJson"],"sources":["../../../../src/drivers/pframe/spec/spec.ts"],"sourcesContent":["import { ensureError } from \"../../../errors\";\nimport { canonicalizeJson, type CanonicalizedJson, type StringifiedJson } from \"../../../json\";\nimport type { PObject, PObjectId, PObjectSpec } from \"../../../pool\";\nimport { z } from \"zod\";\n\nexport const ValueType = {\n Int: \"Int\",\n Long: \"Long\",\n Float: \"Float\",\n Double: \"Double\",\n String: \"String\",\n Bytes: \"Bytes\",\n} as const;\n\nexport type AxisValueType = Extract<ValueType, \"Int\" | \"Long\" | \"String\">;\nexport type ColumnValueType = ValueType;\n\n/** PFrame columns and axes within them may store one of these types. */\nexport type ValueType = (typeof ValueType)[keyof typeof ValueType];\n\nexport type Metadata = Record<string, string>;\n\nexport function readMetadata<U extends Metadata, T extends keyof U = keyof U>(\n metadata: Metadata | undefined,\n key: T,\n): U[T] | undefined {\n return (metadata as U | undefined)?.[key];\n}\n\ntype MetadataJsonImpl<M> = {\n [P in keyof M as M[P] extends StringifiedJson ? P : never]: M[P] extends StringifiedJson<infer U>\n ? z.ZodType<U>\n : never;\n};\nexport type MetadataJson<M> = MetadataJsonImpl<Required<M>>;\n\nexport function readMetadataJsonOrThrow<M extends Metadata, T extends keyof MetadataJson<M>>(\n metadata: Metadata | undefined,\n metadataJson: MetadataJson<M>,\n key: T,\n methodNameInError: string = \"readMetadataJsonOrThrow\",\n): z.infer<MetadataJson<M>[T]> | undefined {\n const json = readMetadata<M, T>(metadata, key);\n if (json === undefined) return undefined;\n\n const schema = metadataJson[key];\n try {\n const value = JSON.parse(json);\n return schema.parse(value);\n } catch (error: unknown) {\n throw new Error(\n `${methodNameInError} failed, ` +\n `key: ${String(key)}, ` +\n `value: ${json}, ` +\n `error: ${ensureError(error)}`,\n );\n }\n}\n\nexport function readMetadataJson<M extends Metadata, T extends keyof MetadataJson<M>>(\n metadata: Metadata | undefined,\n metadataJson: MetadataJson<M>,\n key: T,\n): z.infer<MetadataJson<M>[T]> | undefined {\n try {\n return readMetadataJsonOrThrow(metadata, metadataJson, key);\n } catch {\n return undefined; // treat invalid values as unset\n }\n}\n\n/// Well-known domains\nexport const Domain = {\n Alphabet: \"pl7.app/alphabet\",\n BlockId: \"pl7.app/blockId\",\n VDJ: {\n Clustering: {\n BlockId: \"pl7.app/vdj/clustering/blockId\",\n },\n ScClonotypeChain: {\n Index: \"pl7.app/vdj/scClonotypeChain/index\",\n },\n },\n} as const;\n\nexport type Domain = Metadata &\n Partial<{\n [Domain.Alphabet]: \"nucleotide\" | \"aminoacid\" | (string & {});\n [Domain.BlockId]: string;\n [Domain.VDJ.ScClonotypeChain.Index]: \"primary\" | \"secondary\" | (string & {});\n }>;\n\nexport type DomainJson = MetadataJson<Domain>;\nexport const DomainJson: DomainJson = {};\n\n/// Helper function for reading plain domain values\nexport function readDomain<T extends keyof Domain>(\n spec: { domain?: Metadata | undefined } | undefined,\n key: T,\n): Domain[T] | undefined {\n return readMetadata<Domain, T>(spec?.domain, key);\n}\n\n/// Helper function for reading json-encoded domain values, throws on JSON parsing error\nexport function readDomainJsonOrThrow<T extends keyof DomainJson>(\n spec: { domain?: Metadata | undefined } | undefined,\n key: T,\n): z.infer<DomainJson[T]> | undefined {\n return readMetadataJsonOrThrow<Domain, T>(spec?.domain, DomainJson, key, \"readDomainJsonOrThrow\");\n}\n\n/// Helper function for reading json-encoded domain values, returns undefined on JSON parsing error\nexport function readDomainJson<T extends keyof DomainJson>(\n spec: { domain?: Metadata | undefined } | undefined,\n key: T,\n): z.infer<DomainJson[T]> | undefined {\n return readMetadataJson<Domain, T>(spec?.domain, DomainJson, key);\n}\n\n/// Well-known annotations\nexport const Annotation = {\n AxisNature: \"pl7.app/axisNature\",\n Alphabet: \"pl7.app/alphabet\",\n Description: \"pl7.app/description\",\n DiscreteValues: \"pl7.app/discreteValues\",\n Format: \"pl7.app/format\",\n Graph: {\n Axis: {\n HighCardinality: \"pl7.app/graph/axis/highCardinality\",\n LowerLimit: \"pl7.app/graph/axis/lowerLimit\",\n SymmetricRange: \"pl7.app/graph/axis/symmetricRange\",\n UpperLimit: \"pl7.app/graph/axis/upperLimit\",\n },\n IsDenseAxis: \"pl7.app/graph/isDenseAxis\",\n IsVirtual: \"pl7.app/graph/isVirtual\",\n Palette: \"pl7.app/graph/palette\",\n Thresholds: \"pl7.app/graph/thresholds\",\n TreatAbsentValuesAs: \"pl7.app/graph/treatAbsentValuesAs\",\n },\n HideDataFromUi: \"pl7.app/hideDataFromUi\",\n HideDataFromGraphs: \"pl7.app/hideDataFromGraphs\",\n IsDiscreteFilter: \"pl7.app/isDiscreteFilter\",\n IsAnchor: \"pl7.app/isAnchor\",\n IsLinkerColumn: \"pl7.app/isLinkerColumn\",\n IsScore: \"pl7.app/isScore\",\n IsSubset: \"pl7.app/isSubset\",\n Label: \"pl7.app/label\",\n Max: \"pl7.app/max\",\n Min: \"pl7.app/min\",\n MultipliesBy: \"pl7.app/multipliesBy\",\n Parents: \"pl7.app/parents\",\n Score: {\n DefaultCutoff: \"pl7.app/score/defaultCutoff\",\n RankingOrder: \"pl7.app/score/rankingOrder\",\n },\n Sequence: {\n Annotation: {\n Mapping: \"pl7.app/sequence/annotation/mapping\",\n },\n IsAnnotation: \"pl7.app/sequence/isAnnotation\",\n },\n Table: {\n FontFamily: \"pl7.app/table/fontFamily\",\n OrderPriority: \"pl7.app/table/orderPriority\",\n Visibility: \"pl7.app/table/visibility\",\n },\n Trace: \"pl7.app/trace\",\n VDJ: {\n IsAssemblingFeature: \"pl7.app/vdj/isAssemblingFeature\",\n IsMainSequence: \"pl7.app/vdj/isMainSequence\",\n },\n} as const;\n\nexport type Annotation = Metadata &\n Partial<{\n [Annotation.Alphabet]: \"nucleotide\" | \"aminoacid\" | (string & {});\n [Annotation.AxisNature]: \"homogeneous\" | \"heterogeneous\" | \"scaleCompatible\" | (string & {});\n [Annotation.Description]: string;\n [Annotation.DiscreteValues]: StringifiedJson<number[]> | StringifiedJson<string[]>;\n [Annotation.Format]: string;\n [Annotation.Graph.Axis.HighCardinality]: StringifiedJson<boolean>;\n [Annotation.Graph.Axis.LowerLimit]: StringifiedJson<number>;\n [Annotation.Graph.Axis.SymmetricRange]: StringifiedJson<boolean>;\n [Annotation.Graph.Axis.UpperLimit]: StringifiedJson<number>;\n [Annotation.Graph.IsDenseAxis]: StringifiedJson<boolean>;\n [Annotation.Graph.IsVirtual]: StringifiedJson<boolean>;\n [Annotation.Graph.Palette]: StringifiedJson<{ mapping: Record<string, number>; name: string }>;\n [Annotation.Graph.Thresholds]: StringifiedJson<\n { columnId: { valueType: ValueType; name: string }; value: number }[]\n >;\n [Annotation.Graph.TreatAbsentValuesAs]: StringifiedJson<number>;\n [Annotation.HideDataFromGraphs]: StringifiedJson<boolean>;\n [Annotation.HideDataFromUi]: StringifiedJson<boolean>;\n [Annotation.IsDiscreteFilter]: StringifiedJson<boolean>;\n [Annotation.IsLinkerColumn]: StringifiedJson<boolean>;\n [Annotation.IsSubset]: StringifiedJson<boolean>;\n [Annotation.Label]: string;\n [Annotation.Max]: StringifiedJson<number>;\n [Annotation.Min]: StringifiedJson<number>;\n [Annotation.MultipliesBy]: StringifiedJson<AxisSpec[\"name\"][]>;\n [Annotation.Parents]: StringifiedJson<AxisSpec[\"name\"][]>;\n [Annotation.Sequence.Annotation.Mapping]: StringifiedJson<Record<string, string>>;\n [Annotation.Sequence.IsAnnotation]: StringifiedJson<boolean>;\n [Annotation.Table.FontFamily]: string;\n [Annotation.Table.OrderPriority]: StringifiedJson<number>;\n [Annotation.Table.Visibility]: \"hidden\" | \"optional\" | (string & {});\n [Annotation.Trace]: StringifiedJson<Record<string, unknown>>;\n [Annotation.VDJ.IsAssemblingFeature]: StringifiedJson<boolean>;\n }>;\n\n// export const AxisSpec = z.object({\n// type: z.nativeEnum(ValueType),\n// name: z.string(),\n// domain: z.record(z.string(), z.string()).optional(),\n// annotations: z.record(z.string(), z.string()).optional(),\n// parentAxes: z.array(z.number()).optional(),\n// }).passthrough();\n//\n// type Expect<T extends true> = T;\n// type Equal<X, Y> =\n// (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false;\n//\n// type _test = Expect<Equal<\n// Readonly<z.infer<typeof AxisSpec>>,\n// Readonly<AxisSpec & Record<string, unknown>>\n// >>;\n\nexport type AnnotationJson = MetadataJson<Annotation>;\n\nconst ValueTypeSchema = z.enum([\"Int\", \"Long\", \"Float\", \"Double\", \"String\"] as const);\nexport const AnnotationJson: AnnotationJson = {\n [Annotation.DiscreteValues]: z.array(z.string()).or(z.array(z.number())),\n [Annotation.Graph.Axis.HighCardinality]: z.boolean(),\n [Annotation.Graph.Axis.LowerLimit]: z.number(),\n [Annotation.Graph.Axis.UpperLimit]: z.number(),\n [Annotation.Graph.Axis.SymmetricRange]: z.boolean(),\n [Annotation.Graph.IsDenseAxis]: z.boolean(),\n [Annotation.Graph.Palette]: z.object({ mapping: z.record(z.number()), name: z.string() }),\n [Annotation.Graph.Thresholds]: z.array(\n z.object({\n columnId: z.object({ valueType: ValueTypeSchema, name: z.string() }),\n value: z.number(),\n }),\n ),\n [Annotation.Graph.TreatAbsentValuesAs]: z.number(),\n [Annotation.Graph.IsVirtual]: z.boolean(),\n [Annotation.HideDataFromUi]: z.boolean(),\n [Annotation.HideDataFromGraphs]: z.boolean(),\n [Annotation.IsDiscreteFilter]: z.boolean(),\n [Annotation.IsLinkerColumn]: z.boolean(),\n [Annotation.IsSubset]: z.boolean(),\n [Annotation.Max]: z.number(),\n [Annotation.Min]: z.number(),\n [Annotation.MultipliesBy]: z.array(z.string()),\n [Annotation.Parents]: z.array(z.string()),\n [Annotation.Sequence.Annotation.Mapping]: z.record(z.string(), z.string()),\n [Annotation.Sequence.IsAnnotation]: z.boolean(),\n [Annotation.Table.OrderPriority]: z.number(),\n [Annotation.Trace]: z.record(z.string(), z.unknown()),\n [Annotation.VDJ.IsAssemblingFeature]: z.boolean(),\n};\n\n/// Helper function for reading plain annotation values\nexport function readAnnotation<T extends keyof Annotation>(\n spec: { annotations?: Metadata | undefined } | undefined,\n key: T,\n): Annotation[T] | undefined {\n return readMetadata<Annotation, T>(spec?.annotations, key);\n}\n\n/// Helper function for reading json-encoded annotation values, throws on JSON parsing error\nexport function readAnnotationJsonOrThrow<T extends keyof AnnotationJson>(\n spec: { annotations?: Metadata | undefined } | undefined,\n key: T,\n): z.infer<AnnotationJson[T]> | undefined {\n return readMetadataJsonOrThrow<Annotation, T>(\n spec?.annotations,\n AnnotationJson,\n key,\n \"readAnnotationJsonOrThrow\",\n );\n}\n\n/// Helper function for reading json-encoded annotation values, returns undefined on JSON parsing error\nexport function readAnnotationJson<T extends keyof AnnotationJson>(\n spec: { annotations?: Metadata | undefined } | undefined,\n key: T,\n): z.infer<AnnotationJson[T]> | undefined {\n return readMetadataJson<Annotation, T>(spec?.annotations, AnnotationJson, key);\n}\n\nexport function isLinkerColumn(column: PColumnSpec): boolean {\n return !!readAnnotationJson(column, Annotation.IsLinkerColumn);\n}\n\n/**\n * Specification of an individual axis.\n *\n * Each axis is a part of a composite key that addresses data inside the PColumn.\n *\n * Each record inside a PColumn is addressed by a unique tuple of values set for\n * all the axes specified in the column spec.\n */\nexport type AxisSpec = {\n /** Type of the axis value. Should not use non-key types like float or double. */\n readonly type: ValueType;\n\n /** Name of the axis */\n readonly name: string;\n\n /** Adds auxiliary information to the axis name, type and parents to form a\n * unique identifier */\n readonly domain?: Record<string, string>;\n\n /** Context domain provides additional axis identity that is matched\n * by kinship rules (subset/superset/overlap) rather than exact equality */\n readonly contextDomain?: Record<string, string>;\n\n /** Any additional information attached to the axis that does not affect its\n * identifier */\n readonly annotations?: Record<string, string>;\n\n /**\n * Parent axes provide contextual grouping for the axis in question, establishing\n * a hierarchy where the current axis is dependent on one or more axes for its\n * full definition and meaning. For instance, in a data structure where each\n * \"container\" axis may contain multiple \"item\" axes, the `item` axis would\n * list the index of the `container` axis in this field to denote its dependency.\n *\n * This means that the identity or significance of the `item` axis is only\n * interpretable when combined with its parent `container` axis. An `item` axis\n * index by itself may be non-unique and only gains uniqueness within the context\n * of its parent `container`. Therefore, the `parentAxes` field is essential for\n * mapping these relationships and ensuring data coherence across nested or\n * multi-level data models.\n *\n * A list of zero-based indices of parent axes in the overall axes specification\n * from the column spec. Each index corresponds to the position of a parent axis\n * in the list that defines the structure of the data model.\n */\n readonly parentAxes?: number[];\n};\n\n/** Parents are specs, not indexes; normalized axis can be used considering its parents independently from column */\nexport interface AxisSpecNormalized extends Omit<AxisSpec, \"parentAxes\"> {\n parentAxesSpec: AxisSpecNormalized[];\n}\n\n/** Tree: axis is a root, its parents are children */\nexport type AxisTree = {\n axis: AxisSpecNormalized;\n children: AxisTree[]; // parents\n};\n\nfunction makeAxisTree(axis: AxisSpecNormalized): AxisTree {\n return { axis, children: [] };\n}\n\n/** Build tree by axis parents annotations */\nexport function getAxesTree(rootAxis: AxisSpecNormalized): AxisTree {\n const root = makeAxisTree(rootAxis);\n let nodesQ = [root];\n while (nodesQ.length) {\n const nextNodes: AxisTree[] = [];\n for (const node of nodesQ) {\n node.children = node.axis.parentAxesSpec.map(makeAxisTree);\n nextNodes.push(...node.children);\n }\n nodesQ = nextNodes;\n }\n return root;\n}\n\n/** Get set of canonicalized axisIds from axisTree */\nexport function getSetFromAxisTree(tree: AxisTree): Set<CanonicalizedJson<AxisId>> {\n const set = new Set([canonicalizeJson(getAxisId(tree.axis))]);\n let nodesQ = [tree];\n while (nodesQ.length) {\n const nextNodes = [];\n for (const node of nodesQ) {\n for (const parent of node.children) {\n set.add(canonicalizeJson(getAxisId(parent.axis)));\n nextNodes.push(parent);\n }\n }\n nodesQ = nextNodes;\n }\n return set;\n}\n\n/** Get array of axisSpecs from axisTree */\nexport function getArrayFromAxisTree(tree: AxisTree): AxisSpecNormalized[] {\n const res = [tree.axis];\n let nodesQ = [tree];\n while (nodesQ.length) {\n const nextNodes = [];\n for (const node of nodesQ) {\n for (const parent of node.children) {\n res.push(parent.axis);\n nextNodes.push(parent);\n }\n }\n nodesQ = nextNodes;\n }\n return res;\n}\n\nexport function canonicalizeAxisWithParents(axis: AxisSpecNormalized) {\n return canonicalizeJson(getArrayFromAxisTree(getAxesTree(axis)).map(getAxisId));\n}\n\nfunction normalizingAxesComparator(\n axis1: AxisSpecNormalized,\n axis2: AxisSpecNormalized,\n): 1 | -1 | 0 {\n if (axis1.name !== axis2.name) {\n return axis1.name < axis2.name ? 1 : -1;\n }\n if (axis1.type !== axis2.type) {\n return axis1.type < axis2.type ? 1 : -1;\n }\n const domain1 = canonicalizeJson(axis1.domain ?? {});\n const domain2 = canonicalizeJson(axis2.domain ?? {});\n if (domain1 !== domain2) {\n return domain1 < domain2 ? 1 : -1;\n }\n\n const contextDomain1 = canonicalizeJson(axis1.contextDomain ?? {});\n const contextDomain2 = canonicalizeJson(axis2.contextDomain ?? {});\n if (contextDomain1 !== contextDomain2) {\n return contextDomain1 < contextDomain2 ? 1 : -1;\n }\n\n const parents1 = canonicalizeAxisWithParents(axis1);\n const parents2 = canonicalizeAxisWithParents(axis2);\n\n if (parents1 !== parents2) {\n return parents1 < parents2 ? 1 : -1;\n }\n\n const annotation1 = canonicalizeJson(axis1.annotations ?? {});\n const annotation2 = canonicalizeJson(axis2.annotations ?? {});\n if (annotation1 !== annotation2) {\n return annotation1 < annotation2 ? 1 : -1;\n }\n return 0;\n}\n\nfunction parseParentsFromAnnotations(axis: AxisSpec) {\n const parentsList = readAnnotationJson(axis, Annotation.Parents);\n if (parentsList === undefined) {\n return [];\n }\n return parentsList;\n}\n\nfunction sortParentsDeep(axisSpec: AxisSpecNormalized) {\n axisSpec.parentAxesSpec.forEach(sortParentsDeep);\n axisSpec.parentAxesSpec.sort(normalizingAxesComparator);\n}\n\nfunction hasCycleOfParents(axisSpec: AxisSpecNormalized) {\n const root = makeAxisTree(axisSpec);\n let nodesQ = [root];\n const ancestors = new Set(canonicalizeJson(getAxisId(axisSpec)));\n while (nodesQ.length) {\n const nextNodes: AxisTree[] = [];\n const levelIds = new Set<CanonicalizedJson<AxisId>>();\n for (const node of nodesQ) {\n node.children = node.axis.parentAxesSpec.map(makeAxisTree);\n for (const child of node.children) {\n const childId = canonicalizeJson(getAxisId(child.axis));\n if (!levelIds.has(childId)) {\n nextNodes.push(child);\n levelIds.add(childId);\n if (ancestors.has(childId)) {\n return true;\n }\n ancestors.add(childId);\n }\n }\n }\n nodesQ = nextNodes;\n }\n return false;\n}\n\n/** Create list of normalized axisSpec (parents are in array of specs, not indexes) */\nexport function getNormalizedAxesList(axes: AxisSpec[]): AxisSpecNormalized[] {\n if (!axes.length) {\n return [];\n }\n const modifiedAxes: AxisSpecNormalized[] = axes.map((axis) => {\n const { parentAxes: _, ...copiedRest } = axis;\n return { ...copiedRest, annotations: { ...copiedRest.annotations }, parentAxesSpec: [] };\n });\n\n axes.forEach((axis, idx) => {\n const modifiedAxis = modifiedAxes[idx];\n if (axis.parentAxes) {\n // if we have parents by indexes then take from the list\n modifiedAxis.parentAxesSpec = axis.parentAxes.map((idx) => modifiedAxes[idx]);\n } else {\n // else try to parse from annotation name\n const parents = parseParentsFromAnnotations(axis).map((name) =>\n modifiedAxes.find((axis) => axis.name === name),\n );\n modifiedAxis.parentAxesSpec = parents.some((p) => p === undefined)\n ? []\n : (parents as AxisSpecNormalized[]);\n\n delete modifiedAxis.annotations?.[Annotation.Parents];\n }\n });\n\n if (modifiedAxes.some(hasCycleOfParents)) {\n // Axes list is broken\n modifiedAxes.forEach((axis) => {\n axis.parentAxesSpec = [];\n });\n } else {\n modifiedAxes.forEach((axis) => {\n sortParentsDeep(axis);\n });\n }\n\n return modifiedAxes;\n}\n\n/** Create list of regular axisSpec from normalized (parents are indexes, inside of current axes list) */\nexport function getDenormalizedAxesList(axesSpec: AxisSpecNormalized[]): AxisSpec[] {\n const idsList = axesSpec.map((axisSpec) => canonicalizeJson(getAxisId(axisSpec)));\n return axesSpec.map((axisSpec) => {\n const parentsIds = axisSpec.parentAxesSpec.map((axisSpec) =>\n canonicalizeJson(getAxisId(axisSpec)),\n );\n const parentIdxs = parentsIds.map((id) => idsList.indexOf(id));\n const { parentAxesSpec: _, ...copiedRest } = axisSpec;\n if (parentIdxs.length) {\n return { ...copiedRest, parentAxes: parentIdxs } as AxisSpec;\n }\n return copiedRest;\n });\n}\n\n/** Common type representing spec for all the axes in a column */\nexport type AxesSpec = AxisSpec[];\n\n/// Well-known column names\nexport const PColumnName = {\n Label: \"pl7.app/label\",\n Table: {\n RowSelection: \"pl7.app/table/row-selection\",\n },\n VDJ: {\n LeadSelection: \"pl7.app/vdj/lead-selection\",\n RankingOrder: \"pl7.app/vdj/ranking-order\",\n Sequence: \"pl7.app/vdj/sequence\",\n },\n} as const;\n\n/// Well-known axis names\nexport const PAxisName = {\n SampleId: \"pl7.app/sampleId\",\n VDJ: {\n Assay: {\n SequenceId: \"pl7.app/vdj/assay/sequenceId\",\n },\n ClusterId: \"pl7.app/vdj/clusterId\",\n ClonotypeKey: \"pl7.app/vdj/clonotypeKey\",\n ScClonotypeKey: \"pl7.app/vdj/scClonotypeKey\",\n },\n} as const;\n\nexport function isLabelColumn(column: PColumnSpec) {\n return column.axesSpec.length === 1 && column.name === PColumnName.Label;\n}\n\n/**\n * Full column specification including all axes specs and specs of the column\n * itself.\n *\n * A PColumn in its essence represents a mapping from a fixed size, explicitly\n * typed tuple to an explicitly typed value.\n *\n * (axis1Value1, axis2Value1, ...) -> columnValue\n *\n * Each element in tuple correspond to the axis having the same index in axesSpec.\n */\nexport type PUniversalColumnSpec = PObjectSpec & {\n /** Defines specific type of BObject, the most generic type of unit of\n * information in Platforma Project. */\n readonly kind: \"PColumn\";\n\n /** Type of column values */\n readonly valueType: string;\n\n /** Column name */\n readonly name: string;\n\n /** Adds auxiliary information to the axis name, type and parents to form a\n * unique identifier */\n readonly domain?: Record<string, string>;\n\n /** Context domain provides additional column identity that is matched\n * by kinship rules (subset/superset/overlap) rather than exact equality */\n readonly contextDomain?: Record<string, string>;\n\n /** Any additional information attached to the column that does not affect its\n * identifier */\n readonly annotations?: Record<string, string>;\n\n /** A list of zero-based indices of parent axes from the {@link axesSpec} array. */\n readonly parentAxes?: number[];\n\n /** Axes specifications */\n readonly axesSpec: AxesSpec;\n};\n\n/**\n * Specification of a data column.\n *\n * Data column is a specialized type of PColumn that stores only simple values (strings and numbers)\n * addressed by multiple keys. This is in contrast to other PColumn variants that can store more complex\n * values like files or other abstract data types. Data columns are optimized for storing and processing\n * basic tabular data.\n */\nexport type PDataColumnSpec = PUniversalColumnSpec & {\n /** Type of column values */\n readonly valueType: ValueType;\n};\n\n// @todo: change this to PUniversalColumnSpec\nexport type PColumnSpec = PDataColumnSpec;\n\n/** Unique PColumnSpec identifier */\nexport type PColumnSpecId = {\n /** Defines specific type of BObject, the most generic type of unit of\n * information in Platforma Project. */\n readonly kind: \"PColumn\";\n\n /** Type of column values */\n readonly valueType: ValueType;\n\n /** Column name */\n readonly name: string;\n\n /** Adds auxiliary information to the axis name, type and parents to form a\n * unique identifier */\n readonly domain?: Record<string, string>;\n\n /** Context domain provides additional column identity that is matched\n * by kinship rules (subset/superset/overlap) rather than exact equality */\n readonly contextDomain?: Record<string, string>;\n\n /** A list of zero-based indices of parent axes from the {@link axesSpec} array. */\n readonly parentAxes?: number[];\n\n /** Axes id */\n readonly axesId: AxesId;\n};\n\nexport function getPColumnSpecId(spec: PColumnSpec): PColumnSpecId {\n return {\n kind: spec.kind,\n valueType: spec.valueType,\n name: spec.name,\n domain: spec.domain,\n contextDomain: spec.contextDomain,\n parentAxes: spec.parentAxes,\n axesId: getAxesId(spec.axesSpec),\n };\n}\n\nexport interface PColumn<Data> extends PObject<Data> {\n /** PColumn spec, allowing it to be found among other PObjects */\n readonly spec: PColumnSpec;\n}\n\nexport type PColumnLazy<T> = PColumn<() => T>;\n\n/** Columns in a PFrame also have internal identifier, this object represents\n * combination of specs and such id */\nexport interface PColumnIdAndSpec {\n /** Internal column id within the PFrame */\n readonly columnId: PObjectId;\n\n /** Column spec */\n readonly spec: PColumnSpec;\n}\n\n/** Get column id and spec from a column */\nexport function getColumnIdAndSpec<Data>(column: PColumn<Data>): PColumnIdAndSpec {\n return {\n columnId: column.id,\n spec: column.spec,\n };\n}\n\n/** Information returned by {@link PFrame.listColumns} method */\nexport interface PColumnInfo extends PColumnIdAndSpec {\n /** True if data was associated with this PColumn */\n readonly hasData: boolean;\n}\n\nexport interface AxisId {\n /** Type of the axis or column value. For an axis should not use non-key\n * types like float or double. */\n readonly type: ValueType;\n\n /** Name of the axis or column */\n readonly name: string;\n\n /** Adds auxiliary information to the axis or column name and type to form a\n * unique identifier */\n readonly domain?: Record<string, string>;\n\n /** Context domain provides additional axis identity that is matched\n * by kinship rules (subset/superset/overlap) rather than exact equality */\n readonly contextDomain?: Record<string, string>;\n}\n\n/** Array of axis ids */\nexport type AxesId = AxisId[];\n\n/** Extracts axis ids from axis spec */\nexport function getAxisId(spec: AxisSpec): AxisId {\n const { type, name, domain, contextDomain } = spec;\n const result: AxisId = { type, name };\n if (domain && Object.entries(domain).length > 0) {\n Object.assign(result, { domain });\n }\n if (contextDomain && Object.entries(contextDomain).length > 0) {\n Object.assign(result, { contextDomain });\n }\n return result;\n}\n\n/** Extracts axes ids from axes spec array from column spec */\nexport function getAxesId(spec: AxesSpec): AxesId {\n return spec.map(getAxisId);\n}\n\n/** Canonicalizes axis id */\nexport function canonicalizeAxisId(id: AxisId): CanonicalizedJson<AxisId> {\n return canonicalizeJson(getAxisId(id));\n}\n\n/** Returns true if all domains from query are found in target */\nfunction matchDomain(query?: Record<string, string>, target?: Record<string, string>) {\n if (query === undefined) return target === undefined;\n if (target === undefined) return true;\n for (const k in target) {\n if (query[k] !== target[k]) return false;\n }\n return true;\n}\n\n/** Returns whether \"match\" axis id is compatible with the \"query\" */\nexport function matchAxisId(query: AxisId, target: AxisId): boolean {\n return (\n query.name === target.name &&\n matchDomain(query.domain, target.domain) &&\n matchDomain(query.contextDomain, target.contextDomain)\n );\n}\n\nexport function getTypeFromPColumnOrAxisSpec(spec: PColumnSpec | AxisSpec): ValueType {\n return \"valueType\" in spec ? spec.valueType : spec.type;\n}\n\nexport function isAxisId(id: unknown): id is AxisId {\n return typeof id === \"object\" && id !== null && \"name\" in id && \"type\" in id;\n}\n"],"mappings":";;;;;;AAKA,MAAa,YAAY;CACvB,KAAK;CACL,MAAM;CACN,OAAO;CACP,QAAQ;CACR,QAAQ;CACR,OAAO;CACR;AAUD,SAAgB,aACd,UACA,KACkB;AAClB,QAAQ,WAA6B;;AAUvC,SAAgB,wBACd,UACA,cACA,KACA,oBAA4B,2BACa;CACzC,MAAM,OAAO,aAAmB,UAAU,IAAI;AAC9C,KAAI,SAAS,OAAW,QAAO;CAE/B,MAAM,SAAS,aAAa;AAC5B,KAAI;EACF,MAAM,QAAQ,KAAK,MAAM,KAAK;AAC9B,SAAO,OAAO,MAAM,MAAM;UACnB,OAAgB;AACvB,QAAM,IAAI,MACR,GAAG,kBAAkB,gBACX,OAAO,IAAI,CAAC,WACV,KAAK,WACLA,2BAAY,MAAM,GAC/B;;;AAIL,SAAgB,iBACd,UACA,cACA,KACyC;AACzC,KAAI;AACF,SAAO,wBAAwB,UAAU,cAAc,IAAI;SACrD;AACN;;;AAKJ,MAAa,SAAS;CACpB,UAAU;CACV,SAAS;CACT,KAAK;EACH,YAAY,EACV,SAAS,kCACV;EACD,kBAAkB,EAChB,OAAO,sCACR;EACF;CACF;AAUD,MAAa,aAAyB,EAAE;AAGxC,SAAgB,WACd,MACA,KACuB;AACvB,QAAO,aAAwB,MAAM,QAAQ,IAAI;;AAInD,SAAgB,sBACd,MACA,KACoC;AACpC,QAAO,wBAAmC,MAAM,QAAQ,YAAY,KAAK,wBAAwB;;AAInG,SAAgB,eACd,MACA,KACoC;AACpC,QAAO,iBAA4B,MAAM,QAAQ,YAAY,IAAI;;AAInE,MAAa,aAAa;CACxB,YAAY;CACZ,UAAU;CACV,aAAa;CACb,gBAAgB;CAChB,QAAQ;CACR,OAAO;EACL,MAAM;GACJ,iBAAiB;GACjB,YAAY;GACZ,gBAAgB;GAChB,YAAY;GACb;EACD,aAAa;EACb,WAAW;EACX,SAAS;EACT,YAAY;EACZ,qBAAqB;EACtB;CACD,gBAAgB;CAChB,oBAAoB;CACpB,kBAAkB;CAClB,UAAU;CACV,gBAAgB;CAChB,SAAS;CACT,UAAU;CACV,OAAO;CACP,KAAK;CACL,KAAK;CACL,cAAc;CACd,SAAS;CACT,OAAO;EACL,eAAe;EACf,cAAc;EACf;CACD,UAAU;EACR,YAAY,EACV,SAAS,uCACV;EACD,cAAc;EACf;CACD,OAAO;EACL,YAAY;EACZ,eAAe;EACf,YAAY;EACb;CACD,OAAO;CACP,KAAK;EACH,qBAAqB;EACrB,gBAAgB;EACjB;CACF;AA0DD,MAAM,kBAAkBC,MAAE,KAAK;CAAC;CAAO;CAAQ;CAAS;CAAU;CAAS,CAAU;AACrF,MAAa,iBAAiC;EAC3C,WAAW,iBAAiBA,MAAE,MAAMA,MAAE,QAAQ,CAAC,CAAC,GAAGA,MAAE,MAAMA,MAAE,QAAQ,CAAC,CAAC;EACvE,WAAW,MAAM,KAAK,kBAAkBA,MAAE,SAAS;EACnD,WAAW,MAAM,KAAK,aAAaA,MAAE,QAAQ;EAC7C,WAAW,MAAM,KAAK,aAAaA,MAAE,QAAQ;EAC7C,WAAW,MAAM,KAAK,iBAAiBA,MAAE,SAAS;EAClD,WAAW,MAAM,cAAcA,MAAE,SAAS;EAC1C,WAAW,MAAM,UAAUA,MAAE,OAAO;EAAE,SAASA,MAAE,OAAOA,MAAE,QAAQ,CAAC;EAAE,MAAMA,MAAE,QAAQ;EAAE,CAAC;EACxF,WAAW,MAAM,aAAaA,MAAE,MAC/BA,MAAE,OAAO;EACP,UAAUA,MAAE,OAAO;GAAE,WAAW;GAAiB,MAAMA,MAAE,QAAQ;GAAE,CAAC;EACpE,OAAOA,MAAE,QAAQ;EAClB,CAAC,CACH;EACA,WAAW,MAAM,sBAAsBA,MAAE,QAAQ;EACjD,WAAW,MAAM,YAAYA,MAAE,SAAS;EACxC,WAAW,iBAAiBA,MAAE,SAAS;EACvC,WAAW,qBAAqBA,MAAE,SAAS;EAC3C,WAAW,mBAAmBA,MAAE,SAAS;EACzC,WAAW,iBAAiBA,MAAE,SAAS;EACvC,WAAW,WAAWA,MAAE,SAAS;EACjC,WAAW,MAAMA,MAAE,QAAQ;EAC3B,WAAW,MAAMA,MAAE,QAAQ;EAC3B,WAAW,eAAeA,MAAE,MAAMA,MAAE,QAAQ,CAAC;EAC7C,WAAW,UAAUA,MAAE,MAAMA,MAAE,QAAQ,CAAC;EACxC,WAAW,SAAS,WAAW,UAAUA,MAAE,OAAOA,MAAE,QAAQ,EAAEA,MAAE,QAAQ,CAAC;EACzE,WAAW,SAAS,eAAeA,MAAE,SAAS;EAC9C,WAAW,MAAM,gBAAgBA,MAAE,QAAQ;EAC3C,WAAW,QAAQA,MAAE,OAAOA,MAAE,QAAQ,EAAEA,MAAE,SAAS,CAAC;EACpD,WAAW,IAAI,sBAAsBA,MAAE,SAAS;CAClD;AAGD,SAAgB,eACd,MACA,KAC2B;AAC3B,QAAO,aAA4B,MAAM,aAAa,IAAI;;AAI5D,SAAgB,0BACd,MACA,KACwC;AACxC,QAAO,wBACL,MAAM,aACN,gBACA,KACA,4BACD;;AAIH,SAAgB,mBACd,MACA,KACwC;AACxC,QAAO,iBAAgC,MAAM,aAAa,gBAAgB,IAAI;;AAGhF,SAAgB,eAAe,QAA8B;AAC3D,QAAO,CAAC,CAAC,mBAAmB,QAAQ,WAAW,eAAe;;AA8DhE,SAAS,aAAa,MAAoC;AACxD,QAAO;EAAE;EAAM,UAAU,EAAE;EAAE;;;AAI/B,SAAgB,YAAY,UAAwC;CAClE,MAAM,OAAO,aAAa,SAAS;CACnC,IAAI,SAAS,CAAC,KAAK;AACnB,QAAO,OAAO,QAAQ;EACpB,MAAM,YAAwB,EAAE;AAChC,OAAK,MAAM,QAAQ,QAAQ;AACzB,QAAK,WAAW,KAAK,KAAK,eAAe,IAAI,aAAa;AAC1D,aAAU,KAAK,GAAG,KAAK,SAAS;;AAElC,WAAS;;AAEX,QAAO;;;AAIT,SAAgB,mBAAmB,MAAgD;CACjF,MAAM,MAAM,IAAI,IAAI,CAACC,8BAAiB,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC;CAC7D,IAAI,SAAS,CAAC,KAAK;AACnB,QAAO,OAAO,QAAQ;EACpB,MAAM,YAAY,EAAE;AACpB,OAAK,MAAM,QAAQ,OACjB,MAAK,MAAM,UAAU,KAAK,UAAU;AAClC,OAAI,IAAIA,8BAAiB,UAAU,OAAO,KAAK,CAAC,CAAC;AACjD,aAAU,KAAK,OAAO;;AAG1B,WAAS;;AAEX,QAAO;;;AAIT,SAAgB,qBAAqB,MAAsC;CACzE,MAAM,MAAM,CAAC,KAAK,KAAK;CACvB,IAAI,SAAS,CAAC,KAAK;AACnB,QAAO,OAAO,QAAQ;EACpB,MAAM,YAAY,EAAE;AACpB,OAAK,MAAM,QAAQ,OACjB,MAAK,MAAM,UAAU,KAAK,UAAU;AAClC,OAAI,KAAK,OAAO,KAAK;AACrB,aAAU,KAAK,OAAO;;AAG1B,WAAS;;AAEX,QAAO;;AAGT,SAAgB,4BAA4B,MAA0B;AACpE,QAAOA,8BAAiB,qBAAqB,YAAY,KAAK,CAAC,CAAC,IAAI,UAAU,CAAC;;AAGjF,SAAS,0BACP,OACA,OACY;AACZ,KAAI,MAAM,SAAS,MAAM,KACvB,QAAO,MAAM,OAAO,MAAM,OAAO,IAAI;AAEvC,KAAI,MAAM,SAAS,MAAM,KACvB,QAAO,MAAM,OAAO,MAAM,OAAO,IAAI;CAEvC,MAAM,UAAUA,8BAAiB,MAAM,UAAU,EAAE,CAAC;CACpD,MAAM,UAAUA,8BAAiB,MAAM,UAAU,EAAE,CAAC;AACpD,KAAI,YAAY,QACd,QAAO,UAAU,UAAU,IAAI;CAGjC,MAAM,iBAAiBA,8BAAiB,MAAM,iBAAiB,EAAE,CAAC;CAClE,MAAM,iBAAiBA,8BAAiB,MAAM,iBAAiB,EAAE,CAAC;AAClE,KAAI,mBAAmB,eACrB,QAAO,iBAAiB,iBAAiB,IAAI;CAG/C,MAAM,WAAW,4BAA4B,MAAM;CACnD,MAAM,WAAW,4BAA4B,MAAM;AAEnD,KAAI,aAAa,SACf,QAAO,WAAW,WAAW,IAAI;CAGnC,MAAM,cAAcA,8BAAiB,MAAM,eAAe,EAAE,CAAC;CAC7D,MAAM,cAAcA,8BAAiB,MAAM,eAAe,EAAE,CAAC;AAC7D,KAAI,gBAAgB,YAClB,QAAO,cAAc,cAAc,IAAI;AAEzC,QAAO;;AAGT,SAAS,4BAA4B,MAAgB;CACnD,MAAM,cAAc,mBAAmB,MAAM,WAAW,QAAQ;AAChE,KAAI,gBAAgB,OAClB,QAAO,EAAE;AAEX,QAAO;;AAGT,SAAS,gBAAgB,UAA8B;AACrD,UAAS,eAAe,QAAQ,gBAAgB;AAChD,UAAS,eAAe,KAAK,0BAA0B;;AAGzD,SAAS,kBAAkB,UAA8B;CAEvD,IAAI,SAAS,CADA,aAAa,SAAS,CAChB;CACnB,MAAM,YAAY,IAAI,IAAIA,8BAAiB,UAAU,SAAS,CAAC,CAAC;AAChE,QAAO,OAAO,QAAQ;EACpB,MAAM,YAAwB,EAAE;EAChC,MAAM,2BAAW,IAAI,KAAgC;AACrD,OAAK,MAAM,QAAQ,QAAQ;AACzB,QAAK,WAAW,KAAK,KAAK,eAAe,IAAI,aAAa;AAC1D,QAAK,MAAM,SAAS,KAAK,UAAU;IACjC,MAAM,UAAUA,8BAAiB,UAAU,MAAM,KAAK,CAAC;AACvD,QAAI,CAAC,SAAS,IAAI,QAAQ,EAAE;AAC1B,eAAU,KAAK,MAAM;AACrB,cAAS,IAAI,QAAQ;AACrB,SAAI,UAAU,IAAI,QAAQ,CACxB,QAAO;AAET,eAAU,IAAI,QAAQ;;;;AAI5B,WAAS;;AAEX,QAAO;;;AAIT,SAAgB,sBAAsB,MAAwC;AAC5E,KAAI,CAAC,KAAK,OACR,QAAO,EAAE;CAEX,MAAM,eAAqC,KAAK,KAAK,SAAS;EAC5D,MAAM,EAAE,YAAY,GAAG,GAAG,eAAe;AACzC,SAAO;GAAE,GAAG;GAAY,aAAa,EAAE,GAAG,WAAW,aAAa;GAAE,gBAAgB,EAAE;GAAE;GACxF;AAEF,MAAK,SAAS,MAAM,QAAQ;EAC1B,MAAM,eAAe,aAAa;AAClC,MAAI,KAAK,WAEP,cAAa,iBAAiB,KAAK,WAAW,KAAK,QAAQ,aAAa,KAAK;OACxE;GAEL,MAAM,UAAU,4BAA4B,KAAK,CAAC,KAAK,SACrD,aAAa,MAAM,SAAS,KAAK,SAAS,KAAK,CAChD;AACD,gBAAa,iBAAiB,QAAQ,MAAM,MAAM,MAAM,OAAU,GAC9D,EAAE,GACD;AAEL,UAAO,aAAa,cAAc,WAAW;;GAE/C;AAEF,KAAI,aAAa,KAAK,kBAAkB,CAEtC,cAAa,SAAS,SAAS;AAC7B,OAAK,iBAAiB,EAAE;GACxB;KAEF,cAAa,SAAS,SAAS;AAC7B,kBAAgB,KAAK;GACrB;AAGJ,QAAO;;;AAIT,SAAgB,wBAAwB,UAA4C;CAClF,MAAM,UAAU,SAAS,KAAK,aAAaA,8BAAiB,UAAU,SAAS,CAAC,CAAC;AACjF,QAAO,SAAS,KAAK,aAAa;EAIhC,MAAM,aAHa,SAAS,eAAe,KAAK,aAC9CA,8BAAiB,UAAU,SAAS,CAAC,CACtC,CAC6B,KAAK,OAAO,QAAQ,QAAQ,GAAG,CAAC;EAC9D,MAAM,EAAE,gBAAgB,GAAG,GAAG,eAAe;AAC7C,MAAI,WAAW,OACb,QAAO;GAAE,GAAG;GAAY,YAAY;GAAY;AAElD,SAAO;GACP;;AAOJ,MAAa,cAAc;CACzB,OAAO;CACP,OAAO,EACL,cAAc,+BACf;CACD,KAAK;EACH,eAAe;EACf,cAAc;EACd,UAAU;EACX;CACF;AAGD,MAAa,YAAY;CACvB,UAAU;CACV,KAAK;EACH,OAAO,EACL,YAAY,gCACb;EACD,WAAW;EACX,cAAc;EACd,gBAAgB;EACjB;CACF;AAED,SAAgB,cAAc,QAAqB;AACjD,QAAO,OAAO,SAAS,WAAW,KAAK,OAAO,SAAS,YAAY;;AAuFrE,SAAgB,iBAAiB,MAAkC;AACjE,QAAO;EACL,MAAM,KAAK;EACX,WAAW,KAAK;EAChB,MAAM,KAAK;EACX,QAAQ,KAAK;EACb,eAAe,KAAK;EACpB,YAAY,KAAK;EACjB,QAAQ,UAAU,KAAK,SAAS;EACjC;;;AAqBH,SAAgB,mBAAyB,QAAyC;AAChF,QAAO;EACL,UAAU,OAAO;EACjB,MAAM,OAAO;EACd;;;AA8BH,SAAgB,UAAU,MAAwB;CAChD,MAAM,EAAE,MAAM,MAAM,QAAQ,kBAAkB;CAC9C,MAAM,SAAiB;EAAE;EAAM;EAAM;AACrC,KAAI,UAAU,OAAO,QAAQ,OAAO,CAAC,SAAS,EAC5C,QAAO,OAAO,QAAQ,EAAE,QAAQ,CAAC;AAEnC,KAAI,iBAAiB,OAAO,QAAQ,cAAc,CAAC,SAAS,EAC1D,QAAO,OAAO,QAAQ,EAAE,eAAe,CAAC;AAE1C,QAAO;;;AAIT,SAAgB,UAAU,MAAwB;AAChD,QAAO,KAAK,IAAI,UAAU;;;AAI5B,SAAgB,mBAAmB,IAAuC;AACxE,QAAOA,8BAAiB,UAAU,GAAG,CAAC;;;AAIxC,SAAS,YAAY,OAAgC,QAAiC;AACpF,KAAI,UAAU,OAAW,QAAO,WAAW;AAC3C,KAAI,WAAW,OAAW,QAAO;AACjC,MAAK,MAAM,KAAK,OACd,KAAI,MAAM,OAAO,OAAO,GAAI,QAAO;AAErC,QAAO;;;AAIT,SAAgB,YAAY,OAAe,QAAyB;AAClE,QACE,MAAM,SAAS,OAAO,QACtB,YAAY,MAAM,QAAQ,OAAO,OAAO,IACxC,YAAY,MAAM,eAAe,OAAO,cAAc;;AAI1D,SAAgB,6BAA6B,MAAyC;AACpF,QAAO,eAAe,OAAO,KAAK,YAAY,KAAK;;AAGrD,SAAgB,SAAS,IAA2B;AAClD,QAAO,OAAO,OAAO,YAAY,OAAO,QAAQ,UAAU,MAAM,UAAU"}
|
|
@@ -170,6 +170,9 @@ type AxisSpec = {
|
|
|
170
170
|
/** Adds auxiliary information to the axis name, type and parents to form a
|
|
171
171
|
* unique identifier */
|
|
172
172
|
readonly domain?: Record<string, string>;
|
|
173
|
+
/** Context domain provides additional axis identity that is matched
|
|
174
|
+
* by kinship rules (subset/superset/overlap) rather than exact equality */
|
|
175
|
+
readonly contextDomain?: Record<string, string>;
|
|
173
176
|
/** Any additional information attached to the axis that does not affect its
|
|
174
177
|
* identifier */
|
|
175
178
|
readonly annotations?: Record<string, string>;
|
|
@@ -260,6 +263,9 @@ type PUniversalColumnSpec = PObjectSpec & {
|
|
|
260
263
|
/** Adds auxiliary information to the axis name, type and parents to form a
|
|
261
264
|
* unique identifier */
|
|
262
265
|
readonly domain?: Record<string, string>;
|
|
266
|
+
/** Context domain provides additional column identity that is matched
|
|
267
|
+
* by kinship rules (subset/superset/overlap) rather than exact equality */
|
|
268
|
+
readonly contextDomain?: Record<string, string>;
|
|
263
269
|
/** Any additional information attached to the column that does not affect its
|
|
264
270
|
* identifier */
|
|
265
271
|
readonly annotations?: Record<string, string>; /** A list of zero-based indices of parent axes from the {@link axesSpec} array. */
|
|
@@ -287,7 +293,10 @@ type PColumnSpecId = {
|
|
|
287
293
|
readonly name: string;
|
|
288
294
|
/** Adds auxiliary information to the axis name, type and parents to form a
|
|
289
295
|
* unique identifier */
|
|
290
|
-
readonly domain?: Record<string, string>;
|
|
296
|
+
readonly domain?: Record<string, string>;
|
|
297
|
+
/** Context domain provides additional column identity that is matched
|
|
298
|
+
* by kinship rules (subset/superset/overlap) rather than exact equality */
|
|
299
|
+
readonly contextDomain?: Record<string, string>; /** A list of zero-based indices of parent axes from the {@link axesSpec} array. */
|
|
291
300
|
readonly parentAxes?: number[]; /** Axes id */
|
|
292
301
|
readonly axesId: AxesId;
|
|
293
302
|
};
|
|
@@ -321,6 +330,9 @@ interface AxisId {
|
|
|
321
330
|
/** Adds auxiliary information to the axis or column name and type to form a
|
|
322
331
|
* unique identifier */
|
|
323
332
|
readonly domain?: Record<string, string>;
|
|
333
|
+
/** Context domain provides additional axis identity that is matched
|
|
334
|
+
* by kinship rules (subset/superset/overlap) rather than exact equality */
|
|
335
|
+
readonly contextDomain?: Record<string, string>;
|
|
324
336
|
}
|
|
325
337
|
/** Array of axis ids */
|
|
326
338
|
type AxesId = AxisId[];
|
|
@@ -211,6 +211,9 @@ function normalizingAxesComparator(axis1, axis2) {
|
|
|
211
211
|
const domain1 = canonicalizeJson(axis1.domain ?? {});
|
|
212
212
|
const domain2 = canonicalizeJson(axis2.domain ?? {});
|
|
213
213
|
if (domain1 !== domain2) return domain1 < domain2 ? 1 : -1;
|
|
214
|
+
const contextDomain1 = canonicalizeJson(axis1.contextDomain ?? {});
|
|
215
|
+
const contextDomain2 = canonicalizeJson(axis2.contextDomain ?? {});
|
|
216
|
+
if (contextDomain1 !== contextDomain2) return contextDomain1 < contextDomain2 ? 1 : -1;
|
|
214
217
|
const parents1 = canonicalizeAxisWithParents(axis1);
|
|
215
218
|
const parents2 = canonicalizeAxisWithParents(axis2);
|
|
216
219
|
if (parents1 !== parents2) return parents1 < parents2 ? 1 : -1;
|
|
@@ -318,6 +321,7 @@ function getPColumnSpecId(spec) {
|
|
|
318
321
|
valueType: spec.valueType,
|
|
319
322
|
name: spec.name,
|
|
320
323
|
domain: spec.domain,
|
|
324
|
+
contextDomain: spec.contextDomain,
|
|
321
325
|
parentAxes: spec.parentAxes,
|
|
322
326
|
axesId: getAxesId(spec.axesSpec)
|
|
323
327
|
};
|
|
@@ -331,12 +335,13 @@ function getColumnIdAndSpec(column) {
|
|
|
331
335
|
}
|
|
332
336
|
/** Extracts axis ids from axis spec */
|
|
333
337
|
function getAxisId(spec) {
|
|
334
|
-
const { type, name, domain } = spec;
|
|
338
|
+
const { type, name, domain, contextDomain } = spec;
|
|
335
339
|
const result = {
|
|
336
340
|
type,
|
|
337
341
|
name
|
|
338
342
|
};
|
|
339
343
|
if (domain && Object.entries(domain).length > 0) Object.assign(result, { domain });
|
|
344
|
+
if (contextDomain && Object.entries(contextDomain).length > 0) Object.assign(result, { contextDomain });
|
|
340
345
|
return result;
|
|
341
346
|
}
|
|
342
347
|
/** Extracts axes ids from axes spec array from column spec */
|
|
@@ -356,7 +361,7 @@ function matchDomain(query, target) {
|
|
|
356
361
|
}
|
|
357
362
|
/** Returns whether "match" axis id is compatible with the "query" */
|
|
358
363
|
function matchAxisId(query, target) {
|
|
359
|
-
return query.name === target.name && matchDomain(query.domain, target.domain);
|
|
364
|
+
return query.name === target.name && matchDomain(query.domain, target.domain) && matchDomain(query.contextDomain, target.contextDomain);
|
|
360
365
|
}
|
|
361
366
|
function getTypeFromPColumnOrAxisSpec(spec) {
|
|
362
367
|
return "valueType" in spec ? spec.valueType : spec.type;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec.js","names":[],"sources":["../../../../src/drivers/pframe/spec/spec.ts"],"sourcesContent":["import { ensureError } from \"../../../errors\";\nimport { canonicalizeJson, type CanonicalizedJson, type StringifiedJson } from \"../../../json\";\nimport type { PObject, PObjectId, PObjectSpec } from \"../../../pool\";\nimport { z } from \"zod\";\n\nexport const ValueType = {\n Int: \"Int\",\n Long: \"Long\",\n Float: \"Float\",\n Double: \"Double\",\n String: \"String\",\n Bytes: \"Bytes\",\n} as const;\n\nexport type AxisValueType = Extract<ValueType, \"Int\" | \"Long\" | \"String\">;\nexport type ColumnValueType = ValueType;\n\n/** PFrame columns and axes within them may store one of these types. */\nexport type ValueType = (typeof ValueType)[keyof typeof ValueType];\n\nexport type Metadata = Record<string, string>;\n\nexport function readMetadata<U extends Metadata, T extends keyof U = keyof U>(\n metadata: Metadata | undefined,\n key: T,\n): U[T] | undefined {\n return (metadata as U | undefined)?.[key];\n}\n\ntype MetadataJsonImpl<M> = {\n [P in keyof M as M[P] extends StringifiedJson ? P : never]: M[P] extends StringifiedJson<infer U>\n ? z.ZodType<U>\n : never;\n};\nexport type MetadataJson<M> = MetadataJsonImpl<Required<M>>;\n\nexport function readMetadataJsonOrThrow<M extends Metadata, T extends keyof MetadataJson<M>>(\n metadata: Metadata | undefined,\n metadataJson: MetadataJson<M>,\n key: T,\n methodNameInError: string = \"readMetadataJsonOrThrow\",\n): z.infer<MetadataJson<M>[T]> | undefined {\n const json = readMetadata<M, T>(metadata, key);\n if (json === undefined) return undefined;\n\n const schema = metadataJson[key];\n try {\n const value = JSON.parse(json);\n return schema.parse(value);\n } catch (error: unknown) {\n throw new Error(\n `${methodNameInError} failed, ` +\n `key: ${String(key)}, ` +\n `value: ${json}, ` +\n `error: ${ensureError(error)}`,\n );\n }\n}\n\nexport function readMetadataJson<M extends Metadata, T extends keyof MetadataJson<M>>(\n metadata: Metadata | undefined,\n metadataJson: MetadataJson<M>,\n key: T,\n): z.infer<MetadataJson<M>[T]> | undefined {\n try {\n return readMetadataJsonOrThrow(metadata, metadataJson, key);\n } catch {\n return undefined; // treat invalid values as unset\n }\n}\n\n/// Well-known domains\nexport const Domain = {\n Alphabet: \"pl7.app/alphabet\",\n BlockId: \"pl7.app/blockId\",\n VDJ: {\n Clustering: {\n BlockId: \"pl7.app/vdj/clustering/blockId\",\n },\n ScClonotypeChain: {\n Index: \"pl7.app/vdj/scClonotypeChain/index\",\n },\n },\n} as const;\n\nexport type Domain = Metadata &\n Partial<{\n [Domain.Alphabet]: \"nucleotide\" | \"aminoacid\" | (string & {});\n [Domain.BlockId]: string;\n [Domain.VDJ.ScClonotypeChain.Index]: \"primary\" | \"secondary\" | (string & {});\n }>;\n\nexport type DomainJson = MetadataJson<Domain>;\nexport const DomainJson: DomainJson = {};\n\n/// Helper function for reading plain domain values\nexport function readDomain<T extends keyof Domain>(\n spec: { domain?: Metadata | undefined } | undefined,\n key: T,\n): Domain[T] | undefined {\n return readMetadata<Domain, T>(spec?.domain, key);\n}\n\n/// Helper function for reading json-encoded domain values, throws on JSON parsing error\nexport function readDomainJsonOrThrow<T extends keyof DomainJson>(\n spec: { domain?: Metadata | undefined } | undefined,\n key: T,\n): z.infer<DomainJson[T]> | undefined {\n return readMetadataJsonOrThrow<Domain, T>(spec?.domain, DomainJson, key, \"readDomainJsonOrThrow\");\n}\n\n/// Helper function for reading json-encoded domain values, returns undefined on JSON parsing error\nexport function readDomainJson<T extends keyof DomainJson>(\n spec: { domain?: Metadata | undefined } | undefined,\n key: T,\n): z.infer<DomainJson[T]> | undefined {\n return readMetadataJson<Domain, T>(spec?.domain, DomainJson, key);\n}\n\n/// Well-known annotations\nexport const Annotation = {\n AxisNature: \"pl7.app/axisNature\",\n Alphabet: \"pl7.app/alphabet\",\n Description: \"pl7.app/description\",\n DiscreteValues: \"pl7.app/discreteValues\",\n Format: \"pl7.app/format\",\n Graph: {\n Axis: {\n HighCardinality: \"pl7.app/graph/axis/highCardinality\",\n LowerLimit: \"pl7.app/graph/axis/lowerLimit\",\n SymmetricRange: \"pl7.app/graph/axis/symmetricRange\",\n UpperLimit: \"pl7.app/graph/axis/upperLimit\",\n },\n IsDenseAxis: \"pl7.app/graph/isDenseAxis\",\n IsVirtual: \"pl7.app/graph/isVirtual\",\n Palette: \"pl7.app/graph/palette\",\n Thresholds: \"pl7.app/graph/thresholds\",\n TreatAbsentValuesAs: \"pl7.app/graph/treatAbsentValuesAs\",\n },\n HideDataFromUi: \"pl7.app/hideDataFromUi\",\n HideDataFromGraphs: \"pl7.app/hideDataFromGraphs\",\n IsDiscreteFilter: \"pl7.app/isDiscreteFilter\",\n IsAnchor: \"pl7.app/isAnchor\",\n IsLinkerColumn: \"pl7.app/isLinkerColumn\",\n IsScore: \"pl7.app/isScore\",\n IsSubset: \"pl7.app/isSubset\",\n Label: \"pl7.app/label\",\n Max: \"pl7.app/max\",\n Min: \"pl7.app/min\",\n MultipliesBy: \"pl7.app/multipliesBy\",\n Parents: \"pl7.app/parents\",\n Score: {\n DefaultCutoff: \"pl7.app/score/defaultCutoff\",\n RankingOrder: \"pl7.app/score/rankingOrder\",\n },\n Sequence: {\n Annotation: {\n Mapping: \"pl7.app/sequence/annotation/mapping\",\n },\n IsAnnotation: \"pl7.app/sequence/isAnnotation\",\n },\n Table: {\n FontFamily: \"pl7.app/table/fontFamily\",\n OrderPriority: \"pl7.app/table/orderPriority\",\n Visibility: \"pl7.app/table/visibility\",\n },\n Trace: \"pl7.app/trace\",\n VDJ: {\n IsAssemblingFeature: \"pl7.app/vdj/isAssemblingFeature\",\n IsMainSequence: \"pl7.app/vdj/isMainSequence\",\n },\n} as const;\n\nexport type Annotation = Metadata &\n Partial<{\n [Annotation.Alphabet]: \"nucleotide\" | \"aminoacid\" | (string & {});\n [Annotation.AxisNature]: \"homogeneous\" | \"heterogeneous\" | \"scaleCompatible\" | (string & {});\n [Annotation.Description]: string;\n [Annotation.DiscreteValues]: StringifiedJson<number[]> | StringifiedJson<string[]>;\n [Annotation.Format]: string;\n [Annotation.Graph.Axis.HighCardinality]: StringifiedJson<boolean>;\n [Annotation.Graph.Axis.LowerLimit]: StringifiedJson<number>;\n [Annotation.Graph.Axis.SymmetricRange]: StringifiedJson<boolean>;\n [Annotation.Graph.Axis.UpperLimit]: StringifiedJson<number>;\n [Annotation.Graph.IsDenseAxis]: StringifiedJson<boolean>;\n [Annotation.Graph.IsVirtual]: StringifiedJson<boolean>;\n [Annotation.Graph.Palette]: StringifiedJson<{ mapping: Record<string, number>; name: string }>;\n [Annotation.Graph.Thresholds]: StringifiedJson<\n { columnId: { valueType: ValueType; name: string }; value: number }[]\n >;\n [Annotation.Graph.TreatAbsentValuesAs]: StringifiedJson<number>;\n [Annotation.HideDataFromGraphs]: StringifiedJson<boolean>;\n [Annotation.HideDataFromUi]: StringifiedJson<boolean>;\n [Annotation.IsDiscreteFilter]: StringifiedJson<boolean>;\n [Annotation.IsLinkerColumn]: StringifiedJson<boolean>;\n [Annotation.IsSubset]: StringifiedJson<boolean>;\n [Annotation.Label]: string;\n [Annotation.Max]: StringifiedJson<number>;\n [Annotation.Min]: StringifiedJson<number>;\n [Annotation.MultipliesBy]: StringifiedJson<AxisSpec[\"name\"][]>;\n [Annotation.Parents]: StringifiedJson<AxisSpec[\"name\"][]>;\n [Annotation.Sequence.Annotation.Mapping]: StringifiedJson<Record<string, string>>;\n [Annotation.Sequence.IsAnnotation]: StringifiedJson<boolean>;\n [Annotation.Table.FontFamily]: string;\n [Annotation.Table.OrderPriority]: StringifiedJson<number>;\n [Annotation.Table.Visibility]: \"hidden\" | \"optional\" | (string & {});\n [Annotation.Trace]: StringifiedJson<Record<string, unknown>>;\n [Annotation.VDJ.IsAssemblingFeature]: StringifiedJson<boolean>;\n }>;\n\n// export const AxisSpec = z.object({\n// type: z.nativeEnum(ValueType),\n// name: z.string(),\n// domain: z.record(z.string(), z.string()).optional(),\n// annotations: z.record(z.string(), z.string()).optional(),\n// parentAxes: z.array(z.number()).optional(),\n// }).passthrough();\n//\n// type Expect<T extends true> = T;\n// type Equal<X, Y> =\n// (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false;\n//\n// type _test = Expect<Equal<\n// Readonly<z.infer<typeof AxisSpec>>,\n// Readonly<AxisSpec & Record<string, unknown>>\n// >>;\n\nexport type AnnotationJson = MetadataJson<Annotation>;\n\nconst ValueTypeSchema = z.enum([\"Int\", \"Long\", \"Float\", \"Double\", \"String\"] as const);\nexport const AnnotationJson: AnnotationJson = {\n [Annotation.DiscreteValues]: z.array(z.string()).or(z.array(z.number())),\n [Annotation.Graph.Axis.HighCardinality]: z.boolean(),\n [Annotation.Graph.Axis.LowerLimit]: z.number(),\n [Annotation.Graph.Axis.UpperLimit]: z.number(),\n [Annotation.Graph.Axis.SymmetricRange]: z.boolean(),\n [Annotation.Graph.IsDenseAxis]: z.boolean(),\n [Annotation.Graph.Palette]: z.object({ mapping: z.record(z.number()), name: z.string() }),\n [Annotation.Graph.Thresholds]: z.array(\n z.object({\n columnId: z.object({ valueType: ValueTypeSchema, name: z.string() }),\n value: z.number(),\n }),\n ),\n [Annotation.Graph.TreatAbsentValuesAs]: z.number(),\n [Annotation.Graph.IsVirtual]: z.boolean(),\n [Annotation.HideDataFromUi]: z.boolean(),\n [Annotation.HideDataFromGraphs]: z.boolean(),\n [Annotation.IsDiscreteFilter]: z.boolean(),\n [Annotation.IsLinkerColumn]: z.boolean(),\n [Annotation.IsSubset]: z.boolean(),\n [Annotation.Max]: z.number(),\n [Annotation.Min]: z.number(),\n [Annotation.MultipliesBy]: z.array(z.string()),\n [Annotation.Parents]: z.array(z.string()),\n [Annotation.Sequence.Annotation.Mapping]: z.record(z.string(), z.string()),\n [Annotation.Sequence.IsAnnotation]: z.boolean(),\n [Annotation.Table.OrderPriority]: z.number(),\n [Annotation.Trace]: z.record(z.string(), z.unknown()),\n [Annotation.VDJ.IsAssemblingFeature]: z.boolean(),\n};\n\n/// Helper function for reading plain annotation values\nexport function readAnnotation<T extends keyof Annotation>(\n spec: { annotations?: Metadata | undefined } | undefined,\n key: T,\n): Annotation[T] | undefined {\n return readMetadata<Annotation, T>(spec?.annotations, key);\n}\n\n/// Helper function for reading json-encoded annotation values, throws on JSON parsing error\nexport function readAnnotationJsonOrThrow<T extends keyof AnnotationJson>(\n spec: { annotations?: Metadata | undefined } | undefined,\n key: T,\n): z.infer<AnnotationJson[T]> | undefined {\n return readMetadataJsonOrThrow<Annotation, T>(\n spec?.annotations,\n AnnotationJson,\n key,\n \"readAnnotationJsonOrThrow\",\n );\n}\n\n/// Helper function for reading json-encoded annotation values, returns undefined on JSON parsing error\nexport function readAnnotationJson<T extends keyof AnnotationJson>(\n spec: { annotations?: Metadata | undefined } | undefined,\n key: T,\n): z.infer<AnnotationJson[T]> | undefined {\n return readMetadataJson<Annotation, T>(spec?.annotations, AnnotationJson, key);\n}\n\nexport function isLinkerColumn(column: PColumnSpec): boolean {\n return !!readAnnotationJson(column, Annotation.IsLinkerColumn);\n}\n\n/**\n * Specification of an individual axis.\n *\n * Each axis is a part of a composite key that addresses data inside the PColumn.\n *\n * Each record inside a PColumn is addressed by a unique tuple of values set for\n * all the axes specified in the column spec.\n */\nexport type AxisSpec = {\n /** Type of the axis value. Should not use non-key types like float or double. */\n readonly type: ValueType;\n\n /** Name of the axis */\n readonly name: string;\n\n /** Adds auxiliary information to the axis name, type and parents to form a\n * unique identifier */\n readonly domain?: Record<string, string>;\n\n /** Any additional information attached to the axis that does not affect its\n * identifier */\n readonly annotations?: Record<string, string>;\n\n /**\n * Parent axes provide contextual grouping for the axis in question, establishing\n * a hierarchy where the current axis is dependent on one or more axes for its\n * full definition and meaning. For instance, in a data structure where each\n * \"container\" axis may contain multiple \"item\" axes, the `item` axis would\n * list the index of the `container` axis in this field to denote its dependency.\n *\n * This means that the identity or significance of the `item` axis is only\n * interpretable when combined with its parent `container` axis. An `item` axis\n * index by itself may be non-unique and only gains uniqueness within the context\n * of its parent `container`. Therefore, the `parentAxes` field is essential for\n * mapping these relationships and ensuring data coherence across nested or\n * multi-level data models.\n *\n * A list of zero-based indices of parent axes in the overall axes specification\n * from the column spec. Each index corresponds to the position of a parent axis\n * in the list that defines the structure of the data model.\n */\n readonly parentAxes?: number[];\n};\n\n/** Parents are specs, not indexes; normalized axis can be used considering its parents independently from column */\nexport interface AxisSpecNormalized extends Omit<AxisSpec, \"parentAxes\"> {\n parentAxesSpec: AxisSpecNormalized[];\n}\n\n/** Tree: axis is a root, its parents are children */\nexport type AxisTree = {\n axis: AxisSpecNormalized;\n children: AxisTree[]; // parents\n};\n\nfunction makeAxisTree(axis: AxisSpecNormalized): AxisTree {\n return { axis, children: [] };\n}\n\n/** Build tree by axis parents annotations */\nexport function getAxesTree(rootAxis: AxisSpecNormalized): AxisTree {\n const root = makeAxisTree(rootAxis);\n let nodesQ = [root];\n while (nodesQ.length) {\n const nextNodes: AxisTree[] = [];\n for (const node of nodesQ) {\n node.children = node.axis.parentAxesSpec.map(makeAxisTree);\n nextNodes.push(...node.children);\n }\n nodesQ = nextNodes;\n }\n return root;\n}\n\n/** Get set of canonicalized axisIds from axisTree */\nexport function getSetFromAxisTree(tree: AxisTree): Set<CanonicalizedJson<AxisId>> {\n const set = new Set([canonicalizeJson(getAxisId(tree.axis))]);\n let nodesQ = [tree];\n while (nodesQ.length) {\n const nextNodes = [];\n for (const node of nodesQ) {\n for (const parent of node.children) {\n set.add(canonicalizeJson(getAxisId(parent.axis)));\n nextNodes.push(parent);\n }\n }\n nodesQ = nextNodes;\n }\n return set;\n}\n\n/** Get array of axisSpecs from axisTree */\nexport function getArrayFromAxisTree(tree: AxisTree): AxisSpecNormalized[] {\n const res = [tree.axis];\n let nodesQ = [tree];\n while (nodesQ.length) {\n const nextNodes = [];\n for (const node of nodesQ) {\n for (const parent of node.children) {\n res.push(parent.axis);\n nextNodes.push(parent);\n }\n }\n nodesQ = nextNodes;\n }\n return res;\n}\n\nexport function canonicalizeAxisWithParents(axis: AxisSpecNormalized) {\n return canonicalizeJson(getArrayFromAxisTree(getAxesTree(axis)).map(getAxisId));\n}\n\nfunction normalizingAxesComparator(\n axis1: AxisSpecNormalized,\n axis2: AxisSpecNormalized,\n): 1 | -1 | 0 {\n if (axis1.name !== axis2.name) {\n return axis1.name < axis2.name ? 1 : -1;\n }\n if (axis1.type !== axis2.type) {\n return axis1.type < axis2.type ? 1 : -1;\n }\n const domain1 = canonicalizeJson(axis1.domain ?? {});\n const domain2 = canonicalizeJson(axis2.domain ?? {});\n if (domain1 !== domain2) {\n return domain1 < domain2 ? 1 : -1;\n }\n\n const parents1 = canonicalizeAxisWithParents(axis1);\n const parents2 = canonicalizeAxisWithParents(axis2);\n\n if (parents1 !== parents2) {\n return parents1 < parents2 ? 1 : -1;\n }\n\n const annotation1 = canonicalizeJson(axis1.annotations ?? {});\n const annotation2 = canonicalizeJson(axis2.annotations ?? {});\n if (annotation1 !== annotation2) {\n return annotation1 < annotation2 ? 1 : -1;\n }\n return 0;\n}\n\nfunction parseParentsFromAnnotations(axis: AxisSpec) {\n const parentsList = readAnnotationJson(axis, Annotation.Parents);\n if (parentsList === undefined) {\n return [];\n }\n return parentsList;\n}\n\nfunction sortParentsDeep(axisSpec: AxisSpecNormalized) {\n axisSpec.parentAxesSpec.forEach(sortParentsDeep);\n axisSpec.parentAxesSpec.sort(normalizingAxesComparator);\n}\n\nfunction hasCycleOfParents(axisSpec: AxisSpecNormalized) {\n const root = makeAxisTree(axisSpec);\n let nodesQ = [root];\n const ancestors = new Set(canonicalizeJson(getAxisId(axisSpec)));\n while (nodesQ.length) {\n const nextNodes: AxisTree[] = [];\n const levelIds = new Set<CanonicalizedJson<AxisId>>();\n for (const node of nodesQ) {\n node.children = node.axis.parentAxesSpec.map(makeAxisTree);\n for (const child of node.children) {\n const childId = canonicalizeJson(getAxisId(child.axis));\n if (!levelIds.has(childId)) {\n nextNodes.push(child);\n levelIds.add(childId);\n if (ancestors.has(childId)) {\n return true;\n }\n ancestors.add(childId);\n }\n }\n }\n nodesQ = nextNodes;\n }\n return false;\n}\n\n/** Create list of normalized axisSpec (parents are in array of specs, not indexes) */\nexport function getNormalizedAxesList(axes: AxisSpec[]): AxisSpecNormalized[] {\n if (!axes.length) {\n return [];\n }\n const modifiedAxes: AxisSpecNormalized[] = axes.map((axis) => {\n const { parentAxes: _, ...copiedRest } = axis;\n return { ...copiedRest, annotations: { ...copiedRest.annotations }, parentAxesSpec: [] };\n });\n\n axes.forEach((axis, idx) => {\n const modifiedAxis = modifiedAxes[idx];\n if (axis.parentAxes) {\n // if we have parents by indexes then take from the list\n modifiedAxis.parentAxesSpec = axis.parentAxes.map((idx) => modifiedAxes[idx]);\n } else {\n // else try to parse from annotation name\n const parents = parseParentsFromAnnotations(axis).map((name) =>\n modifiedAxes.find((axis) => axis.name === name),\n );\n modifiedAxis.parentAxesSpec = parents.some((p) => p === undefined)\n ? []\n : (parents as AxisSpecNormalized[]);\n\n delete modifiedAxis.annotations?.[Annotation.Parents];\n }\n });\n\n if (modifiedAxes.some(hasCycleOfParents)) {\n // Axes list is broken\n modifiedAxes.forEach((axis) => {\n axis.parentAxesSpec = [];\n });\n } else {\n modifiedAxes.forEach((axis) => {\n sortParentsDeep(axis);\n });\n }\n\n return modifiedAxes;\n}\n\n/** Create list of regular axisSpec from normalized (parents are indexes, inside of current axes list) */\nexport function getDenormalizedAxesList(axesSpec: AxisSpecNormalized[]): AxisSpec[] {\n const idsList = axesSpec.map((axisSpec) => canonicalizeJson(getAxisId(axisSpec)));\n return axesSpec.map((axisSpec) => {\n const parentsIds = axisSpec.parentAxesSpec.map((axisSpec) =>\n canonicalizeJson(getAxisId(axisSpec)),\n );\n const parentIdxs = parentsIds.map((id) => idsList.indexOf(id));\n const { parentAxesSpec: _, ...copiedRest } = axisSpec;\n if (parentIdxs.length) {\n return { ...copiedRest, parentAxes: parentIdxs } as AxisSpec;\n }\n return copiedRest;\n });\n}\n\n/** Common type representing spec for all the axes in a column */\nexport type AxesSpec = AxisSpec[];\n\n/// Well-known column names\nexport const PColumnName = {\n Label: \"pl7.app/label\",\n Table: {\n RowSelection: \"pl7.app/table/row-selection\",\n },\n VDJ: {\n LeadSelection: \"pl7.app/vdj/lead-selection\",\n RankingOrder: \"pl7.app/vdj/ranking-order\",\n Sequence: \"pl7.app/vdj/sequence\",\n },\n} as const;\n\n/// Well-known axis names\nexport const PAxisName = {\n SampleId: \"pl7.app/sampleId\",\n VDJ: {\n Assay: {\n SequenceId: \"pl7.app/vdj/assay/sequenceId\",\n },\n ClusterId: \"pl7.app/vdj/clusterId\",\n ClonotypeKey: \"pl7.app/vdj/clonotypeKey\",\n ScClonotypeKey: \"pl7.app/vdj/scClonotypeKey\",\n },\n} as const;\n\nexport function isLabelColumn(column: PColumnSpec) {\n return column.axesSpec.length === 1 && column.name === PColumnName.Label;\n}\n\n/**\n * Full column specification including all axes specs and specs of the column\n * itself.\n *\n * A PColumn in its essence represents a mapping from a fixed size, explicitly\n * typed tuple to an explicitly typed value.\n *\n * (axis1Value1, axis2Value1, ...) -> columnValue\n *\n * Each element in tuple correspond to the axis having the same index in axesSpec.\n */\nexport type PUniversalColumnSpec = PObjectSpec & {\n /** Defines specific type of BObject, the most generic type of unit of\n * information in Platforma Project. */\n readonly kind: \"PColumn\";\n\n /** Type of column values */\n readonly valueType: string;\n\n /** Column name */\n readonly name: string;\n\n /** Adds auxiliary information to the axis name, type and parents to form a\n * unique identifier */\n readonly domain?: Record<string, string>;\n\n /** Any additional information attached to the column that does not affect its\n * identifier */\n readonly annotations?: Record<string, string>;\n\n /** A list of zero-based indices of parent axes from the {@link axesSpec} array. */\n readonly parentAxes?: number[];\n\n /** Axes specifications */\n readonly axesSpec: AxesSpec;\n};\n\n/**\n * Specification of a data column.\n *\n * Data column is a specialized type of PColumn that stores only simple values (strings and numbers)\n * addressed by multiple keys. This is in contrast to other PColumn variants that can store more complex\n * values like files or other abstract data types. Data columns are optimized for storing and processing\n * basic tabular data.\n */\nexport type PDataColumnSpec = PUniversalColumnSpec & {\n /** Type of column values */\n readonly valueType: ValueType;\n};\n\n// @todo: change this to PUniversalColumnSpec\nexport type PColumnSpec = PDataColumnSpec;\n\n/** Unique PColumnSpec identifier */\nexport type PColumnSpecId = {\n /** Defines specific type of BObject, the most generic type of unit of\n * information in Platforma Project. */\n readonly kind: \"PColumn\";\n\n /** Type of column values */\n readonly valueType: ValueType;\n\n /** Column name */\n readonly name: string;\n\n /** Adds auxiliary information to the axis name, type and parents to form a\n * unique identifier */\n readonly domain?: Record<string, string>;\n\n /** A list of zero-based indices of parent axes from the {@link axesSpec} array. */\n readonly parentAxes?: number[];\n\n /** Axes id */\n readonly axesId: AxesId;\n};\n\nexport function getPColumnSpecId(spec: PColumnSpec): PColumnSpecId {\n return {\n kind: spec.kind,\n valueType: spec.valueType,\n name: spec.name,\n domain: spec.domain,\n parentAxes: spec.parentAxes,\n axesId: getAxesId(spec.axesSpec),\n };\n}\n\nexport interface PColumn<Data> extends PObject<Data> {\n /** PColumn spec, allowing it to be found among other PObjects */\n readonly spec: PColumnSpec;\n}\n\nexport type PColumnLazy<T> = PColumn<() => T>;\n\n/** Columns in a PFrame also have internal identifier, this object represents\n * combination of specs and such id */\nexport interface PColumnIdAndSpec {\n /** Internal column id within the PFrame */\n readonly columnId: PObjectId;\n\n /** Column spec */\n readonly spec: PColumnSpec;\n}\n\n/** Get column id and spec from a column */\nexport function getColumnIdAndSpec<Data>(column: PColumn<Data>): PColumnIdAndSpec {\n return {\n columnId: column.id,\n spec: column.spec,\n };\n}\n\n/** Information returned by {@link PFrame.listColumns} method */\nexport interface PColumnInfo extends PColumnIdAndSpec {\n /** True if data was associated with this PColumn */\n readonly hasData: boolean;\n}\n\nexport interface AxisId {\n /** Type of the axis or column value. For an axis should not use non-key\n * types like float or double. */\n readonly type: ValueType;\n\n /** Name of the axis or column */\n readonly name: string;\n\n /** Adds auxiliary information to the axis or column name and type to form a\n * unique identifier */\n readonly domain?: Record<string, string>;\n}\n\n/** Array of axis ids */\nexport type AxesId = AxisId[];\n\n/** Extracts axis ids from axis spec */\nexport function getAxisId(spec: AxisSpec): AxisId {\n const { type, name, domain } = spec;\n const result = { type, name };\n if (domain && Object.entries(domain).length > 0) {\n Object.assign(result, { domain });\n }\n return result;\n}\n\n/** Extracts axes ids from axes spec array from column spec */\nexport function getAxesId(spec: AxesSpec): AxesId {\n return spec.map(getAxisId);\n}\n\n/** Canonicalizes axis id */\nexport function canonicalizeAxisId(id: AxisId): CanonicalizedJson<AxisId> {\n return canonicalizeJson(getAxisId(id));\n}\n\n/** Returns true if all domains from query are found in target */\nfunction matchDomain(query?: Record<string, string>, target?: Record<string, string>) {\n if (query === undefined) return target === undefined;\n if (target === undefined) return true;\n for (const k in target) {\n if (query[k] !== target[k]) return false;\n }\n return true;\n}\n\n/** Returns whether \"match\" axis id is compatible with the \"query\" */\nexport function matchAxisId(query: AxisId, target: AxisId): boolean {\n return query.name === target.name && matchDomain(query.domain, target.domain);\n}\n\nexport function getTypeFromPColumnOrAxisSpec(spec: PColumnSpec | AxisSpec): ValueType {\n return \"valueType\" in spec ? spec.valueType : spec.type;\n}\n\nexport function isAxisId(id: unknown): id is AxisId {\n return typeof id === \"object\" && id !== null && \"name\" in id && \"type\" in id;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"spec.js","names":[],"sources":["../../../../src/drivers/pframe/spec/spec.ts"],"sourcesContent":["import { ensureError } from \"../../../errors\";\nimport { canonicalizeJson, type CanonicalizedJson, type StringifiedJson } from \"../../../json\";\nimport type { PObject, PObjectId, PObjectSpec } from \"../../../pool\";\nimport { z } from \"zod\";\n\nexport const ValueType = {\n Int: \"Int\",\n Long: \"Long\",\n Float: \"Float\",\n Double: \"Double\",\n String: \"String\",\n Bytes: \"Bytes\",\n} as const;\n\nexport type AxisValueType = Extract<ValueType, \"Int\" | \"Long\" | \"String\">;\nexport type ColumnValueType = ValueType;\n\n/** PFrame columns and axes within them may store one of these types. */\nexport type ValueType = (typeof ValueType)[keyof typeof ValueType];\n\nexport type Metadata = Record<string, string>;\n\nexport function readMetadata<U extends Metadata, T extends keyof U = keyof U>(\n metadata: Metadata | undefined,\n key: T,\n): U[T] | undefined {\n return (metadata as U | undefined)?.[key];\n}\n\ntype MetadataJsonImpl<M> = {\n [P in keyof M as M[P] extends StringifiedJson ? P : never]: M[P] extends StringifiedJson<infer U>\n ? z.ZodType<U>\n : never;\n};\nexport type MetadataJson<M> = MetadataJsonImpl<Required<M>>;\n\nexport function readMetadataJsonOrThrow<M extends Metadata, T extends keyof MetadataJson<M>>(\n metadata: Metadata | undefined,\n metadataJson: MetadataJson<M>,\n key: T,\n methodNameInError: string = \"readMetadataJsonOrThrow\",\n): z.infer<MetadataJson<M>[T]> | undefined {\n const json = readMetadata<M, T>(metadata, key);\n if (json === undefined) return undefined;\n\n const schema = metadataJson[key];\n try {\n const value = JSON.parse(json);\n return schema.parse(value);\n } catch (error: unknown) {\n throw new Error(\n `${methodNameInError} failed, ` +\n `key: ${String(key)}, ` +\n `value: ${json}, ` +\n `error: ${ensureError(error)}`,\n );\n }\n}\n\nexport function readMetadataJson<M extends Metadata, T extends keyof MetadataJson<M>>(\n metadata: Metadata | undefined,\n metadataJson: MetadataJson<M>,\n key: T,\n): z.infer<MetadataJson<M>[T]> | undefined {\n try {\n return readMetadataJsonOrThrow(metadata, metadataJson, key);\n } catch {\n return undefined; // treat invalid values as unset\n }\n}\n\n/// Well-known domains\nexport const Domain = {\n Alphabet: \"pl7.app/alphabet\",\n BlockId: \"pl7.app/blockId\",\n VDJ: {\n Clustering: {\n BlockId: \"pl7.app/vdj/clustering/blockId\",\n },\n ScClonotypeChain: {\n Index: \"pl7.app/vdj/scClonotypeChain/index\",\n },\n },\n} as const;\n\nexport type Domain = Metadata &\n Partial<{\n [Domain.Alphabet]: \"nucleotide\" | \"aminoacid\" | (string & {});\n [Domain.BlockId]: string;\n [Domain.VDJ.ScClonotypeChain.Index]: \"primary\" | \"secondary\" | (string & {});\n }>;\n\nexport type DomainJson = MetadataJson<Domain>;\nexport const DomainJson: DomainJson = {};\n\n/// Helper function for reading plain domain values\nexport function readDomain<T extends keyof Domain>(\n spec: { domain?: Metadata | undefined } | undefined,\n key: T,\n): Domain[T] | undefined {\n return readMetadata<Domain, T>(spec?.domain, key);\n}\n\n/// Helper function for reading json-encoded domain values, throws on JSON parsing error\nexport function readDomainJsonOrThrow<T extends keyof DomainJson>(\n spec: { domain?: Metadata | undefined } | undefined,\n key: T,\n): z.infer<DomainJson[T]> | undefined {\n return readMetadataJsonOrThrow<Domain, T>(spec?.domain, DomainJson, key, \"readDomainJsonOrThrow\");\n}\n\n/// Helper function for reading json-encoded domain values, returns undefined on JSON parsing error\nexport function readDomainJson<T extends keyof DomainJson>(\n spec: { domain?: Metadata | undefined } | undefined,\n key: T,\n): z.infer<DomainJson[T]> | undefined {\n return readMetadataJson<Domain, T>(spec?.domain, DomainJson, key);\n}\n\n/// Well-known annotations\nexport const Annotation = {\n AxisNature: \"pl7.app/axisNature\",\n Alphabet: \"pl7.app/alphabet\",\n Description: \"pl7.app/description\",\n DiscreteValues: \"pl7.app/discreteValues\",\n Format: \"pl7.app/format\",\n Graph: {\n Axis: {\n HighCardinality: \"pl7.app/graph/axis/highCardinality\",\n LowerLimit: \"pl7.app/graph/axis/lowerLimit\",\n SymmetricRange: \"pl7.app/graph/axis/symmetricRange\",\n UpperLimit: \"pl7.app/graph/axis/upperLimit\",\n },\n IsDenseAxis: \"pl7.app/graph/isDenseAxis\",\n IsVirtual: \"pl7.app/graph/isVirtual\",\n Palette: \"pl7.app/graph/palette\",\n Thresholds: \"pl7.app/graph/thresholds\",\n TreatAbsentValuesAs: \"pl7.app/graph/treatAbsentValuesAs\",\n },\n HideDataFromUi: \"pl7.app/hideDataFromUi\",\n HideDataFromGraphs: \"pl7.app/hideDataFromGraphs\",\n IsDiscreteFilter: \"pl7.app/isDiscreteFilter\",\n IsAnchor: \"pl7.app/isAnchor\",\n IsLinkerColumn: \"pl7.app/isLinkerColumn\",\n IsScore: \"pl7.app/isScore\",\n IsSubset: \"pl7.app/isSubset\",\n Label: \"pl7.app/label\",\n Max: \"pl7.app/max\",\n Min: \"pl7.app/min\",\n MultipliesBy: \"pl7.app/multipliesBy\",\n Parents: \"pl7.app/parents\",\n Score: {\n DefaultCutoff: \"pl7.app/score/defaultCutoff\",\n RankingOrder: \"pl7.app/score/rankingOrder\",\n },\n Sequence: {\n Annotation: {\n Mapping: \"pl7.app/sequence/annotation/mapping\",\n },\n IsAnnotation: \"pl7.app/sequence/isAnnotation\",\n },\n Table: {\n FontFamily: \"pl7.app/table/fontFamily\",\n OrderPriority: \"pl7.app/table/orderPriority\",\n Visibility: \"pl7.app/table/visibility\",\n },\n Trace: \"pl7.app/trace\",\n VDJ: {\n IsAssemblingFeature: \"pl7.app/vdj/isAssemblingFeature\",\n IsMainSequence: \"pl7.app/vdj/isMainSequence\",\n },\n} as const;\n\nexport type Annotation = Metadata &\n Partial<{\n [Annotation.Alphabet]: \"nucleotide\" | \"aminoacid\" | (string & {});\n [Annotation.AxisNature]: \"homogeneous\" | \"heterogeneous\" | \"scaleCompatible\" | (string & {});\n [Annotation.Description]: string;\n [Annotation.DiscreteValues]: StringifiedJson<number[]> | StringifiedJson<string[]>;\n [Annotation.Format]: string;\n [Annotation.Graph.Axis.HighCardinality]: StringifiedJson<boolean>;\n [Annotation.Graph.Axis.LowerLimit]: StringifiedJson<number>;\n [Annotation.Graph.Axis.SymmetricRange]: StringifiedJson<boolean>;\n [Annotation.Graph.Axis.UpperLimit]: StringifiedJson<number>;\n [Annotation.Graph.IsDenseAxis]: StringifiedJson<boolean>;\n [Annotation.Graph.IsVirtual]: StringifiedJson<boolean>;\n [Annotation.Graph.Palette]: StringifiedJson<{ mapping: Record<string, number>; name: string }>;\n [Annotation.Graph.Thresholds]: StringifiedJson<\n { columnId: { valueType: ValueType; name: string }; value: number }[]\n >;\n [Annotation.Graph.TreatAbsentValuesAs]: StringifiedJson<number>;\n [Annotation.HideDataFromGraphs]: StringifiedJson<boolean>;\n [Annotation.HideDataFromUi]: StringifiedJson<boolean>;\n [Annotation.IsDiscreteFilter]: StringifiedJson<boolean>;\n [Annotation.IsLinkerColumn]: StringifiedJson<boolean>;\n [Annotation.IsSubset]: StringifiedJson<boolean>;\n [Annotation.Label]: string;\n [Annotation.Max]: StringifiedJson<number>;\n [Annotation.Min]: StringifiedJson<number>;\n [Annotation.MultipliesBy]: StringifiedJson<AxisSpec[\"name\"][]>;\n [Annotation.Parents]: StringifiedJson<AxisSpec[\"name\"][]>;\n [Annotation.Sequence.Annotation.Mapping]: StringifiedJson<Record<string, string>>;\n [Annotation.Sequence.IsAnnotation]: StringifiedJson<boolean>;\n [Annotation.Table.FontFamily]: string;\n [Annotation.Table.OrderPriority]: StringifiedJson<number>;\n [Annotation.Table.Visibility]: \"hidden\" | \"optional\" | (string & {});\n [Annotation.Trace]: StringifiedJson<Record<string, unknown>>;\n [Annotation.VDJ.IsAssemblingFeature]: StringifiedJson<boolean>;\n }>;\n\n// export const AxisSpec = z.object({\n// type: z.nativeEnum(ValueType),\n// name: z.string(),\n// domain: z.record(z.string(), z.string()).optional(),\n// annotations: z.record(z.string(), z.string()).optional(),\n// parentAxes: z.array(z.number()).optional(),\n// }).passthrough();\n//\n// type Expect<T extends true> = T;\n// type Equal<X, Y> =\n// (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false;\n//\n// type _test = Expect<Equal<\n// Readonly<z.infer<typeof AxisSpec>>,\n// Readonly<AxisSpec & Record<string, unknown>>\n// >>;\n\nexport type AnnotationJson = MetadataJson<Annotation>;\n\nconst ValueTypeSchema = z.enum([\"Int\", \"Long\", \"Float\", \"Double\", \"String\"] as const);\nexport const AnnotationJson: AnnotationJson = {\n [Annotation.DiscreteValues]: z.array(z.string()).or(z.array(z.number())),\n [Annotation.Graph.Axis.HighCardinality]: z.boolean(),\n [Annotation.Graph.Axis.LowerLimit]: z.number(),\n [Annotation.Graph.Axis.UpperLimit]: z.number(),\n [Annotation.Graph.Axis.SymmetricRange]: z.boolean(),\n [Annotation.Graph.IsDenseAxis]: z.boolean(),\n [Annotation.Graph.Palette]: z.object({ mapping: z.record(z.number()), name: z.string() }),\n [Annotation.Graph.Thresholds]: z.array(\n z.object({\n columnId: z.object({ valueType: ValueTypeSchema, name: z.string() }),\n value: z.number(),\n }),\n ),\n [Annotation.Graph.TreatAbsentValuesAs]: z.number(),\n [Annotation.Graph.IsVirtual]: z.boolean(),\n [Annotation.HideDataFromUi]: z.boolean(),\n [Annotation.HideDataFromGraphs]: z.boolean(),\n [Annotation.IsDiscreteFilter]: z.boolean(),\n [Annotation.IsLinkerColumn]: z.boolean(),\n [Annotation.IsSubset]: z.boolean(),\n [Annotation.Max]: z.number(),\n [Annotation.Min]: z.number(),\n [Annotation.MultipliesBy]: z.array(z.string()),\n [Annotation.Parents]: z.array(z.string()),\n [Annotation.Sequence.Annotation.Mapping]: z.record(z.string(), z.string()),\n [Annotation.Sequence.IsAnnotation]: z.boolean(),\n [Annotation.Table.OrderPriority]: z.number(),\n [Annotation.Trace]: z.record(z.string(), z.unknown()),\n [Annotation.VDJ.IsAssemblingFeature]: z.boolean(),\n};\n\n/// Helper function for reading plain annotation values\nexport function readAnnotation<T extends keyof Annotation>(\n spec: { annotations?: Metadata | undefined } | undefined,\n key: T,\n): Annotation[T] | undefined {\n return readMetadata<Annotation, T>(spec?.annotations, key);\n}\n\n/// Helper function for reading json-encoded annotation values, throws on JSON parsing error\nexport function readAnnotationJsonOrThrow<T extends keyof AnnotationJson>(\n spec: { annotations?: Metadata | undefined } | undefined,\n key: T,\n): z.infer<AnnotationJson[T]> | undefined {\n return readMetadataJsonOrThrow<Annotation, T>(\n spec?.annotations,\n AnnotationJson,\n key,\n \"readAnnotationJsonOrThrow\",\n );\n}\n\n/// Helper function for reading json-encoded annotation values, returns undefined on JSON parsing error\nexport function readAnnotationJson<T extends keyof AnnotationJson>(\n spec: { annotations?: Metadata | undefined } | undefined,\n key: T,\n): z.infer<AnnotationJson[T]> | undefined {\n return readMetadataJson<Annotation, T>(spec?.annotations, AnnotationJson, key);\n}\n\nexport function isLinkerColumn(column: PColumnSpec): boolean {\n return !!readAnnotationJson(column, Annotation.IsLinkerColumn);\n}\n\n/**\n * Specification of an individual axis.\n *\n * Each axis is a part of a composite key that addresses data inside the PColumn.\n *\n * Each record inside a PColumn is addressed by a unique tuple of values set for\n * all the axes specified in the column spec.\n */\nexport type AxisSpec = {\n /** Type of the axis value. Should not use non-key types like float or double. */\n readonly type: ValueType;\n\n /** Name of the axis */\n readonly name: string;\n\n /** Adds auxiliary information to the axis name, type and parents to form a\n * unique identifier */\n readonly domain?: Record<string, string>;\n\n /** Context domain provides additional axis identity that is matched\n * by kinship rules (subset/superset/overlap) rather than exact equality */\n readonly contextDomain?: Record<string, string>;\n\n /** Any additional information attached to the axis that does not affect its\n * identifier */\n readonly annotations?: Record<string, string>;\n\n /**\n * Parent axes provide contextual grouping for the axis in question, establishing\n * a hierarchy where the current axis is dependent on one or more axes for its\n * full definition and meaning. For instance, in a data structure where each\n * \"container\" axis may contain multiple \"item\" axes, the `item` axis would\n * list the index of the `container` axis in this field to denote its dependency.\n *\n * This means that the identity or significance of the `item` axis is only\n * interpretable when combined with its parent `container` axis. An `item` axis\n * index by itself may be non-unique and only gains uniqueness within the context\n * of its parent `container`. Therefore, the `parentAxes` field is essential for\n * mapping these relationships and ensuring data coherence across nested or\n * multi-level data models.\n *\n * A list of zero-based indices of parent axes in the overall axes specification\n * from the column spec. Each index corresponds to the position of a parent axis\n * in the list that defines the structure of the data model.\n */\n readonly parentAxes?: number[];\n};\n\n/** Parents are specs, not indexes; normalized axis can be used considering its parents independently from column */\nexport interface AxisSpecNormalized extends Omit<AxisSpec, \"parentAxes\"> {\n parentAxesSpec: AxisSpecNormalized[];\n}\n\n/** Tree: axis is a root, its parents are children */\nexport type AxisTree = {\n axis: AxisSpecNormalized;\n children: AxisTree[]; // parents\n};\n\nfunction makeAxisTree(axis: AxisSpecNormalized): AxisTree {\n return { axis, children: [] };\n}\n\n/** Build tree by axis parents annotations */\nexport function getAxesTree(rootAxis: AxisSpecNormalized): AxisTree {\n const root = makeAxisTree(rootAxis);\n let nodesQ = [root];\n while (nodesQ.length) {\n const nextNodes: AxisTree[] = [];\n for (const node of nodesQ) {\n node.children = node.axis.parentAxesSpec.map(makeAxisTree);\n nextNodes.push(...node.children);\n }\n nodesQ = nextNodes;\n }\n return root;\n}\n\n/** Get set of canonicalized axisIds from axisTree */\nexport function getSetFromAxisTree(tree: AxisTree): Set<CanonicalizedJson<AxisId>> {\n const set = new Set([canonicalizeJson(getAxisId(tree.axis))]);\n let nodesQ = [tree];\n while (nodesQ.length) {\n const nextNodes = [];\n for (const node of nodesQ) {\n for (const parent of node.children) {\n set.add(canonicalizeJson(getAxisId(parent.axis)));\n nextNodes.push(parent);\n }\n }\n nodesQ = nextNodes;\n }\n return set;\n}\n\n/** Get array of axisSpecs from axisTree */\nexport function getArrayFromAxisTree(tree: AxisTree): AxisSpecNormalized[] {\n const res = [tree.axis];\n let nodesQ = [tree];\n while (nodesQ.length) {\n const nextNodes = [];\n for (const node of nodesQ) {\n for (const parent of node.children) {\n res.push(parent.axis);\n nextNodes.push(parent);\n }\n }\n nodesQ = nextNodes;\n }\n return res;\n}\n\nexport function canonicalizeAxisWithParents(axis: AxisSpecNormalized) {\n return canonicalizeJson(getArrayFromAxisTree(getAxesTree(axis)).map(getAxisId));\n}\n\nfunction normalizingAxesComparator(\n axis1: AxisSpecNormalized,\n axis2: AxisSpecNormalized,\n): 1 | -1 | 0 {\n if (axis1.name !== axis2.name) {\n return axis1.name < axis2.name ? 1 : -1;\n }\n if (axis1.type !== axis2.type) {\n return axis1.type < axis2.type ? 1 : -1;\n }\n const domain1 = canonicalizeJson(axis1.domain ?? {});\n const domain2 = canonicalizeJson(axis2.domain ?? {});\n if (domain1 !== domain2) {\n return domain1 < domain2 ? 1 : -1;\n }\n\n const contextDomain1 = canonicalizeJson(axis1.contextDomain ?? {});\n const contextDomain2 = canonicalizeJson(axis2.contextDomain ?? {});\n if (contextDomain1 !== contextDomain2) {\n return contextDomain1 < contextDomain2 ? 1 : -1;\n }\n\n const parents1 = canonicalizeAxisWithParents(axis1);\n const parents2 = canonicalizeAxisWithParents(axis2);\n\n if (parents1 !== parents2) {\n return parents1 < parents2 ? 1 : -1;\n }\n\n const annotation1 = canonicalizeJson(axis1.annotations ?? {});\n const annotation2 = canonicalizeJson(axis2.annotations ?? {});\n if (annotation1 !== annotation2) {\n return annotation1 < annotation2 ? 1 : -1;\n }\n return 0;\n}\n\nfunction parseParentsFromAnnotations(axis: AxisSpec) {\n const parentsList = readAnnotationJson(axis, Annotation.Parents);\n if (parentsList === undefined) {\n return [];\n }\n return parentsList;\n}\n\nfunction sortParentsDeep(axisSpec: AxisSpecNormalized) {\n axisSpec.parentAxesSpec.forEach(sortParentsDeep);\n axisSpec.parentAxesSpec.sort(normalizingAxesComparator);\n}\n\nfunction hasCycleOfParents(axisSpec: AxisSpecNormalized) {\n const root = makeAxisTree(axisSpec);\n let nodesQ = [root];\n const ancestors = new Set(canonicalizeJson(getAxisId(axisSpec)));\n while (nodesQ.length) {\n const nextNodes: AxisTree[] = [];\n const levelIds = new Set<CanonicalizedJson<AxisId>>();\n for (const node of nodesQ) {\n node.children = node.axis.parentAxesSpec.map(makeAxisTree);\n for (const child of node.children) {\n const childId = canonicalizeJson(getAxisId(child.axis));\n if (!levelIds.has(childId)) {\n nextNodes.push(child);\n levelIds.add(childId);\n if (ancestors.has(childId)) {\n return true;\n }\n ancestors.add(childId);\n }\n }\n }\n nodesQ = nextNodes;\n }\n return false;\n}\n\n/** Create list of normalized axisSpec (parents are in array of specs, not indexes) */\nexport function getNormalizedAxesList(axes: AxisSpec[]): AxisSpecNormalized[] {\n if (!axes.length) {\n return [];\n }\n const modifiedAxes: AxisSpecNormalized[] = axes.map((axis) => {\n const { parentAxes: _, ...copiedRest } = axis;\n return { ...copiedRest, annotations: { ...copiedRest.annotations }, parentAxesSpec: [] };\n });\n\n axes.forEach((axis, idx) => {\n const modifiedAxis = modifiedAxes[idx];\n if (axis.parentAxes) {\n // if we have parents by indexes then take from the list\n modifiedAxis.parentAxesSpec = axis.parentAxes.map((idx) => modifiedAxes[idx]);\n } else {\n // else try to parse from annotation name\n const parents = parseParentsFromAnnotations(axis).map((name) =>\n modifiedAxes.find((axis) => axis.name === name),\n );\n modifiedAxis.parentAxesSpec = parents.some((p) => p === undefined)\n ? []\n : (parents as AxisSpecNormalized[]);\n\n delete modifiedAxis.annotations?.[Annotation.Parents];\n }\n });\n\n if (modifiedAxes.some(hasCycleOfParents)) {\n // Axes list is broken\n modifiedAxes.forEach((axis) => {\n axis.parentAxesSpec = [];\n });\n } else {\n modifiedAxes.forEach((axis) => {\n sortParentsDeep(axis);\n });\n }\n\n return modifiedAxes;\n}\n\n/** Create list of regular axisSpec from normalized (parents are indexes, inside of current axes list) */\nexport function getDenormalizedAxesList(axesSpec: AxisSpecNormalized[]): AxisSpec[] {\n const idsList = axesSpec.map((axisSpec) => canonicalizeJson(getAxisId(axisSpec)));\n return axesSpec.map((axisSpec) => {\n const parentsIds = axisSpec.parentAxesSpec.map((axisSpec) =>\n canonicalizeJson(getAxisId(axisSpec)),\n );\n const parentIdxs = parentsIds.map((id) => idsList.indexOf(id));\n const { parentAxesSpec: _, ...copiedRest } = axisSpec;\n if (parentIdxs.length) {\n return { ...copiedRest, parentAxes: parentIdxs } as AxisSpec;\n }\n return copiedRest;\n });\n}\n\n/** Common type representing spec for all the axes in a column */\nexport type AxesSpec = AxisSpec[];\n\n/// Well-known column names\nexport const PColumnName = {\n Label: \"pl7.app/label\",\n Table: {\n RowSelection: \"pl7.app/table/row-selection\",\n },\n VDJ: {\n LeadSelection: \"pl7.app/vdj/lead-selection\",\n RankingOrder: \"pl7.app/vdj/ranking-order\",\n Sequence: \"pl7.app/vdj/sequence\",\n },\n} as const;\n\n/// Well-known axis names\nexport const PAxisName = {\n SampleId: \"pl7.app/sampleId\",\n VDJ: {\n Assay: {\n SequenceId: \"pl7.app/vdj/assay/sequenceId\",\n },\n ClusterId: \"pl7.app/vdj/clusterId\",\n ClonotypeKey: \"pl7.app/vdj/clonotypeKey\",\n ScClonotypeKey: \"pl7.app/vdj/scClonotypeKey\",\n },\n} as const;\n\nexport function isLabelColumn(column: PColumnSpec) {\n return column.axesSpec.length === 1 && column.name === PColumnName.Label;\n}\n\n/**\n * Full column specification including all axes specs and specs of the column\n * itself.\n *\n * A PColumn in its essence represents a mapping from a fixed size, explicitly\n * typed tuple to an explicitly typed value.\n *\n * (axis1Value1, axis2Value1, ...) -> columnValue\n *\n * Each element in tuple correspond to the axis having the same index in axesSpec.\n */\nexport type PUniversalColumnSpec = PObjectSpec & {\n /** Defines specific type of BObject, the most generic type of unit of\n * information in Platforma Project. */\n readonly kind: \"PColumn\";\n\n /** Type of column values */\n readonly valueType: string;\n\n /** Column name */\n readonly name: string;\n\n /** Adds auxiliary information to the axis name, type and parents to form a\n * unique identifier */\n readonly domain?: Record<string, string>;\n\n /** Context domain provides additional column identity that is matched\n * by kinship rules (subset/superset/overlap) rather than exact equality */\n readonly contextDomain?: Record<string, string>;\n\n /** Any additional information attached to the column that does not affect its\n * identifier */\n readonly annotations?: Record<string, string>;\n\n /** A list of zero-based indices of parent axes from the {@link axesSpec} array. */\n readonly parentAxes?: number[];\n\n /** Axes specifications */\n readonly axesSpec: AxesSpec;\n};\n\n/**\n * Specification of a data column.\n *\n * Data column is a specialized type of PColumn that stores only simple values (strings and numbers)\n * addressed by multiple keys. This is in contrast to other PColumn variants that can store more complex\n * values like files or other abstract data types. Data columns are optimized for storing and processing\n * basic tabular data.\n */\nexport type PDataColumnSpec = PUniversalColumnSpec & {\n /** Type of column values */\n readonly valueType: ValueType;\n};\n\n// @todo: change this to PUniversalColumnSpec\nexport type PColumnSpec = PDataColumnSpec;\n\n/** Unique PColumnSpec identifier */\nexport type PColumnSpecId = {\n /** Defines specific type of BObject, the most generic type of unit of\n * information in Platforma Project. */\n readonly kind: \"PColumn\";\n\n /** Type of column values */\n readonly valueType: ValueType;\n\n /** Column name */\n readonly name: string;\n\n /** Adds auxiliary information to the axis name, type and parents to form a\n * unique identifier */\n readonly domain?: Record<string, string>;\n\n /** Context domain provides additional column identity that is matched\n * by kinship rules (subset/superset/overlap) rather than exact equality */\n readonly contextDomain?: Record<string, string>;\n\n /** A list of zero-based indices of parent axes from the {@link axesSpec} array. */\n readonly parentAxes?: number[];\n\n /** Axes id */\n readonly axesId: AxesId;\n};\n\nexport function getPColumnSpecId(spec: PColumnSpec): PColumnSpecId {\n return {\n kind: spec.kind,\n valueType: spec.valueType,\n name: spec.name,\n domain: spec.domain,\n contextDomain: spec.contextDomain,\n parentAxes: spec.parentAxes,\n axesId: getAxesId(spec.axesSpec),\n };\n}\n\nexport interface PColumn<Data> extends PObject<Data> {\n /** PColumn spec, allowing it to be found among other PObjects */\n readonly spec: PColumnSpec;\n}\n\nexport type PColumnLazy<T> = PColumn<() => T>;\n\n/** Columns in a PFrame also have internal identifier, this object represents\n * combination of specs and such id */\nexport interface PColumnIdAndSpec {\n /** Internal column id within the PFrame */\n readonly columnId: PObjectId;\n\n /** Column spec */\n readonly spec: PColumnSpec;\n}\n\n/** Get column id and spec from a column */\nexport function getColumnIdAndSpec<Data>(column: PColumn<Data>): PColumnIdAndSpec {\n return {\n columnId: column.id,\n spec: column.spec,\n };\n}\n\n/** Information returned by {@link PFrame.listColumns} method */\nexport interface PColumnInfo extends PColumnIdAndSpec {\n /** True if data was associated with this PColumn */\n readonly hasData: boolean;\n}\n\nexport interface AxisId {\n /** Type of the axis or column value. For an axis should not use non-key\n * types like float or double. */\n readonly type: ValueType;\n\n /** Name of the axis or column */\n readonly name: string;\n\n /** Adds auxiliary information to the axis or column name and type to form a\n * unique identifier */\n readonly domain?: Record<string, string>;\n\n /** Context domain provides additional axis identity that is matched\n * by kinship rules (subset/superset/overlap) rather than exact equality */\n readonly contextDomain?: Record<string, string>;\n}\n\n/** Array of axis ids */\nexport type AxesId = AxisId[];\n\n/** Extracts axis ids from axis spec */\nexport function getAxisId(spec: AxisSpec): AxisId {\n const { type, name, domain, contextDomain } = spec;\n const result: AxisId = { type, name };\n if (domain && Object.entries(domain).length > 0) {\n Object.assign(result, { domain });\n }\n if (contextDomain && Object.entries(contextDomain).length > 0) {\n Object.assign(result, { contextDomain });\n }\n return result;\n}\n\n/** Extracts axes ids from axes spec array from column spec */\nexport function getAxesId(spec: AxesSpec): AxesId {\n return spec.map(getAxisId);\n}\n\n/** Canonicalizes axis id */\nexport function canonicalizeAxisId(id: AxisId): CanonicalizedJson<AxisId> {\n return canonicalizeJson(getAxisId(id));\n}\n\n/** Returns true if all domains from query are found in target */\nfunction matchDomain(query?: Record<string, string>, target?: Record<string, string>) {\n if (query === undefined) return target === undefined;\n if (target === undefined) return true;\n for (const k in target) {\n if (query[k] !== target[k]) return false;\n }\n return true;\n}\n\n/** Returns whether \"match\" axis id is compatible with the \"query\" */\nexport function matchAxisId(query: AxisId, target: AxisId): boolean {\n return (\n query.name === target.name &&\n matchDomain(query.domain, target.domain) &&\n matchDomain(query.contextDomain, target.contextDomain)\n );\n}\n\nexport function getTypeFromPColumnOrAxisSpec(spec: PColumnSpec | AxisSpec): ValueType {\n return \"valueType\" in spec ? spec.valueType : spec.type;\n}\n\nexport function isAxisId(id: unknown): id is AxisId {\n return typeof id === \"object\" && id !== null && \"name\" in id && \"type\" in id;\n}\n"],"mappings":"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"}
|
package/dist/pool/query.cjs
CHANGED
|
@@ -17,7 +17,7 @@ function executePSpecPredicate(predicate, spec) {
|
|
|
17
17
|
case "name_pattern": return require_spec.isPColumnSpec(spec) && Boolean(spec.name.match(predicate.pattern));
|
|
18
18
|
case "annotation": return require_spec.isPColumnSpec(spec) && spec.annotations !== void 0 && spec.annotations[predicate.annotation] === predicate.value;
|
|
19
19
|
case "annotation_pattern": return require_spec.isPColumnSpec(spec) && spec.annotations !== void 0 && spec.annotations[predicate.annotation] !== void 0 && Boolean(spec.annotations[predicate.annotation].match(predicate.pattern));
|
|
20
|
-
case "has_axes": return require_spec.isPColumnSpec(spec) && predicate.axes.every((matcher) => spec.axesSpec.some((axisSpec) => (matcher.type === void 0 || matcher.type === axisSpec.type) && (matcher.name === void 0 || matcher.name === axisSpec.name) && (matcher.domain === void 0 || Object.keys(matcher.domain).length === 0 || axisSpec.domain !== void 0 && Object.entries(matcher.domain).every(([domain, domainValue]) => axisSpec.domain[domain] === domainValue))));
|
|
20
|
+
case "has_axes": return require_spec.isPColumnSpec(spec) && predicate.axes.every((matcher) => spec.axesSpec.some((axisSpec) => (matcher.type === void 0 || matcher.type === axisSpec.type) && (matcher.name === void 0 || matcher.name === axisSpec.name) && (matcher.domain === void 0 || Object.keys(matcher.domain).length === 0 || axisSpec.domain !== void 0 && Object.entries(matcher.domain).every(([domain, domainValue]) => axisSpec.domain[domain] === domainValue)) && (matcher.contextDomain === void 0 || Object.keys(matcher.contextDomain).length === 0 || axisSpec.contextDomain !== void 0 && Object.entries(matcher.contextDomain).every(([key, value]) => axisSpec.contextDomain[key] === value))));
|
|
21
21
|
default: assertNever(predicate);
|
|
22
22
|
}
|
|
23
23
|
}
|
package/dist/pool/query.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.cjs","names":["isPColumnSpec"],"sources":["../../src/pool/query.ts"],"sourcesContent":["import type { AxisId } from \"../drivers\";\nimport type { PObjectSpec } from \"./spec\";\nimport { isPColumnSpec } from \"./spec\";\n\nexport type PSpecPredicate =\n | {\n type: \"and\" | \"or\";\n operands: PSpecPredicate[];\n }\n | {\n type: \"not\";\n operand: PSpecPredicate;\n }\n | {\n type: \"name\";\n name: string;\n }\n | {\n type: \"name_pattern\";\n pattern: string;\n }\n | {\n type: \"annotation\";\n annotation: string;\n value: string;\n }\n | {\n type: \"annotation_pattern\";\n annotation: string;\n pattern: string;\n }\n | {\n type: \"has_axes\";\n axes: Partial<AxisId>[];\n };\n\nfunction assertNever(x: never): never {\n throw new Error(\"Unexpected object: \" + x); // This is ok, because this is a possible runtime error\n}\n\nexport function executePSpecPredicate(predicate: PSpecPredicate, spec: PObjectSpec): boolean {\n switch (predicate.type) {\n case \"and\":\n for (const operator of predicate.operands)\n if (!executePSpecPredicate(operator, spec)) return false;\n return true;\n case \"or\":\n for (const operator of predicate.operands)\n if (executePSpecPredicate(operator, spec)) return true;\n return false;\n case \"not\":\n return !executePSpecPredicate(predicate.operand, spec);\n case \"name\":\n return isPColumnSpec(spec) && spec.name === predicate.name;\n case \"name_pattern\":\n return isPColumnSpec(spec) && Boolean(spec.name.match(predicate.pattern));\n case \"annotation\":\n return (\n isPColumnSpec(spec) &&\n spec.annotations !== undefined &&\n spec.annotations[predicate.annotation] === predicate.value\n );\n case \"annotation_pattern\":\n return (\n isPColumnSpec(spec) &&\n spec.annotations !== undefined &&\n spec.annotations[predicate.annotation] !== undefined &&\n Boolean(spec.annotations[predicate.annotation].match(predicate.pattern))\n );\n case \"has_axes\":\n return (\n isPColumnSpec(spec) &&\n predicate.axes.every((matcher) =>\n spec.axesSpec.some(\n (axisSpec) =>\n (matcher.type === undefined || matcher.type === axisSpec.type) &&\n (matcher.name === undefined || matcher.name === axisSpec.name) &&\n (matcher.domain === undefined ||\n Object.keys(matcher.domain).length === 0 ||\n (axisSpec.domain !== undefined &&\n Object.entries(matcher.domain).every(\n ([domain, domainValue]) => axisSpec.domain![domain] === domainValue,\n ))),\n ),\n )\n );\n default:\n assertNever(predicate);\n }\n}\n"],"mappings":";;;AAoCA,SAAS,YAAY,GAAiB;AACpC,OAAM,IAAI,MAAM,wBAAwB,EAAE;;AAG5C,SAAgB,sBAAsB,WAA2B,MAA4B;AAC3F,SAAQ,UAAU,MAAlB;EACE,KAAK;AACH,QAAK,MAAM,YAAY,UAAU,SAC/B,KAAI,CAAC,sBAAsB,UAAU,KAAK,CAAE,QAAO;AACrD,UAAO;EACT,KAAK;AACH,QAAK,MAAM,YAAY,UAAU,SAC/B,KAAI,sBAAsB,UAAU,KAAK,CAAE,QAAO;AACpD,UAAO;EACT,KAAK,MACH,QAAO,CAAC,sBAAsB,UAAU,SAAS,KAAK;EACxD,KAAK,OACH,QAAOA,2BAAc,KAAK,IAAI,KAAK,SAAS,UAAU;EACxD,KAAK,eACH,QAAOA,2BAAc,KAAK,IAAI,QAAQ,KAAK,KAAK,MAAM,UAAU,QAAQ,CAAC;EAC3E,KAAK,aACH,QACEA,2BAAc,KAAK,IACnB,KAAK,gBAAgB,UACrB,KAAK,YAAY,UAAU,gBAAgB,UAAU;EAEzD,KAAK,qBACH,QACEA,2BAAc,KAAK,IACnB,KAAK,gBAAgB,UACrB,KAAK,YAAY,UAAU,gBAAgB,UAC3C,QAAQ,KAAK,YAAY,UAAU,YAAY,MAAM,UAAU,QAAQ,CAAC;EAE5E,KAAK,WACH,QACEA,2BAAc,KAAK,IACnB,UAAU,KAAK,OAAO,YACpB,KAAK,SAAS,MACX,cACE,QAAQ,SAAS,UAAa,QAAQ,SAAS,SAAS,UACxD,QAAQ,SAAS,UAAa,QAAQ,SAAS,SAAS,UACxD,QAAQ,WAAW,UAClB,OAAO,KAAK,QAAQ,OAAO,CAAC,WAAW,KACtC,SAAS,WAAW,UACnB,OAAO,QAAQ,QAAQ,OAAO,CAAC,OAC5B,CAAC,QAAQ,iBAAiB,SAAS,OAAQ,YAAY,YACzD,EACR,CACF;EAEL,QACE,aAAY,UAAU"}
|
|
1
|
+
{"version":3,"file":"query.cjs","names":["isPColumnSpec"],"sources":["../../src/pool/query.ts"],"sourcesContent":["import type { AxisId } from \"../drivers\";\nimport type { PObjectSpec } from \"./spec\";\nimport { isPColumnSpec } from \"./spec\";\n\nexport type PSpecPredicate =\n | {\n type: \"and\" | \"or\";\n operands: PSpecPredicate[];\n }\n | {\n type: \"not\";\n operand: PSpecPredicate;\n }\n | {\n type: \"name\";\n name: string;\n }\n | {\n type: \"name_pattern\";\n pattern: string;\n }\n | {\n type: \"annotation\";\n annotation: string;\n value: string;\n }\n | {\n type: \"annotation_pattern\";\n annotation: string;\n pattern: string;\n }\n | {\n type: \"has_axes\";\n axes: Partial<AxisId>[];\n };\n\nfunction assertNever(x: never): never {\n throw new Error(\"Unexpected object: \" + x); // This is ok, because this is a possible runtime error\n}\n\nexport function executePSpecPredicate(predicate: PSpecPredicate, spec: PObjectSpec): boolean {\n switch (predicate.type) {\n case \"and\":\n for (const operator of predicate.operands)\n if (!executePSpecPredicate(operator, spec)) return false;\n return true;\n case \"or\":\n for (const operator of predicate.operands)\n if (executePSpecPredicate(operator, spec)) return true;\n return false;\n case \"not\":\n return !executePSpecPredicate(predicate.operand, spec);\n case \"name\":\n return isPColumnSpec(spec) && spec.name === predicate.name;\n case \"name_pattern\":\n return isPColumnSpec(spec) && Boolean(spec.name.match(predicate.pattern));\n case \"annotation\":\n return (\n isPColumnSpec(spec) &&\n spec.annotations !== undefined &&\n spec.annotations[predicate.annotation] === predicate.value\n );\n case \"annotation_pattern\":\n return (\n isPColumnSpec(spec) &&\n spec.annotations !== undefined &&\n spec.annotations[predicate.annotation] !== undefined &&\n Boolean(spec.annotations[predicate.annotation].match(predicate.pattern))\n );\n case \"has_axes\":\n return (\n isPColumnSpec(spec) &&\n predicate.axes.every((matcher) =>\n spec.axesSpec.some(\n (axisSpec) =>\n (matcher.type === undefined || matcher.type === axisSpec.type) &&\n (matcher.name === undefined || matcher.name === axisSpec.name) &&\n (matcher.domain === undefined ||\n Object.keys(matcher.domain).length === 0 ||\n (axisSpec.domain !== undefined &&\n Object.entries(matcher.domain).every(\n ([domain, domainValue]) => axisSpec.domain![domain] === domainValue,\n ))) &&\n (matcher.contextDomain === undefined ||\n Object.keys(matcher.contextDomain).length === 0 ||\n (axisSpec.contextDomain !== undefined &&\n Object.entries(matcher.contextDomain).every(\n ([key, value]) => axisSpec.contextDomain![key] === value,\n ))),\n ),\n )\n );\n default:\n assertNever(predicate);\n }\n}\n"],"mappings":";;;AAoCA,SAAS,YAAY,GAAiB;AACpC,OAAM,IAAI,MAAM,wBAAwB,EAAE;;AAG5C,SAAgB,sBAAsB,WAA2B,MAA4B;AAC3F,SAAQ,UAAU,MAAlB;EACE,KAAK;AACH,QAAK,MAAM,YAAY,UAAU,SAC/B,KAAI,CAAC,sBAAsB,UAAU,KAAK,CAAE,QAAO;AACrD,UAAO;EACT,KAAK;AACH,QAAK,MAAM,YAAY,UAAU,SAC/B,KAAI,sBAAsB,UAAU,KAAK,CAAE,QAAO;AACpD,UAAO;EACT,KAAK,MACH,QAAO,CAAC,sBAAsB,UAAU,SAAS,KAAK;EACxD,KAAK,OACH,QAAOA,2BAAc,KAAK,IAAI,KAAK,SAAS,UAAU;EACxD,KAAK,eACH,QAAOA,2BAAc,KAAK,IAAI,QAAQ,KAAK,KAAK,MAAM,UAAU,QAAQ,CAAC;EAC3E,KAAK,aACH,QACEA,2BAAc,KAAK,IACnB,KAAK,gBAAgB,UACrB,KAAK,YAAY,UAAU,gBAAgB,UAAU;EAEzD,KAAK,qBACH,QACEA,2BAAc,KAAK,IACnB,KAAK,gBAAgB,UACrB,KAAK,YAAY,UAAU,gBAAgB,UAC3C,QAAQ,KAAK,YAAY,UAAU,YAAY,MAAM,UAAU,QAAQ,CAAC;EAE5E,KAAK,WACH,QACEA,2BAAc,KAAK,IACnB,UAAU,KAAK,OAAO,YACpB,KAAK,SAAS,MACX,cACE,QAAQ,SAAS,UAAa,QAAQ,SAAS,SAAS,UACxD,QAAQ,SAAS,UAAa,QAAQ,SAAS,SAAS,UACxD,QAAQ,WAAW,UAClB,OAAO,KAAK,QAAQ,OAAO,CAAC,WAAW,KACtC,SAAS,WAAW,UACnB,OAAO,QAAQ,QAAQ,OAAO,CAAC,OAC5B,CAAC,QAAQ,iBAAiB,SAAS,OAAQ,YAAY,YACzD,MACJ,QAAQ,kBAAkB,UACzB,OAAO,KAAK,QAAQ,cAAc,CAAC,WAAW,KAC7C,SAAS,kBAAkB,UAC1B,OAAO,QAAQ,QAAQ,cAAc,CAAC,OACnC,CAAC,KAAK,WAAW,SAAS,cAAe,SAAS,MACpD,EACR,CACF;EAEL,QACE,aAAY,UAAU"}
|
package/dist/pool/query.js
CHANGED
|
@@ -17,7 +17,7 @@ function executePSpecPredicate(predicate, spec) {
|
|
|
17
17
|
case "name_pattern": return isPColumnSpec(spec) && Boolean(spec.name.match(predicate.pattern));
|
|
18
18
|
case "annotation": return isPColumnSpec(spec) && spec.annotations !== void 0 && spec.annotations[predicate.annotation] === predicate.value;
|
|
19
19
|
case "annotation_pattern": return isPColumnSpec(spec) && spec.annotations !== void 0 && spec.annotations[predicate.annotation] !== void 0 && Boolean(spec.annotations[predicate.annotation].match(predicate.pattern));
|
|
20
|
-
case "has_axes": return isPColumnSpec(spec) && predicate.axes.every((matcher) => spec.axesSpec.some((axisSpec) => (matcher.type === void 0 || matcher.type === axisSpec.type) && (matcher.name === void 0 || matcher.name === axisSpec.name) && (matcher.domain === void 0 || Object.keys(matcher.domain).length === 0 || axisSpec.domain !== void 0 && Object.entries(matcher.domain).every(([domain, domainValue]) => axisSpec.domain[domain] === domainValue))));
|
|
20
|
+
case "has_axes": return isPColumnSpec(spec) && predicate.axes.every((matcher) => spec.axesSpec.some((axisSpec) => (matcher.type === void 0 || matcher.type === axisSpec.type) && (matcher.name === void 0 || matcher.name === axisSpec.name) && (matcher.domain === void 0 || Object.keys(matcher.domain).length === 0 || axisSpec.domain !== void 0 && Object.entries(matcher.domain).every(([domain, domainValue]) => axisSpec.domain[domain] === domainValue)) && (matcher.contextDomain === void 0 || Object.keys(matcher.contextDomain).length === 0 || axisSpec.contextDomain !== void 0 && Object.entries(matcher.contextDomain).every(([key, value]) => axisSpec.contextDomain[key] === value))));
|
|
21
21
|
default: assertNever(predicate);
|
|
22
22
|
}
|
|
23
23
|
}
|