in source/packages/services/device-patcher/src/patch/patch.dao.ts [115:347]
pk: createDelimitedAttribute(PkType.PatchTask, patch.taskId),
sk: createDelimitedAttribute(PkType.DevicePatch, patch.patchId),
si1Sort: createDelimitedAttribute(PkType.PatchTask, patch.taskId),
si2Hash: createDelimitedAttribute(PkType.Device, patch.deviceId),
},
},
};
requestItems.push(patchTaskRecord);
}
// batch write the items to ddb
// build the request and write to DynamoDB
const params: AWS.DynamoDB.DocumentClient.BatchWriteItemInput = {
RequestItems: {},
};
params.RequestItems[this.tableName] = requestItems;
const result = await this.dynamoDbUtils.batchWriteAll(params);
if (this.dynamoDbUtils.hasUnprocessedItems(result)) {
throw new Error('SAVE_FAILED');
}
}
public async getBulk(
patchItems: { patchId: string; deviceId: string }[]
): Promise<PatchItem[]> {
logger.debug(`patch.dao: list: in: patchItems: ${patchItems}`);
const params = {
RequestItems: {},
};
params.RequestItems[this.tableName] = { Keys: [] };
for (const item of patchItems) {
params.RequestItems[this.tableName].Keys.push({
pk: createDelimitedAttribute(PkType.DevicePatch, item.patchId),
sk: createDelimitedAttribute(PkType.Device, item.deviceId),
});
params.RequestItems[this.tableName].Keys.push({
pk: createDelimitedAttribute(PkType.DevicePatch, item.patchId),
sk: createDelimitedAttribute(
PkType.DevicePatch,
PkType.DevicePatchAssociation,
'map'
),
});
}
const result = await this.dynamoDbUtils.batchGetAll(params);
if (
result.Responses[this.tableName] === undefined ||
result.Responses[this.tableName].length === 0
) {
logger.debug('patches.dao list: exit: undefined');
return undefined;
}
const patches = this.assemblePatch(result.Responses[this.tableName]);
logger.debug(`patch.dao: list: exit: patchList: ${JSON.stringify(patches)}`);
return patches;
}
public async get(patchId: string): Promise<PatchItem> {
logger.debug(`patch.dao: list: in: patchId: ${patchId}`);
const params = {
TableName: this.tableName,
KeyConditionExpression: `#pk=:pk`,
ExpressionAttributeNames: {
'#pk': 'pk',
},
ExpressionAttributeValues: {
':pk': createDelimitedAttribute(PkType.DevicePatch, patchId),
},
};
const result = await this.dc.query(params).promise();
if (result.Items === undefined || result.Items.length === 0) {
logger.debug('patches.dao list: exit: undefined');
return undefined;
}
const patches = this.assemblePatch(result.Items);
logger.debug(`patch.dao: list: exit: patchList: ${JSON.stringify(patches)}`);
return patches[0];
}
public async list(
deviceId: string,
status?: string,
count?: number,
exclusiveStart?: PatchListPaginationKey
): Promise<[PatchItem[], PatchListPaginationKey]> {
logger.debug(`patch.dao: list: in: patch: ${JSON.stringify(deviceId)}`);
let exclusiveStartKey: DynamoDbPaginationKey;
if (exclusiveStart?.nextToken) {
const decoded = atob(`${exclusiveStart?.nextToken}`);
exclusiveStartKey = JSON.parse(decoded);
}
const params = {
TableName: this.tableName,
IndexName: this.SI1_INDEX,
KeyConditionExpression: `#pk=:pk AND begins_with(#sk,:sk)`,
ExpressionAttributeNames: {
'#pk': 'sk',
'#sk': 'si1Sort',
},
ExpressionAttributeValues: {
':pk': createDelimitedAttribute(PkType.Device, deviceId),
':sk': createDelimitedAttribute(PkType.DevicePatch),
},
ExclusiveStartKey: exclusiveStartKey,
Limit: count,
};
if (status) {
params.ExpressionAttributeValues[':sk'] = createDelimitedAttribute(
PkType.Device,
status
);
}
const results = await this.dc.query(params).promise();
if ((results?.Items?.length ?? 0) === 0) {
logger.debug(`patchTask.dao:getPatchs exit: undefined`);
return [undefined, undefined];
}
const patchItemKeys = results.Items.map((item) => {
return {
patchId: expandDelimitedAttribute(item.pk)[1],
deviceId: expandDelimitedAttribute(item.sk)[1],
};
});
const patches = await this.getBulk(patchItemKeys);
let paginationKey: PatchListPaginationKey;
if (results.LastEvaluatedKey) {
const nextToken = btoa(`${JSON.stringify(results.LastEvaluatedKey)}`);
paginationKey = {
nextToken,
};
}
logger.debug(`patch.dao: list: exit: patchList: ${JSON.stringify(patches)}`);
return [patches, paginationKey];
}
public async update(patch: PatchItem): Promise<void> {
logger.debug(`patch.dao: update: in: patch: ${JSON.stringify(patch)}`);
let date = new Date().toISOString();
if (patch.updatedAt && patch.updatedAt instanceof Date) {
logger.silly(
`patch.dao: update: using updated at from payload, updatedAt: ${patch.updatedAt}`
);
date = patch.updatedAt.toISOString();
}
const params = {
TableName: this.tableName,
Key: {
pk: createDelimitedAttribute(PkType.DevicePatch, patch.patchId),
sk: createDelimitedAttribute(PkType.Device, patch.deviceId),
},
UpdateExpression:
'set patchStatus = :s, statusMessage = :m, updatedAt = :u, patchTemplateName = :t, si1Sort = :si1Sort',
ExpressionAttributeValues: {
':s': patch.patchStatus,
':m': patch.statusMessage || null,
':u': date,
':t': patch.patchTemplateName,
':si1Sort': createDelimitedAttribute(
PkType.DevicePatch,
patch.patchStatus,
patch.patchId
),
},
};
const result = await this.dc.update(params).promise();
logger.debug(`patch.dao: save: exit: result: ${JSON.stringify(result)}`);
}
public async delete(patchId: string): Promise<void> {
logger.debug(`patch.dao: delete: in: patch: ${JSON.stringify(patchId)}`);
// retrieve all records associated with the template
const queryParams: AWS.DynamoDB.DocumentClient.QueryInput = {
TableName: this.tableName,
KeyConditionExpression: `#hash = :hash`,
ExpressionAttributeNames: { '#hash': 'pk' },
ExpressionAttributeValues: {
':hash': createDelimitedAttribute(PkType.DevicePatch, patchId),
},
};
let queryResults;
try {
queryResults = await this.dc.query(queryParams).promise();
} catch (err) {
logger.error(
`patch.dao: delete: query: params: ${JSON.stringify(
queryParams
)}, error: ${JSON.stringify(err)}`
);
throw err;
}
if (queryResults?.Items === undefined || queryResults?.Items.length === 0) {
logger.debug('patches.dao delete: exit: nothing to delete');
return;
}
// batch delete
const batchParams: AWS.DynamoDB.DocumentClient.BatchWriteItemInput = { RequestItems: {} };
batchParams.RequestItems[this.tableName] = [];
queryResults.Items.forEach((i) => {
const req: AWS.DynamoDB.DocumentClient.WriteRequest = {
DeleteRequest: {
Key: {