blob: 6c9a0404d7e3bf641c5592502c8839fc4b620f9d [file] [log] [blame]
/**
*
* Copyright (c) 2021 Silicon Labs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* This module provides queries related to attributes.
*
* @module DB API: attribute queries.
*/
const dbApi = require('./db-api.js')
const dbMapping = require('./db-mapping.js')
const dbCache = require('./db-cache')
/**
* Promises to select all endpoint type attributes filtered by EndpointTypeRef and ClusterRef.
*
* @export
* @param {*} db
* @param {*} endpointTypeRef
* @param {*} endpointTypeClusterRef
* @returns Records of selected Endpoint Type Attributes.
*/
async function selectEndpointTypeAttributesByEndpointTypeRefAndClusterRef(
db,
endpointTypeRef,
endpointTypeClusterRef
) {
let rows = await dbApi.dbAll(
db,
`
SELECT
ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_ATTRIBUTE_ID,
ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_REF,
ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF AS 'CLUSTER_REF',
ENDPOINT_TYPE_ATTRIBUTE.ATTRIBUTE_REF,
ENDPOINT_TYPE_ATTRIBUTE.INCLUDED,
ENDPOINT_TYPE_ATTRIBUTE.STORAGE_OPTION,
ENDPOINT_TYPE_ATTRIBUTE.SINGLETON,
ENDPOINT_TYPE_ATTRIBUTE.BOUNDED,
ENDPOINT_TYPE_ATTRIBUTE.DEFAULT_VALUE,
ENDPOINT_TYPE_ATTRIBUTE.INCLUDED_REPORTABLE,
ENDPOINT_TYPE_ATTRIBUTE.MIN_INTERVAL,
ENDPOINT_TYPE_ATTRIBUTE.MAX_INTERVAL,
ENDPOINT_TYPE_ATTRIBUTE.REPORTABLE_CHANGE
FROM
ENDPOINT_TYPE_ATTRIBUTE
INNER JOIN
ENDPOINT_TYPE_CLUSTER
ON
ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF = ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID
WHERE
ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_REF = ? and ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF = ?`,
[endpointTypeRef, endpointTypeClusterRef]
)
return rows.map(dbMapping.map.endpointTypeAttribute)
}
/**
* Promises to duplicate endpoint type attributes.
*
* @export
* @param {*} db
* @param {*} newEndpointTypeClusterRef
* @param {*} attribute
* @returns Promise duplicated endpoint type attribute's id.
*/
async function duplicateEndpointTypeAttribute(
db,
newEndpointTypeClusterRef,
attribute
) {
return await dbApi.dbInsert(
db,
`INSERT INTO ENDPOINT_TYPE_ATTRIBUTE (
ENDPOINT_TYPE_CLUSTER_REF,
ATTRIBUTE_REF,
INCLUDED,
STORAGE_OPTION,
SINGLETON,
BOUNDED,
DEFAULT_VALUE,
INCLUDED_REPORTABLE,
MIN_INTERVAL,
MAX_INTERVAL,
REPORTABLE_CHANGE)
VALUES (
?,
?,
?,
?,
?,
?,
?,
?,
?,
?,
?
)`,
[
newEndpointTypeClusterRef,
attribute.attributeRef,
attribute.included,
attribute.storageOption,
attribute.singleton,
attribute.bounded,
attribute.defaultValue,
attribute.includedReportable,
attribute.minInterval,
attribute.maxInterval,
attribute.reportableChange
]
)
}
/**
* Returns a promise of data for attributes inside an endpoint type.
*
* @param {*} db
* @param {*} endpointTypeId
* @param {*} packageIds
* @param {*} side
* @returns Promise that resolves with the attribute data.
*/
async function selectAllAttributeDetailsFromEnabledClusters(
db,
endpointsAndClusters,
packageIds,
side = null
) {
let sideFilter = ''
if (side) {
sideFilter = ` AND ATTRIBUTE.SIDE = '${side}' `
}
let endpointTypeClusterRef = endpointsAndClusters
.map((ep) => ep.endpointTypeClusterRef)
.toString()
return dbApi
.dbAll(
db,
`
SELECT
ATTRIBUTE.ATTRIBUTE_ID,
ATTRIBUTE.NAME,
ATTRIBUTE.CODE,
ATTRIBUTE.SIDE,
ATTRIBUTE.TYPE,
ATTRIBUTE.DEFINE,
ATTRIBUTE.MANUFACTURER_CODE,
ENDPOINT_TYPE_CLUSTER.SIDE,
CLUSTER.NAME AS CLUSTER_NAME,
ENDPOINT_TYPE_CLUSTER.ENABLED,
CASE
WHEN
ATTRIBUTE.ARRAY_TYPE IS NOT NULL
THEN
1
ELSE
0
END AS IS_ARRAY,
ATTRIBUTE.IS_WRITABLE,
ATTRIBUTE.IS_READABLE,
ATTRIBUTE.IS_NULLABLE,
ATTRIBUTE.MAX_LENGTH,
ATTRIBUTE.MIN_LENGTH,
ATTRIBUTE.MIN,
ATTRIBUTE.MAX,
ATTRIBUTE.ARRAY_TYPE,
ATTRIBUTE.MUST_USE_TIMED_WRITE,
ATTRIBUTE.IS_SCENE_REQUIRED,
ATTRIBUTE.IS_OPTIONAL,
CASE
WHEN
ATTRIBUTE.CLUSTER_REF IS NULL
THEN
1
ELSE
0
END AS IS_GLOBAL_ATTRIBUTE,
ENDPOINT_TYPE_ATTRIBUTE.INCLUDED_REPORTABLE,
ENDPOINT_TYPE_ATTRIBUTE.STORAGE_OPTION,
ENDPOINT_TYPE_ATTRIBUTE.SINGLETON,
ENDPOINT_TYPE_ATTRIBUTE.BOUNDED,
ENDPOINT_TYPE_ATTRIBUTE.INCLUDED,
ENDPOINT_TYPE_ATTRIBUTE.DEFAULT_VALUE,
ENDPOINT_TYPE_ATTRIBUTE.MIN_INTERVAL,
ENDPOINT_TYPE_ATTRIBUTE.MAX_INTERVAL,
ENDPOINT_TYPE_ATTRIBUTE.REPORTABLE_CHANGE,
ATTRIBUTE.API_MATURITY,
ATTRIBUTE.IS_CHANGE_OMITTED,
ATTRIBUTE.PERSISTENCE
FROM ATTRIBUTE
INNER JOIN ENDPOINT_TYPE_ATTRIBUTE
ON ATTRIBUTE.ATTRIBUTE_ID = ENDPOINT_TYPE_ATTRIBUTE.ATTRIBUTE_REF
INNER JOIN ENDPOINT_TYPE_CLUSTER
ON ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF = ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID
INNER JOIN CLUSTER
ON ENDPOINT_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID
WHERE ENDPOINT_TYPE_CLUSTER.CLUSTER_REF IN (${endpointTypeClusterRef})
AND ENDPOINT_TYPE_ATTRIBUTE.INCLUDED = 1
AND ENDPOINT_TYPE_CLUSTER.ENABLED = 1
AND ATTRIBUTE.PACKAGE_REF IN (${dbApi.toInClause(packageIds)})
${sideFilter}
GROUP BY CLUSTER.MANUFACTURER_CODE, CLUSTER.CODE, ATTRIBUTE.MANUFACTURER_CODE, ATTRIBUTE.CODE, ATTRIBUTE.SIDE
ORDER BY ATTRIBUTE.CODE
`
)
.then((rows) => rows.map(dbMapping.map.endpointTypeAttributeExtended))
}
/**
* Returns a promise of data for manufacturing/non-manufacturing specific attributes
* inside an endpoint type.
*
* @param db
* @param endpointTypeId
* @param isManufacturingSpecific,
* @param packageIds
* @returns Promise that resolves with the manufacturing/non-manufacturing
* specific attribute data.
*/
async function selectAttributeDetailsFromAllEndpointTypesAndClustersUtil(
db,
endpointsAndClusters,
isManufacturingSpecific,
packageIds
) {
let endpointTypeIds = endpointsAndClusters
.map((ep) => ep.endpointId)
.toString()
let endpointClusterIds = endpointsAndClusters
.map((ep) => ep.endpointClusterId)
.toString()
return dbApi
.dbAll(
db,
`
SELECT
ATTRIBUTE.ATTRIBUTE_ID,
ATTRIBUTE.NAME,
ATTRIBUTE.CODE,
ATTRIBUTE.SIDE,
ATTRIBUTE.TYPE,
ATTRIBUTE.DEFINE,
ATTRIBUTE.MANUFACTURER_CODE,
ENDPOINT_TYPE_CLUSTER.SIDE,
CLUSTER.NAME AS CLUSTER_NAME,
ENDPOINT_TYPE_CLUSTER.ENABLED,
ATTRIBUTE.API_MATURITY,
ATTRIBUTE.IS_CHANGE_OMITTED,
ATTRIBUTE.PERSISTENCE
FROM
ATTRIBUTE
INNER JOIN
ENDPOINT_TYPE_ATTRIBUTE
ON ATTRIBUTE.ATTRIBUTE_ID = ENDPOINT_TYPE_ATTRIBUTE.ATTRIBUTE_REF
INNER JOIN
ENDPOINT_TYPE_CLUSTER
ON ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF = ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID
INNER JOIN
CLUSTER
ON ATTRIBUTE.CLUSTER_REF = CLUSTER.CLUSTER_ID
WHERE
ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_REF IN (${endpointTypeIds})
AND ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF in (${endpointClusterIds})
AND ATTRIBUTE.MANUFACTURER_CODE IS ` +
(isManufacturingSpecific ? `NOT ` : ``) +
`NULL
AND ENDPOINT_TYPE_ATTRIBUTE.INCLUDED = 1
AND ATTRIBUTE.PACKAGE_REF IN (${dbApi.toInClause(packageIds)})
GROUP BY ATTRIBUTE.NAME
`
)
.then((rows) => rows.map(dbMapping.map.endpointTypeAttributeExtended))
}
/**
* Returns a promise of data for manufacturing specific attributes inside an endpoint type.
*
* @param db
* @param endpointTypeId
* @param packageIds
* @returns Promise that resolves with the manufacturing specific attribute data.
*/
async function selectManufacturerSpecificAttributeDetailsFromAllEndpointTypesAndClusters(
db,
endpointsAndClusters,
packageIds
) {
return selectAttributeDetailsFromAllEndpointTypesAndClustersUtil(
db,
endpointsAndClusters,
true,
packageIds
)
}
/**
* Returns a promise of data for attributes with no manufacturing specific information inside an endpoint type.
*
* @param db
* @param endpointTypeId
* @param packageIds
* @returns Promise that resolves with the non-manufacturing specific attribute data.
*/
async function selectNonManufacturerSpecificAttributeDetailsFromAllEndpointTypesAndClusters(
db,
endpointsAndClusters,
packageIds
) {
return selectAttributeDetailsFromAllEndpointTypesAndClustersUtil(
db,
endpointsAndClusters,
false,
packageIds
)
}
/**
* Returns a promise of data for attributes inside an endpoint type
* that either have a default or a bounded attribute.
*
* @param {*} db
* @param {*} endpointTypeId
* @param {*} packageIds
* @returns Promise that resolves with the attribute data.
*/
async function selectAttributeDetailsWithABoundFromEnabledClusters(
db,
endpointsAndClusters,
packageIds
) {
let endpointClusterIds = endpointsAndClusters
.map((ep) => ep.endpointClusterId)
.toString()
let mapFunction = (x) => {
return {
id: x.ATTRIBUTE_ID,
name: x.NAME,
side: x.SIDE,
clusterName: x.CLUSTER_NAME,
attributeMinValue: x.MIN,
attributeMaxValue: x.MAX,
defaultValue: x.DEFAULT_VALUE
}
}
return dbApi
.dbAll(
db,
`
SELECT
ATTRIBUTE.ATTRIBUTE_ID,
ATTRIBUTE.NAME,
ATTRIBUTE.SIDE,
CLUSTER.NAME AS CLUSTER_NAME,
ATTRIBUTE.MIN,
ATTRIBUTE.MAX,
ENDPOINT_TYPE_ATTRIBUTE.DEFAULT_VALUE
FROM
ATTRIBUTE
INNER JOIN
ENDPOINT_TYPE_ATTRIBUTE
ON
ATTRIBUTE.ATTRIBUTE_ID = ENDPOINT_TYPE_ATTRIBUTE.ATTRIBUTE_REF
INNER JOIN
ENDPOINT_TYPE_CLUSTER
ON
ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF = ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID
INNER JOIN
CLUSTER
ON
CLUSTER.CLUSTER_ID = ENDPOINT_TYPE_CLUSTER.CLUSTER_REF
INNER JOIN
ATOMIC
ON
ATOMIC.NAME = ATTRIBUTE.TYPE
WHERE ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF in (${endpointClusterIds})
AND ENDPOINT_TYPE_ATTRIBUTE.INCLUDED = 1 AND ENDPOINT_TYPE_ATTRIBUTE.BOUNDED !=0
AND ENDPOINT_TYPE_CLUSTER.ENABLED=1
AND ATTRIBUTE.PACKAGE_REF IN (${dbApi.toInClause(packageIds)})
GROUP BY CLUSTER.MANUFACTURER_CODE, CLUSTER.CODE, ATTRIBUTE.MANUFACTURER_CODE, ATTRIBUTE.NAME, ATTRIBUTE.SIDE
`
)
.then((rows) => rows.map(mapFunction))
}
/**
* The enabled attributes details across all endpoints and clusters.
* @param db
* @param endpointsAndClusters
* @param packageIds
* @returns The enabled attributes details across all endpoints and clusters.
*/
async function selectAttributeDetailsFromEnabledClusters(
db,
endpointsAndClusters,
packageIds
) {
let endpointClusterIds = endpointsAndClusters
.map((ep) => ep.endpointClusterId)
.toString()
let mapFunction = (x) => {
return {
id: x.ATTRIBUTE_ID,
name: x.NAME,
code: x.CODE,
side: x.SIDE,
type: x.TYPE,
define: x.DEFINE,
mfgCode: x.MANUFACTURER_CODE
? x.MANUFACTURER_CODE
: x.CLUSTER_MANUFACTURER_CODE,
isWritable: x.IS_WRITABLE,
isReadable: x.IS_READABLE,
clusterId: x.CLUSTER_ID,
clusterSide: x.CLUSTER_SIDE,
clusterName: x.CLUSTER_NAME,
clusterDefine: x.CLUSTER_DEFINE,
clusterCode: x.CLUSTER_CODE,
isAttributeBounded: x.BOUNDED,
storageOption: x.STORAGE_OPTION,
isSingleton: x.SINGLETON,
defaultValue: x.DEFAULT_VALUE,
attributeSize: x.ATOMIC_SIZE,
clusterIndex: x.CLUSTER_INDEX,
mfgAttributeCount: x.MANUFACTURING_SPECIFIC_ATTRIBUTE_COUNT,
singletonAttributeSize: x.SINGLETON_ATTRIBUTE_SIZE,
singletonTokenizedAttributeSize: x.SINGLETON_TOKENIZED_ATTRIBUTE_SIZE,
nonSingletonTokenizedAttributeSize:
x.NON_SINGLETON_TOKENIZED_ATTRIBUTE_SIZE,
tokenizedAttributeSize: x.TOKENIZED_ATTRIBUTE_SIZE,
maxAttributeSize: x.MAX_ATTRIBUTE_SIZE,
maxTokenAttributeSize: x.MAX_TOKEN_ATTRIBUTE_SIZE,
isString: x.IS_STRING,
isManufacturingSpecific: dbApi.toDbBool(
x.MANUFACTURER_CODE | x.CLUSTER_MANUFACTURER_CODE
) // Is Attribute mfg specific or not
}
}
return dbApi
.dbAll(
db,
`
SELECT
ATOMIC.IS_STRING AS IS_STRING,
ATTRIBUTE.ATTRIBUTE_ID,
ATTRIBUTE.NAME,
ATTRIBUTE.CODE,
ATTRIBUTE.SIDE,
ATTRIBUTE.TYPE,
ATTRIBUTE.DEFINE,
ATTRIBUTE.MANUFACTURER_CODE,
ATTRIBUTE.IS_WRITABLE,
ATTRIBUTE.IS_READABLE,
CLUSTER.CLUSTER_ID AS CLUSTER_ID,
ENDPOINT_TYPE_CLUSTER.SIDE AS CLUSTER_SIDE,
CLUSTER.NAME AS CLUSTER_NAME,
CLUSTER.DEFINE AS CLUSTER_DEFINE,
CLUSTER.CODE AS CLUSTER_CODE,
CLUSTER.MANUFACTURER_CODE AS CLUSTER_MANUFACTURER_CODE,
ENDPOINT_TYPE_ATTRIBUTE.BOUNDED,
ENDPOINT_TYPE_ATTRIBUTE.STORAGE_OPTION,
ENDPOINT_TYPE_ATTRIBUTE.SINGLETON,
ENDPOINT_TYPE_ATTRIBUTE.DEFAULT_VALUE,
CASE
WHEN ATOMIC.IS_STRING=1 THEN
CASE WHEN ATOMIC.IS_LONG=0 THEN ATTRIBUTE.MAX_LENGTH+1
WHEN ATOMIC.IS_LONG=1 THEN ATTRIBUTE.MAX_LENGTH+2
ELSE ATOMIC.ATOMIC_SIZE
END
WHEN ATOMIC.ATOMIC_SIZE IS NULL THEN ATTRIBUTE.MAX_LENGTH
ELSE ATOMIC.ATOMIC_SIZE
END AS ATOMIC_SIZE,
ROW_NUMBER() OVER (PARTITION BY CLUSTER.MANUFACTURER_CODE, CLUSTER.CODE, ENDPOINT_TYPE_CLUSTER.SIDE ORDER BY CLUSTER.MANUFACTURER_CODE, CLUSTER.CODE, ATTRIBUTE.CODE, ATTRIBUTE.MANUFACTURER_CODE) CLUSTER_INDEX,
COUNT (CASE WHEN ATTRIBUTE.MANUFACTURER_CODE THEN ATTRIBUTE.MANUFACTURER_CODE
WHEN CLUSTER.MANUFACTURER_CODE THEN CLUSTER.MANUFACTURER_CODE
ELSE NULL
END) OVER () AS MANUFACTURING_SPECIFIC_ATTRIBUTE_COUNT,
SUM (CASE WHEN ENDPOINT_TYPE_ATTRIBUTE.SINGLETON=1 THEN
CASE WHEN ATOMIC.IS_STRING=1 THEN
CASE WHEN ATOMIC.IS_LONG=0 THEN ATTRIBUTE.MAX_LENGTH+1
WHEN ATOMIC.IS_LONG=1 THEN ATTRIBUTE.MAX_LENGTH+2
ELSE ATOMIC.ATOMIC_SIZE
END
WHEN ATOMIC.ATOMIC_SIZE IS NULL THEN ATTRIBUTE.MAX_LENGTH
ELSE ATOMIC.ATOMIC_SIZE
END
ELSE 0 END) OVER () AS SINGLETON_ATTRIBUTE_SIZE,
SUM (CASE WHEN ENDPOINT_TYPE_ATTRIBUTE.SINGLETON=1 THEN
CASE WHEN ENDPOINT_TYPE_ATTRIBUTE.STORAGE_OPTION='NVM' THEN
1
ELSE
0
END
ELSE 0 END) OVER () AS SINGLETON_TOKENIZED_ATTRIBUTE_SIZE,
SUM (CASE WHEN ENDPOINT_TYPE_ATTRIBUTE.SINGLETON=0 THEN
CASE WHEN ENDPOINT_TYPE_ATTRIBUTE.STORAGE_OPTION='NVM' THEN
1
ELSE
0
END
ELSE 0 END) OVER () AS NON_SINGLETON_TOKENIZED_ATTRIBUTE_SIZE,
SUM (CASE WHEN ENDPOINT_TYPE_ATTRIBUTE.STORAGE_OPTION='NVM' THEN
1
ELSE
0
END) OVER () AS TOKENIZED_ATTRIBUTE_SIZE,
MAX(CASE WHEN ATOMIC.IS_STRING=1 THEN
CASE WHEN ATOMIC.IS_LONG=0 THEN ATTRIBUTE.MAX_LENGTH+1
WHEN ATOMIC.IS_LONG=1 THEN ATTRIBUTE.MAX_LENGTH+2
ELSE ATOMIC.ATOMIC_SIZE
END
WHEN ATOMIC.ATOMIC_SIZE IS NULL THEN ATTRIBUTE.MAX_LENGTH
ELSE ATOMIC.ATOMIC_SIZE
END) OVER () AS MAX_ATTRIBUTE_SIZE,
MAX(CASE WHEN ENDPOINT_TYPE_ATTRIBUTE.STORAGE_OPTION='NVM' THEN
CASE WHEN ATOMIC.IS_STRING=1 THEN
CASE WHEN ATOMIC.IS_LONG=0 THEN ATTRIBUTE.MAX_LENGTH+1
WHEN ATOMIC.IS_LONG=1 THEN ATTRIBUTE.MAX_LENGTH+2
ELSE ATOMIC.ATOMIC_SIZE
END
WHEN ATOMIC.ATOMIC_SIZE IS NULL THEN ATTRIBUTE.MAX_LENGTH
ELSE ATOMIC.ATOMIC_SIZE
END
ELSE
0
END) OVER () AS MAX_TOKEN_ATTRIBUTE_SIZE
FROM ATTRIBUTE
INNER JOIN ENDPOINT_TYPE_ATTRIBUTE
ON ATTRIBUTE.ATTRIBUTE_ID = ENDPOINT_TYPE_ATTRIBUTE.ATTRIBUTE_REF
INNER JOIN ENDPOINT_TYPE_CLUSTER
ON ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF = ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID
INNER JOIN CLUSTER
ON ENDPOINT_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID
INNER JOIN ATOMIC
ON ATOMIC.NAME = ATTRIBUTE.TYPE
WHERE ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF IN (${endpointClusterIds})
AND ENDPOINT_TYPE_ATTRIBUTE.INCLUDED = 1 AND ENDPOINT_TYPE_CLUSTER.ENABLED=1 AND ENDPOINT_TYPE_CLUSTER.SIDE=ATTRIBUTE.SIDE
AND ATTRIBUTE.PACKAGE_REF IN (${dbApi.toInClause(packageIds)})
GROUP BY CLUSTER.MANUFACTURER_CODE, CLUSTER.CODE, ATTRIBUTE.CODE, ATTRIBUTE.MANUFACTURER_CODE, ATTRIBUTE.SIDE
ORDER BY CLUSTER.MANUFACTURER_CODE, CLUSTER.CODE, ENDPOINT_TYPE_CLUSTER.SIDE, ATTRIBUTE.CODE, ATTRIBUTE.MANUFACTURER_CODE
`
)
.then((rows) => rows.map(mapFunction))
}
/**
*
* @param db
* @param endpointsAndClusters
* @param packageIds
* @returns
* Default values for the attributes longer than a pointer,
* in a form of a binary blob. All attribute values with size greater than 2 bytes.
* Excluding 0 values and externally saved values
* Union is used to get separate entries of attributes w.r.t to default, minimum
* and maximum values
*/
async function selectAttributeBoundDetails(
db,
endpointsAndClusters,
packageIds
) {
let endpointClusterIds = endpointsAndClusters
.map((ep) => ep.endpointClusterId)
.toString()
let mapFunction = (x) => {
return {
id: x.ATTRIBUTE_ID,
name: x.NAME,
side: x.SIDE,
clusterName: x.CLUSTER_NAME,
clusterMfgCode: x.CLUSTER_MANUFACTURER_CODE,
defaultValue: x.ATT_VALUE,
attributeSize: x.ATOMIC_SIZE,
attributeValueType: x.ATTRIBUTE_VALUE_TYPE,
arrayIndex: x.ARRAY_INDEX,
isString: x.IS_STRING,
isSingleton: x.SINGLETON
}
}
return dbApi
.dbAll(
db,
`SELECT
*, SUM(ATOMIC_SIZE) OVER (ORDER BY CLUSTER_MANUFACTURER_CODE, CLUSTER_NAME ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS ARRAY_INDEX FROM (
SELECT
ATTRIBUTE.ATTRIBUTE_ID AS ATTRIBUTE_ID,
ATTRIBUTE.NAME AS NAME,
ATTRIBUTE.SIDE AS SIDE,
CLUSTER.NAME AS CLUSTER_NAME,
CLUSTER.MANUFACTURER_CODE AS CLUSTER_MANUFACTURER_CODE,
ENDPOINT_TYPE_ATTRIBUTE.DEFAULT_VALUE AS ATT_VALUE,
CASE
WHEN ATOMIC.IS_STRING=1 THEN
CASE WHEN ATOMIC.IS_LONG=0 THEN ATTRIBUTE.MAX_LENGTH+1
WHEN ATOMIC.IS_LONG=1 THEN ATTRIBUTE.MAX_LENGTH+2
ELSE ATOMIC.ATOMIC_SIZE
END
WHEN ATOMIC.ATOMIC_SIZE IS NULL THEN ATTRIBUTE.MAX_LENGTH
ELSE ATOMIC.ATOMIC_SIZE
END AS ATOMIC_SIZE,
'DEFAULT' as ATTRIBUTE_VALUE_TYPE,
ATOMIC.IS_STRING AS IS_STRING,
ENDPOINT_TYPE_ATTRIBUTE.SINGLETON
FROM ATTRIBUTE
INNER JOIN ENDPOINT_TYPE_ATTRIBUTE
ON ATTRIBUTE.ATTRIBUTE_ID = ENDPOINT_TYPE_ATTRIBUTE.ATTRIBUTE_REF
INNER JOIN ENDPOINT_TYPE_CLUSTER
ON ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF = ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID
INNER JOIN CLUSTER
ON ENDPOINT_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID
INNER JOIN ATOMIC
ON ATOMIC.NAME = ATTRIBUTE.TYPE
WHERE ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF in (${endpointClusterIds})
AND ENDPOINT_TYPE_CLUSTER.SIDE = ATTRIBUTE.SIDE AND ENDPOINT_TYPE_CLUSTER.ENABLED=1
AND (CASE
WHEN ATOMIC.IS_STRING=1 THEN
CASE WHEN ATOMIC.IS_LONG=0 THEN ATTRIBUTE.MAX_LENGTH+1
WHEN ATOMIC.IS_LONG=1 THEN ATTRIBUTE.MAX_LENGTH+2
ELSE ATOMIC.ATOMIC_SIZE
END
WHEN ATOMIC.ATOMIC_SIZE IS NULL THEN ATTRIBUTE.MAX_LENGTH
ELSE ATOMIC.ATOMIC_SIZE
END) > 2 AND ENDPOINT_TYPE_ATTRIBUTE.INCLUDED = 1 AND ATT_VALUE IS NOT NULL AND ATT_VALUE != "" AND REPLACE(ATT_VALUE, '0', '')!='x' AND REPLACE(ATT_VALUE, '0', '')!=''
AND ATTRIBUTE.PACKAGE_REF IN (${dbApi.toInClause(packageIds)})
GROUP BY CLUSTER.MANUFACTURER_CODE, CLUSTER.CODE, ATTRIBUTE.CODE, ATTRIBUTE.MANUFACTURER_CODE, ATTRIBUTE.SIDE
UNION
SELECT
ATTRIBUTE.ATTRIBUTE_ID AS ATTRIBUTE_ID,
ATTRIBUTE.NAME AS NAME,
ATTRIBUTE.SIDE AS SIDE,
CLUSTER.NAME AS CLUSTER_NAME,
CLUSTER.MANUFACTURER_CODE AS CLUSTER_MANUFACTURER_CODE,
ATTRIBUTE.MIN AS ATT_VALUE,
CASE
WHEN ATOMIC.IS_STRING=1 THEN
CASE WHEN ATOMIC.IS_LONG=0 THEN ATTRIBUTE.MAX_LENGTH+1
WHEN ATOMIC.IS_LONG=1 THEN ATTRIBUTE.MAX_LENGTH+2
ELSE ATOMIC.ATOMIC_SIZE
END
WHEN ATOMIC.ATOMIC_SIZE IS NULL THEN ATTRIBUTE.MAX_LENGTH
ELSE ATOMIC.ATOMIC_SIZE
END AS ATOMIC_SIZE,
'MINIMUM' as ATTRIBUTE_VALUE_TYPE,
ATOMIC.IS_STRING AS IS_STRING,
ENDPOINT_TYPE_ATTRIBUTE.SINGLETON
FROM ATTRIBUTE
INNER JOIN ENDPOINT_TYPE_ATTRIBUTE
ON ATTRIBUTE.ATTRIBUTE_ID = ENDPOINT_TYPE_ATTRIBUTE.ATTRIBUTE_REF
INNER JOIN ENDPOINT_TYPE_CLUSTER
ON ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF = ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID
INNER JOIN CLUSTER
ON ENDPOINT_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID
INNER JOIN ATOMIC
ON ATOMIC.NAME = ATTRIBUTE.TYPE
WHERE ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF in (${endpointClusterIds})
AND ENDPOINT_TYPE_CLUSTER.SIDE = ATTRIBUTE.SIDE AND ENDPOINT_TYPE_CLUSTER.ENABLED=1
AND (CASE
WHEN ATOMIC.IS_STRING=1 THEN
CASE WHEN ATOMIC.IS_LONG=0 THEN ATTRIBUTE.MAX_LENGTH+1
WHEN ATOMIC.IS_LONG=1 THEN ATTRIBUTE.MAX_LENGTH+2
ELSE ATOMIC.ATOMIC_SIZE
END
WHEN ATOMIC.ATOMIC_SIZE IS NULL THEN ATTRIBUTE.MAX_LENGTH
ELSE ATOMIC.ATOMIC_SIZE
END) > 2 AND ENDPOINT_TYPE_ATTRIBUTE.INCLUDED = 1 AND ATT_VALUE IS NOT NULL AND ATT_VALUE != "" AND ENDPOINT_TYPE_ATTRIBUTE.BOUNDED !=0 AND REPLACE(ATT_VALUE, '0', '')!='x' AND REPLACE(ATT_VALUE, '0', '')!=''
AND ATTRIBUTE.PACKAGE_REF IN (${dbApi.toInClause(packageIds)})
GROUP BY CLUSTER.MANUFACTURER_CODE, CLUSTER.CODE, ATTRIBUTE.CODE, ATTRIBUTE.MANUFACTURER_CODE, ATTRIBUTE.SIDE
UNION
SELECT
ATTRIBUTE.ATTRIBUTE_ID AS ATTRIBUTE_ID,
ATTRIBUTE.NAME AS NAME,
ATTRIBUTE.SIDE AS SIDE,
CLUSTER.NAME AS CLUSTER_NAME,
CLUSTER.MANUFACTURER_CODE AS CLUSTER_MANUFACTURER_CODE,
ATTRIBUTE.MAX AS ATT_VALUE,
CASE
WHEN ATOMIC.IS_STRING=1 THEN
CASE WHEN ATOMIC.IS_LONG=0 THEN ATTRIBUTE.MAX_LENGTH+1
WHEN ATOMIC.IS_LONG=1 THEN ATTRIBUTE.MAX_LENGTH+2
ELSE ATOMIC.ATOMIC_SIZE
END
WHEN ATOMIC.ATOMIC_SIZE IS NULL THEN ATTRIBUTE.MAX_LENGTH
ELSE ATOMIC.ATOMIC_SIZE
END AS ATOMIC_SIZE,
'MAXIMUM' as ATTRIBUTE_VALUE_TYPE,
ATOMIC.IS_STRING AS IS_STRING,
ENDPOINT_TYPE_ATTRIBUTE.SINGLETON
FROM ATTRIBUTE
INNER JOIN ENDPOINT_TYPE_ATTRIBUTE
ON ATTRIBUTE.ATTRIBUTE_ID = ENDPOINT_TYPE_ATTRIBUTE.ATTRIBUTE_REF
INNER JOIN ENDPOINT_TYPE_CLUSTER
ON ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF = ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID
INNER JOIN CLUSTER
ON ENDPOINT_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID
INNER JOIN ATOMIC
ON ATOMIC.NAME = ATTRIBUTE.TYPE
WHERE ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF in (${endpointClusterIds})
AND ENDPOINT_TYPE_CLUSTER.SIDE = ATTRIBUTE.SIDE AND ENDPOINT_TYPE_CLUSTER.ENABLED=1
AND (CASE
WHEN ATOMIC.IS_STRING=1 THEN
CASE WHEN ATOMIC.IS_LONG=0 THEN ATTRIBUTE.MAX_LENGTH+1
WHEN ATOMIC.IS_LONG=1 THEN ATTRIBUTE.MAX_LENGTH+2
ELSE ATOMIC.ATOMIC_SIZE
END
WHEN ATOMIC.ATOMIC_SIZE IS NULL THEN ATTRIBUTE.MAX_LENGTH
ELSE ATOMIC.ATOMIC_SIZE
END) > 2 AND ENDPOINT_TYPE_ATTRIBUTE.INCLUDED = 1 AND ATT_VALUE IS NOT NULL AND ATT_VALUE != "" AND ENDPOINT_TYPE_ATTRIBUTE.BOUNDED !=0 AND REPLACE(ATT_VALUE, '0', '')!='x' AND REPLACE(ATT_VALUE, '0', '')!=''
AND ATTRIBUTE.PACKAGE_REF IN (${dbApi.toInClause(packageIds)})
GROUP BY CLUSTER.MANUFACTURER_CODE, CLUSTER.CODE, ATTRIBUTE.CODE, ATTRIBUTE.MANUFACTURER_CODE, ATTRIBUTE.SIDE )
`
)
.then((rows) => rows.map(mapFunction))
}
/**
* The reportable attribute details per endpoint per clusters.
* @param {*} db
* @param {*} endpointsAndClusters
* @param {*} packageIds
* @returns * The reportable attribute details per endpoint per clusters.
*/
async function selectReportableAttributeDetailsFromEnabledClustersAndEndpoints(
db,
endpointsAndClusters,
packageIds
) {
let endpointClusterIds = endpointsAndClusters
.map((ep) => ep.endpointClusterId)
.toString()
let mapFunction = (x) => {
return {
id: x.ATTRIBUTE_ID,
name: x.NAME,
code: x.CODE,
side: x.SIDE,
mfgCode: x.MANUFACTURER_CODE,
clusterName: x.CLUSTER_NAME,
clusterCode: x.CLUSTER_CODE,
attributeReportableMinValue: x.MIN_INTERVAL,
attributeReportableMaxValue: x.MAX_INTERVAL,
attributeReportableChange: x.REPORTABLE_CHANGE,
endpointIdentifier: x.ENDPOINT_IDENTIFIER
}
}
return dbApi
.dbAll(
db,
`
SELECT
ATTRIBUTE.ATTRIBUTE_ID,
ATTRIBUTE.NAME,
ATTRIBUTE.CODE,
ATTRIBUTE.SIDE,
ATTRIBUTE.MANUFACTURER_CODE,
CLUSTER.NAME AS CLUSTER_NAME,
CLUSTER.CODE AS CLUSTER_CODE,
ENDPOINT_TYPE_ATTRIBUTE.MIN_INTERVAL,
ENDPOINT_TYPE_ATTRIBUTE.MAX_INTERVAL,
ENDPOINT_TYPE_ATTRIBUTE.REPORTABLE_CHANGE,
ENDPOINT.ENDPOINT_IDENTIFIER
FROM ATTRIBUTE
INNER JOIN ENDPOINT_TYPE_ATTRIBUTE
ON ATTRIBUTE.ATTRIBUTE_ID = ENDPOINT_TYPE_ATTRIBUTE.ATTRIBUTE_REF
INNER JOIN ENDPOINT_TYPE_CLUSTER
ON ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF = ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID
INNER JOIN CLUSTER
ON ENDPOINT_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID
INNER JOIN ENDPOINT
ON ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_REF = ENDPOINT.ENDPOINT_TYPE_REF
INNER JOIN ATOMIC
ON ATOMIC.NAME = ATTRIBUTE.TYPE
WHERE ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF IN (${endpointClusterIds})
AND ENDPOINT_TYPE_ATTRIBUTE.INCLUDED = 1 AND ENDPOINT_TYPE_CLUSTER.ENABLED=1 AND ENDPOINT_TYPE_CLUSTER.SIDE=ATTRIBUTE.SIDE
AND ENDPOINT_TYPE_ATTRIBUTE.INCLUDED_REPORTABLE = 1
AND ATTRIBUTE.PACKAGE_REF IN (${dbApi.toInClause(packageIds)})
GROUP BY CASE WHEN SINGLETON=0 THEN ENDPOINT.ENDPOINT_IDENTIFIER END, CLUSTER.MANUFACTURER_CODE, CLUSTER.CODE, ATTRIBUTE.CODE, ATTRIBUTE.MANUFACTURER_CODE, ATTRIBUTE.SIDE
HAVING CASE WHEN SINGLETON=1 THEN ENDPOINT.ENDPOINT_IDENTIFIER = MIN(ENDPOINT.ENDPOINT_IDENTIFIER) ELSE SINGLETON=0 END
ORDER BY ENDPOINT.ENDPOINT_IDENTIFIER, CLUSTER.MANUFACTURER_CODE, CLUSTER.CODE, ATTRIBUTE.CODE, ATTRIBUTE.MANUFACTURER_CODE
`
)
.then((rows) => rows.map(mapFunction))
}
/**
* Get attribute data by attribute code.
* @param {*} db
* @param {*} packageIds
* @param {*} clusterCode
* @param {*} attributeCode
* @param {*} manufacturerCode
* @returns promise of attribute data
*/
async function selectAttributeByCode(
db,
packageIds,
clusterCode,
attributeCode,
manufacturerCode
) {
if (clusterCode == null) {
return selectGlobalAttributeByCode(
db,
packageIds,
attributeCode,
manufacturerCode
)
} else {
return selectNonGlobalAttributeByCode(
db,
packageIds,
clusterCode,
attributeCode,
manufacturerCode
)
}
}
/**
* Get attribute information by code for attributes which are not global.
* @param {*} db
* @param {*} packageIds
* @param {*} clusterCode
* @param {*} attributeCode
* @param {*} manufacturerCode
* @returns promise of attribute data
*/
async function selectNonGlobalAttributeByCode(
db,
packageIds,
clusterCode,
attributeCode,
manufacturerCode
) {
let manufacturerCondition
let arg = [attributeCode, clusterCode]
if (manufacturerCode == null || manufacturerCode == 0) {
manufacturerCondition = 'C.MANUFACTURER_CODE IS NULL'
} else {
manufacturerCondition =
'( C.MANUFACTURER_CODE IS NULL OR C.MANUFACTURER_CODE = ? )'
arg.push(manufacturerCode)
}
return dbApi
.dbGet(
db,
`
SELECT
A.ATTRIBUTE_ID,
A.CLUSTER_REF,
A.CODE,
A.MANUFACTURER_CODE,
A.NAME,
A.TYPE,
A.SIDE,
A.DEFINE,
A.MIN,
A.MAX,
A.REPORT_MIN_INTERVAL,
A.REPORT_MAX_INTERVAL,
A.REPORTABLE_CHANGE,
A.REPORTABLE_CHANGE_LENGTH,
A.IS_WRITABLE,
A.IS_READABLE,
A.DEFAULT_VALUE,
A.IS_OPTIONAL,
A.REPORTING_POLICY,
A.STORAGE_POLICY,
A.IS_NULLABLE,
A.IS_SCENE_REQUIRED,
A.ARRAY_TYPE,
A.MUST_USE_TIMED_WRITE,
A.API_MATURITY,
A.IS_CHANGE_OMITTED,
A.PERSISTENCE
FROM ATTRIBUTE AS A
INNER JOIN CLUSTER AS C
ON C.CLUSTER_ID = A.CLUSTER_REF
WHERE A.PACKAGE_REF IN (${dbApi.toInClause(packageIds)})
AND A.CODE = ?
AND C.CODE = ?
AND ${manufacturerCondition}`,
arg
)
.then(dbMapping.map.attribute)
}
/**
* Get global attributes by their attribute code.
* @param {*} db
* @param {*} packageIds
* @param {*} attributeCode
* @param {*} manufacturerCode
* @returns promise of global attribute data
*/
async function selectGlobalAttributeByCode(
db,
packageIds,
attributeCode,
manufacturerCode
) {
let manufacturerCondition
let arg = [attributeCode]
if (manufacturerCode == null || manufacturerCode == 0) {
manufacturerCondition = 'A.MANUFACTURER_CODE IS NULL'
} else {
manufacturerCondition =
'( A.MANUFACTURER_CODE IS NULL OR A.MANUFACTURER_CODE = ? )'
arg.push(manufacturerCode)
}
return dbApi
.dbGet(
db,
`
SELECT
A.ATTRIBUTE_ID,
A.CLUSTER_REF,
A.CODE,
A.MANUFACTURER_CODE,
A.NAME,
A.TYPE,
A.SIDE,
A.DEFINE,
A.MIN,
A.MAX,
A.REPORT_MIN_INTERVAL,
A.REPORT_MAX_INTERVAL,
A.REPORTABLE_CHANGE,
A.REPORTABLE_CHANGE_LENGTH,
A.IS_WRITABLE,
A.IS_READABLE,
A.DEFAULT_VALUE,
A.IS_OPTIONAL,
A.REPORTING_POLICY,
A.STORAGE_POLICY,
A.IS_NULLABLE,
A.IS_SCENE_REQUIRED,
A.ARRAY_TYPE,
A.MUST_USE_TIMED_WRITE,
A.API_MATURITY,
A.IS_CHANGE_OMITTED,
A.PERSISTENCE
FROM ATTRIBUTE AS A
WHERE A.PACKAGE_REF IN (${dbApi.toInClause(packageIds)})
AND A.CODE = ?
AND ${manufacturerCondition}`,
arg
)
.then(dbMapping.map.attribute)
}
/**
* Retrieves the global attribute data for a given attribute and cluster code.
*
* @param {*} db
* @param {*} clusterRef
* @param {*} attributeRef
*/
async function selectGlobalAttributeDefaults(db, clusterRef, attributeRef) {
return dbApi
.dbAll(
db,
`
SELECT
GAD.DEFAULT_VALUE,
GAB.BIT,
GAB.VALUE,
(SELECT NAME FROM TAG WHERE TAG_ID = GAB.TAG_REF) AS TAG
FROM
GLOBAL_ATTRIBUTE_DEFAULT AS GAD
LEFT JOIN
GLOBAL_ATTRIBUTE_BIT AS GAB
ON
GAD.GLOBAL_ATTRIBUTE_DEFAULT_ID = GAB.GLOBAL_ATTRIBUTE_DEFAULT_REF
WHERE
GAD.CLUSTER_REF = ?
AND GAD.ATTRIBUTE_REF = ?
ORDER BY
GAD.CLUSTER_REF, GAD.ATTRIBUTE_REF, GAB.BIT
`,
[clusterRef, attributeRef]
)
.then((rows) =>
rows.reduce((ac, row) => {
if (!('default_value' in ac)) {
ac.defaultValue = row.DEFAULT_VALUE
}
if (row.BIT != null) {
if (!('featureBits' in ac)) {
ac.featureBits = []
}
ac.featureBits.push({ bit: row.BIT, value: row.VALUE, tag: row.TAG })
}
return ac
}, {})
)
}
/**
*
* @param {*} db
* @param {*} packageIds
* @param {*} endpointTypeRef
* @param {*} options
* @returns Token attributes for a specific endpoint type based on the endpoint
* type reference. Can also filter the attributes based on whether the
* attribute is configured to be singleton or not.
*/
async function selectTokenAttributesForEndpoint(
db,
packageIds,
endpointTypeRef,
options
) {
let singletonQuery =
'isSingleton' in options.hash
? `AND ENDPOINT_TYPE_ATTRIBUTE.SINGLETON=${options.hash.isSingleton}`
: ``
let rows = await dbApi.dbAll(
db,
`
SELECT
ATTRIBUTE.NAME AS NAME,
ATTRIBUTE.CODE AS CODE,
ATTRIBUTE.SIDE AS SIDE,
ATTRIBUTE.DEFINE,
ATTRIBUTE.TYPE,
ATTRIBUTE.MANUFACTURER_CODE AS MANUFACTURER_CODE,
CLUSTER.MANUFACTURER_CODE AS CLUSTER_MANUFACTURER_CODE,
CLUSTER.NAME AS CLUSTER_NAME,
CLUSTER.DEFINE AS CLUSTER_DEFINE,
ENDPOINT_TYPE_ATTRIBUTE.SINGLETON,
ENDPOINT_TYPE_ATTRIBUTE.STORAGE_OPTION,
ATTRIBUTE.API_MATURITY
FROM
ATTRIBUTE
INNER JOIN
ENDPOINT_TYPE_ATTRIBUTE
ON
ENDPOINT_TYPE_ATTRIBUTE.ATTRIBUTE_REF = ATTRIBUTE.ATTRIBUTE_ID
INNER JOIN
ENDPOINT_TYPE_CLUSTER
ON
ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF = ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID
INNER JOIN
CLUSTER
ON
ATTRIBUTE.CLUSTER_REF = CLUSTER.CLUSTER_ID
WHERE
ENDPOINT_TYPE_CLUSTER.ENABLED = 1
AND
ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_REF = ?
AND
ENDPOINT_TYPE_ATTRIBUTE.INCLUDED = 1
AND
ENDPOINT_TYPE_ATTRIBUTE.STORAGE_OPTION = 'NVM'
AND
ATTRIBUTE.PACKAGE_REF IN (${dbApi.toInClause(packageIds)})
${singletonQuery}
`,
endpointTypeRef
)
return rows.map(dbMapping.map.endpointTypeAttributeExtended)
}
/**
* Gets all token attribute information.
* @param {*} db
* @param {*} sessionId
* @param {*} packageIds
* @param {*} options
* @returns All token attributes. Singleton token attributes are only returned
* once whereas non-singleton token attributes are returned per endpoint.
*/
async function selectAllUserTokenAttributes(
db,
sessionId,
packageIds,
options
) {
const tokenSqlQuery = `SELECT
ATTRIBUTE.NAME,
ATTRIBUTE.CODE,
ATTRIBUTE.MANUFACTURER_CODE,
ATTRIBUTE.DEFINE,
ATTRIBUTE.SIDE,
ATTRIBUTE.TYPE,
CLUSTER.NAME AS CLUSTER_NAME,
CLUSTER.DEFINE AS CLUSTER_DEFINE,
CLUSTER.CODE AS CLUSTER_CODE,
CLUSTER.MANUFACTURER_CODE AS CLUSTER_MANUFACTURER_CODE,
ENDPOINT_TYPE_ATTRIBUTE.SINGLETON,
ENDPOINT.ENDPOINT_IDENTIFIER,
ENDPOINT.ENDPOINT_TYPE_REF,
MIN
(ENDPOINT.ENDPOINT_IDENTIFIER)
OVER
(PARTITION BY
CLUSTER.CODE,
CLUSTER.MANUFACTURER_CODE,
ATTRIBUTE.CODE,
ATTRIBUTE.MANUFACTURER_CODE,
ATTRIBUTE.SIDE) AS SMALLEST_ENDPOINT_IDENTIFIER
FROM
ATTRIBUTE
INNER JOIN
ENDPOINT_TYPE_ATTRIBUTE
ON
ENDPOINT_TYPE_ATTRIBUTE.ATTRIBUTE_REF = ATTRIBUTE.ATTRIBUTE_ID
INNER JOIN
ENDPOINT_TYPE_CLUSTER
ON
ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF = ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID
INNER JOIN
ENDPOINT_TYPE
ON
ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_REF = ENDPOINT_TYPE.ENDPOINT_TYPE_ID
INNER JOIN
ENDPOINT
ON
ENDPOINT_TYPE.ENDPOINT_TYPE_ID = ENDPOINT.ENDPOINT_TYPE_REF
INNER JOIN
CLUSTER
ON
ENDPOINT_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID
INNER JOIN
SESSION_PARTITION
ON
ENDPOINT_TYPE.SESSION_PARTITION_REF = SESSION_PARTITION.SESSION_PARTITION_ID
WHERE
SESSION_PARTITION.SESSION_REF = ${sessionId}
AND
ENDPOINT_TYPE_CLUSTER.ENABLED=1
AND
ATTRIBUTE.PACKAGE_REF IN (${dbApi.toInClause(packageIds)})
AND
ENDPOINT_TYPE_ATTRIBUTE.STORAGE_OPTION='NVM'
AND
ENDPOINT_TYPE_ATTRIBUTE.INCLUDED=1`
// Selecting the rows in such a way that singletons token attributes exist
// only once and non-singleton token attributes exist per endpoint.
let rows = await dbApi.dbAll(
db,
`
SELECT
*,
ROW_NUMBER() OVER() + 45055 AS TOKEN_ID
FROM
(
SELECT * FROM (
${tokenSqlQuery} AND ENDPOINT_TYPE_ATTRIBUTE.SINGLETON = 0
UNION
${tokenSqlQuery} AND ENDPOINT_TYPE_ATTRIBUTE.SINGLETON = 1
GROUP BY
CLUSTER.CODE,
CLUSTER.MANUFACTURER_CODE,
ATTRIBUTE.CODE,
ATTRIBUTE.MANUFACTURER_CODE,
ATTRIBUTE.SIDE
)
ORDER BY
SINGLETON DESC,
CLUSTER_MANUFACTURER_CODE,
MANUFACTURER_CODE,
CASE
WHEN
SINGLETON = 1
THEN
SMALLEST_ENDPOINT_IDENTIFIER
ELSE
ENDPOINT_IDENTIFIER
END,
CLUSTER_CODE,
CODE
)
ORDER BY
TOKEN_ID
`
)
return rows.map(dbMapping.map.endpointTypeAttributeExtended)
}
/**
* Get all attributes which are related to each other and belong to certain set of packageIds
* @param {*} db
* @param {*} packageIds
* @returns all attributes which are related to each other and belong to certain set of packageIds
*/
async function selectAttributeMappingsByPackageIds(db, packageIds) {
let rows = await dbApi.dbAll(
db,
`
SELECT
ATTRIBUTE_MAPPING.ATTRIBUTE_MAPPING_ID,
ATTRIBUTE_MAPPING.ATTRIBUTE_LEFT_REF,
ATTRIBUTE_MAPPING.ATTRIBUTE_RIGHT_REF,
A1.CODE AS A1_CODE,
COALESCE(A1.MANUFACTURER_CODE, 0) AS A1_MANUFACTURER_CODE,
A2.CODE AS A2_CODE,
COALESCE(A2.MANUFACTURER_CODE, 0) AS A2_MANUFACTURER_CODE,
A1.NAME AS A1_NAME,
A2.NAME AS A2_NAME,
C1.CODE AS C1_CODE,
COALESCE(C1.MANUFACTURER_CODE, 0) AS C1_MANUFACTURER_CODE,
C1.NAME AS C1_NAME,
C2.CODE AS C2_CODE,
COALESCE(C2.MANUFACTURER_CODE, 0) AS C2_MANUFACTURER_CODE,
C2.NAME AS C2_NAME,
ROW_NUMBER() OVER (
PARTITION BY C1.CODE, COALESCE(C1.MANUFACTURER_CODE, 0), C2.CODE, COALESCE(C2.MANUFACTURER_CODE, 0)
ORDER BY C1.CODE, COALESCE(C1.MANUFACTURER_CODE, 0), C2.CODE, COALESCE(C2.MANUFACTURER_CODE, 0)
) AS CLUSTER_MAPPING_INDEX,
COUNT(*) OVER (
PARTITION BY C1.CODE, COALESCE(C1.MANUFACTURER_CODE, 0), C2.CODE, COALESCE(C2.MANUFACTURER_CODE, 0)
) AS TOTAL_CLUSTER_MAPPED_ATTRIBUTES,
CASE
WHEN
(
RANK() OVER (
ORDER BY C1.CODE, COALESCE(C1.MANUFACTURER_CODE, 0), C2.CODE, COALESCE(C2.MANUFACTURER_CODE, 0)
)
+
COUNT(*) OVER (
PARTITION BY C1.CODE, COALESCE(C1.MANUFACTURER_CODE, 0), C2.CODE, COALESCE(C2.MANUFACTURER_CODE, 0)
)
) > COUNT(*) OVER ()
THEN 1
ELSE 0
END AS IS_LAST_CLUSTER_PARTITION
FROM
ATTRIBUTE_MAPPING
INNER JOIN
ATTRIBUTE A1
ON
ATTRIBUTE_MAPPING.ATTRIBUTE_LEFT_REF = A1.ATTRIBUTE_ID
INNER JOIN
ATTRIBUTE A2
ON
ATTRIBUTE_MAPPING.ATTRIBUTE_RIGHT_REF = A2.ATTRIBUTE_ID
INNER JOIN
CLUSTER C1
ON
C1.CLUSTER_ID = A1.CLUSTER_REF
INNER JOIN
CLUSTER C2
ON
C2.CLUSTER_ID = A2.CLUSTER_REF
WHERE
A1.PACKAGE_REF IN (${dbApi.toInClause(packageIds)})
OR
A2.PACKAGE_REF IN (${dbApi.toInClause(packageIds)})
ORDER BY C1_CODE, C1_MANUFACTURER_CODE, C2_CODE, C2_MANUFACTURER_CODE, A1_CODE, A1_MANUFACTURER_CODE, A2_CODE, A2_MANUFACTURER_CODE
`
)
return rows.map(dbMapping.map.attributeMapping)
}
/**
* Get all attributes in an endpoint type cluster
* @param {*} db
* @param {*} endpointTyeClusterId
* @returns all attributes in an endpoint type cluster
*/
async function selectAttributesByEndpointTypeClusterId(
db,
endpointTypeClusterId
) {
let rows = await dbApi.dbAll(
db,
`
SELECT
ATTRIBUTE.ATTRIBUTE_ID,
ATTRIBUTE.NAME,
ATTRIBUTE.CLUSTER_REF,
ATTRIBUTE.SIDE,
ATTRIBUTE.CONFORMANCE,
ATTRIBUTE.REPORT_MIN_INTERVAL,
ATTRIBUTE.REPORT_MAX_INTERVAL,
ATTRIBUTE.REPORTABLE_CHANGE,
ENDPOINT_TYPE_ATTRIBUTE.INCLUDED
FROM
ATTRIBUTE
JOIN
ENDPOINT_TYPE_CLUSTER
ON
ATTRIBUTE.CLUSTER_REF = ENDPOINT_TYPE_CLUSTER.CLUSTER_REF
AND
ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID = ?
LEFT JOIN
ENDPOINT_TYPE_ATTRIBUTE
ON
ATTRIBUTE.ATTRIBUTE_ID = ENDPOINT_TYPE_ATTRIBUTE.ATTRIBUTE_REF
AND
ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF = ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID
`,
[endpointTypeClusterId]
)
return rows.map(dbMapping.map.endpointTypeAttributeExtended)
}
exports.selectAllAttributeDetailsFromEnabledClusters = dbCache.cacheQuery(
selectAllAttributeDetailsFromEnabledClusters
)
exports.selectManufacturerSpecificAttributeDetailsFromAllEndpointTypesAndClusters =
selectManufacturerSpecificAttributeDetailsFromAllEndpointTypesAndClusters
exports.selectNonManufacturerSpecificAttributeDetailsFromAllEndpointTypesAndClusters =
selectNonManufacturerSpecificAttributeDetailsFromAllEndpointTypesAndClusters
exports.selectAttributeDetailsWithABoundFromEnabledClusters =
dbCache.cacheQuery(selectAttributeDetailsWithABoundFromEnabledClusters)
exports.selectAttributeDetailsFromEnabledClusters = dbCache.cacheQuery(
selectAttributeDetailsFromEnabledClusters
)
exports.selectAttributeBoundDetails = dbCache.cacheQuery(
selectAttributeBoundDetails
)
exports.selectReportableAttributeDetailsFromEnabledClustersAndEndpoints =
selectReportableAttributeDetailsFromEnabledClustersAndEndpoints
exports.selectGlobalAttributeDefaults = selectGlobalAttributeDefaults
exports.selectAttributeByCode = selectAttributeByCode
exports.duplicateEndpointTypeAttribute = duplicateEndpointTypeAttribute
exports.selectEndpointTypeAttributesByEndpointTypeRefAndClusterRef =
selectEndpointTypeAttributesByEndpointTypeRefAndClusterRef
exports.selectTokenAttributesForEndpoint = selectTokenAttributesForEndpoint
exports.selectAllUserTokenAttributes = selectAllUserTokenAttributes
exports.selectAttributeMappingsByPackageIds =
selectAttributeMappingsByPackageIds
exports.selectAttributesByEndpointTypeClusterId =
selectAttributesByEndpointTypeClusterId