Skip to content

Commit 5458d9a

Browse files
authored
Clean up helper when structs with same name exist as a global struct and a cluster specific one (#1562)
* Clean up helper when structs with same name exist as a global struct and a cluster specific one - Add selectStructByNameAndClusterName because selectStructByNameAndClusterId could not be used for some of our existing helpers such as asObjectiveCClass. - Update query-util.js to form the correct data type retrieval using data type name and cluster name: sqlQueryForDataTypeByNameAndClusterName - Update asObjectiveCClass with selectStructByNameAndClusterName instead of selectStructByName - Adding unit test for the above - Github: ZAP#1559
1 parent 1a2f946 commit 5458d9a

File tree

6 files changed

+384
-4
lines changed

6 files changed

+384
-4
lines changed

docs/api.md

Lines changed: 238 additions & 0 deletions
Large diffs are not rendered by default.

src-electron/db/query-struct.js

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const dbApi = require('./db-api')
2525
const dbCache = require('./db-cache')
2626
const dbMapping = require('./db-mapping')
2727
const queryUtil = require('./query-util')
28+
const dbEnum = require('../../src-shared/db-enum.js')
2829

2930
/**
3031
* Get all structs from a given package ID.
@@ -132,12 +133,12 @@ ORDER BY
132133
*/
133134
async function selectStructByNameAndClusterId(db, name, clusterId, packageIds) {
134135
let queryWithoutClusterId = queryUtil.sqlQueryForDataTypeByNameAndClusterId(
135-
'struct',
136+
dbEnum.zclType.struct,
136137
null,
137138
packageIds
138139
)
139140
let queryWithClusterId = queryUtil.sqlQueryForDataTypeByNameAndClusterId(
140-
'struct',
141+
dbEnum.zclType.struct,
141142
clusterId,
142143
packageIds
143144
)
@@ -154,6 +155,48 @@ async function selectStructByNameAndClusterId(db, name, clusterId, packageIds) {
154155
}
155156
}
156157

158+
/**
159+
* Select a struct matched by name and cluster name
160+
* Note: Use selectStructByNameAndClusterName but this was needed for backwards compatibility.
161+
* @param {*} db
162+
* @param {*} name
163+
* @param {*} clusterName
164+
* @param {*} packageIds
165+
* @returns struct information or undefined
166+
*/
167+
async function selectStructByNameAndClusterName(
168+
db,
169+
name,
170+
clusterName,
171+
packageIds
172+
) {
173+
let queryWithClusterName = queryUtil.sqlQueryForDataTypeByNameAndClusterName(
174+
dbEnum.zclType.struct,
175+
name,
176+
clusterName,
177+
packageIds
178+
)
179+
let res = await dbApi
180+
.dbAll(db, queryWithClusterName)
181+
.then((rows) => rows.map(dbMapping.map.struct))
182+
if (res && res.length == 1) {
183+
return res[0]
184+
} else if (res && res.length > 1) {
185+
throw new Error(
186+
`More than one struct ${name} exists with same name for ${clusterName} cluster.`
187+
)
188+
} else {
189+
queryWithClusterName = queryUtil.sqlQueryForDataTypeByNameAndClusterName(
190+
dbEnum.zclType.struct,
191+
name,
192+
null, // Retrieving global data types since cluster specific ones were not found.
193+
packageIds
194+
)
195+
res = await dbApi.dbGet(db, queryWithClusterName).then(dbMapping.map.struct)
196+
return res
197+
}
198+
}
199+
157200
/**
158201
* Get all structs which have a cluster associated with them. If a struct is
159202
* present in more than one cluster then it can be grouped by struct name to
@@ -208,5 +251,6 @@ exports.selectStructByName = dbCache.cacheQuery(selectStructByName)
208251
exports.selectStructByNameAndClusterId = dbCache.cacheQuery(
209252
selectStructByNameAndClusterId
210253
)
254+
exports.selectStructByNameAndClusterName = selectStructByNameAndClusterName
211255
exports.selectStructsWithClusterAssociation =
212256
selectStructsWithClusterAssociation

src-electron/db/query-util.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,5 +83,70 @@ function sqlQueryForDataTypeByNameAndClusterId(
8383
return clusterId ? queryWithClusterId : queryWithoutClusterId
8484
}
8585

86+
/**
87+
* Formulate a sqlite query string for a data type from the given cluster name and package IDs.
88+
* @param {*} typeDiscriminator
89+
* @param {*} name data type name
90+
* @param {*} clusterName
91+
* @param {*} packageIds
92+
* @param {*} options
93+
* @returns SQLite query string
94+
*/
95+
function sqlQueryForDataTypeByNameAndClusterName(
96+
typeDiscriminator,
97+
name,
98+
clusterName,
99+
packageIds,
100+
options = {}
101+
) {
102+
let typeTableName = typeDiscriminator.toUpperCase()
103+
let numberExtensionString =
104+
typeDiscriminator == 'number' ? 'NUMBER.IS_SIGNED, ' : ''
105+
let checkLowerCaseString =
106+
typeDiscriminator != 'number' && typeDiscriminator != 'struct'
107+
? `OR DATA_TYPE.NAME = '${name}'`
108+
: ''
109+
let structExtensionString =
110+
typeDiscriminator == 'struct'
111+
? 'STRUCT.IS_FABRIC_SCOPED, DATA_TYPE.DISCRIMINATOR_REF, '
112+
: ''
113+
let selectQueryString = `
114+
SELECT
115+
${typeTableName}.${typeTableName}_ID,
116+
${structExtensionString}
117+
DATA_TYPE.NAME AS NAME,
118+
${numberExtensionString}
119+
${typeTableName}.SIZE AS SIZE,
120+
CLUSTER.NAME AS CLUSTER_NAME
121+
FROM ${typeTableName}
122+
INNER JOIN
123+
DATA_TYPE
124+
ON
125+
${typeTableName}.${typeTableName}_ID = DATA_TYPE.DATA_TYPE_ID
126+
LEFT JOIN
127+
DATA_TYPE_CLUSTER
128+
ON
129+
DATA_TYPE_CLUSTER.DATA_TYPE_REF = ${typeTableName}.${typeTableName}_ID
130+
LEFT JOIN
131+
CLUSTER
132+
ON
133+
DATA_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID
134+
WHERE
135+
(DATA_TYPE.NAME = '${name}' ${checkLowerCaseString})
136+
AND
137+
DATA_TYPE.PACKAGE_REF IN (${dbApi.toInClause(packageIds)}) `
138+
139+
let whereClause = !options.ignoreClusterWhereClause
140+
? clusterName
141+
? `AND CLUSTER.NAME = '${clusterName}'`
142+
: `AND CLUSTER.NAME IS NULL`
143+
: ``
144+
145+
let resultingQuery = selectQueryString + whereClause
146+
return resultingQuery
147+
}
148+
86149
exports.sqlQueryForDataTypeByNameAndClusterId =
87150
sqlQueryForDataTypeByNameAndClusterId
151+
exports.sqlQueryForDataTypeByNameAndClusterName =
152+
sqlQueryForDataTypeByNameAndClusterName

src-electron/db/query-zcl.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,6 +1332,8 @@ exports.selectStructById = queryStruct.selectStructById
13321332
exports.selectStructByName = queryStruct.selectStructByName
13331333
exports.selectStructByNameAndClusterId =
13341334
queryStruct.selectStructByNameAndClusterId
1335+
exports.selectStructByNameAndClusterName =
1336+
queryStruct.selectStructByNameAndClusterName
13351337

13361338
exports.selectBitmapById = queryBitmap.selectBitmapById
13371339
exports.selectAllBitmaps = queryBitmap.selectAllBitmaps

src-electron/generator/matter/darwin/Framework/CHIP/templates/helper.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,12 +240,27 @@ async function asObjectiveCClass(type, cluster, options) {
240240
}
241241

242242
if (isStruct) {
243-
const structObj = await zclQuery.selectStructByName(
243+
let structObj = await zclQuery.selectStructByNameAndClusterName(
244244
this.global.db,
245245
type,
246+
cluster,
246247
pkgIds
247248
);
248-
if (structObj.structClusterCount == 0) {
249+
250+
let isGlobalStruct;
251+
if (!structObj) {
252+
// Can end up here when our "cluster name" is a backwards compat name.
253+
// Just fetch by struct name only in that case.
254+
structObj = await zclQuery.selectStructByName(
255+
this.global.db,
256+
type,
257+
pkgIds
258+
);
259+
isGlobalStruct = structObj.structClusterCount == 0;
260+
} else {
261+
isGlobalStruct = !structObj.clusterName;
262+
}
263+
if (isGlobalStruct) {
249264
// This is a global struct.
250265
return `${
251266
options.hash.structTypePrefix || 'MTR'

test/gen-matter-3-1.test.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const testUtil = require('./test-util')
2929
const queryEndpoint = require('../src-electron/db/query-endpoint')
3030
const queryEndpointType = require('../src-electron/db/query-endpoint-type')
3131
const queryConfig = require('../src-electron/db/query-config')
32+
const queryZcl = require('../src-electron/db/query-zcl')
3233
const queryDeviceType = require('../src-electron/db/query-device-type')
3334
const util = require('../src-electron/util/util')
3435
const testQuery = require('./test-query')
@@ -521,6 +522,21 @@ test(
521522
'SemanticTagStruct item 3 from Identify cluster: Label'
522523
)
523524
expect(ept).not.toContain('SemanticTagStruct item 4 from Identify cluster')
525+
526+
// Testing selectStructByNameAndClusterName for struct names
527+
let globalStruct = await queryZcl.selectStructByNameAndClusterName(
528+
db,
529+
'SemanticTagStruct',
530+
'Descriptor',
531+
zclPackageId
532+
)
533+
let clusterStruct = await await queryZcl.selectStructByNameAndClusterName(
534+
db,
535+
'SemanticTagStruct',
536+
'Mode Select',
537+
zclPackageId
538+
)
539+
expect(globalStruct.id).not.toEqual(clusterStruct.id)
524540
},
525541
testUtil.timeout.long()
526542
)

0 commit comments

Comments
 (0)