@kwiz/node 1.0.15 → 1.0.17

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/src/axios.ts CHANGED
@@ -1,45 +1,45 @@
1
- import { isNullOrEmptyString } from "@kwiz/common";
2
- import { AxiosError, AxiosRequestConfig } from "axios";
3
- import { Agent, globalAgent } from "https";
4
-
5
- type axiosConfigOptions = {
6
- contantType?: "application/json" | "application/json; odata=nometadata" | "application/xml";
7
- }
8
- export function getAxiosConfigBearer(token: string, options?: axiosConfigOptions) {
9
- return getAxiosConfig(`Bearer ${token}`, options);
10
- }
11
-
12
- export function getAxiosConfig(token?: string, options?: axiosConfigOptions) {
13
- //allow self sign ssl certificates
14
- globalAgent.options.rejectUnauthorized = false;
15
- const config: AxiosRequestConfig<any> = {
16
- httpAgent: new Agent({
17
- rejectUnauthorized: false
18
- }),
19
- headers: {}
20
- };
21
-
22
- if (!isNullOrEmptyString(token))
23
- config.headers!.Authorization = token;
24
-
25
- if (options) {
26
- if (!isNullOrEmptyString(options.contantType)) {
27
- config.headers!["Content-Type"] = options.contantType;
28
- config.headers!["Accept"] = options.contantType;
29
- }
30
- }
31
- return config;
32
- }
33
-
34
- export function getAxiosErrorData(error: AxiosError) {
35
- let code = error.code || "Unknown";
36
- let errorMessage = error.message || "Unspecified error";
37
- if (error && error.response && error.response.data && error.response.data["odata.error"]) {
38
- let errorData: { code: string; message: { value: string; }; } = error.response.data["odata.error"];
39
- if (errorData.message && errorData.message.value)
40
- errorMessage = errorData.message.value;
41
- if (errorData && errorData.code)
42
- code = errorData.code;
43
- }
44
- return { code: code, message: errorMessage };
1
+ import { isNullOrEmptyString } from "@kwiz/common";
2
+ import { AxiosError, AxiosRequestConfig } from "axios";
3
+ import { Agent, globalAgent } from "https";
4
+
5
+ type axiosConfigOptions = {
6
+ contantType?: "application/json" | "application/json; odata=nometadata" | "application/xml";
7
+ }
8
+ export function getAxiosConfigBearer(token: string, options?: axiosConfigOptions) {
9
+ return getAxiosConfig(`Bearer ${token}`, options);
10
+ }
11
+
12
+ export function getAxiosConfig(token?: string, options?: axiosConfigOptions) {
13
+ //allow self sign ssl certificates
14
+ globalAgent.options.rejectUnauthorized = false;
15
+ const config: AxiosRequestConfig<any> = {
16
+ httpAgent: new Agent({
17
+ rejectUnauthorized: false
18
+ }),
19
+ headers: {}
20
+ };
21
+
22
+ if (!isNullOrEmptyString(token))
23
+ config.headers!.Authorization = token;
24
+
25
+ if (options) {
26
+ if (!isNullOrEmptyString(options.contantType)) {
27
+ config.headers!["Content-Type"] = options.contantType;
28
+ config.headers!["Accept"] = options.contantType;
29
+ }
30
+ }
31
+ return config;
32
+ }
33
+
34
+ export function getAxiosErrorData(error: AxiosError) {
35
+ let code = error.code || "Unknown";
36
+ let errorMessage = error.message || "Unspecified error";
37
+ if (error && error.response && error.response.data && error.response.data["odata.error"]) {
38
+ let errorData: { code: string; message: { value: string; }; } = error.response.data["odata.error"];
39
+ if (errorData.message && errorData.message.value)
40
+ errorMessage = errorData.message.value;
41
+ if (errorData && errorData.code)
42
+ code = errorData.code;
43
+ }
44
+ return { code: code, message: errorMessage };
45
45
  }
@@ -3,3 +3,4 @@ export * from './auth/exports-index';
3
3
  export * from './graph/exports-index';
4
4
  export * from './storage/exports-index';
5
5
  export * from './axios';
6
+ export * from './get-with-cache';
@@ -0,0 +1,38 @@
1
+ import { IDictionary, isNullOrUndefined } from "@kwiz/common";
2
+
3
+ const $$cache: IDictionary<{ expires: Date; value: any }> = {};
4
+
5
+ export async function getWithCache<T>(worker: () => Promise<{ success: boolean; value: T }>, info: {
6
+ /** seconds */
7
+ successCacheDuration: number;
8
+ /** seconds */
9
+ failedCacheDuration?: number;
10
+ /** must be unique for your call! function name, and parameters */
11
+ cacheKey: string;
12
+ forceRefresh?: boolean;
13
+ }) {
14
+ const now = new Date();
15
+ //purge old values
16
+ Object.keys($$cache).forEach(key => {
17
+ if ($$cache[key].expires < now) delete $$cache[key];
18
+ });
19
+
20
+ let cached = info.forceRefresh ? null : $$cache[info.cacheKey];
21
+
22
+ if (isNullOrUndefined(cached)) {
23
+ const result = await worker();
24
+ if (result.success) {
25
+ $$cache[info.cacheKey] = {
26
+ expires: new Date(new Date().getTime() + info.successCacheDuration * 1000),
27
+ value: result.value
28
+ };
29
+ }
30
+ else if (info.failedCacheDuration > 0) {
31
+ $$cache[info.cacheKey] = {
32
+ expires: new Date(new Date().getTime() + info.failedCacheDuration * 1000),
33
+ value: result.value
34
+ };
35
+ }
36
+ }
37
+ return $$cache[info.cacheKey].value;
38
+ }
@@ -1,18 +1,18 @@
1
- import { AuthContextType, ITenantInfo, isNullOrUndefined } from "@kwiz/common";
2
- import { GetMSALToken } from "../auth/msal";
3
- import { getAxiosConfigBearer } from "../axios";
4
-
5
- /** "https://graph.microsoft.com" */
6
- export const graphScope = "https://graph.microsoft.com";
7
-
8
- var auth: AuthContextType = null;
9
- export function ConfigureGraphAuth(config?: AuthContextType) {
10
- auth = config;
11
- }
12
- export async function getAxiosConfigGraph(tenantInfo: ITenantInfo, clearCache?: boolean) {
13
- if (isNullOrUndefined(auth)) throw Error("Call ConfigureGraphAuth first");
14
-
15
- // secret or certificate supported
16
- let token = await GetMSALToken(tenantInfo, graphScope, auth, clearCache);
17
- return getAxiosConfigBearer(token);
1
+ import { AuthContextType, ITenantInfo, isNullOrUndefined } from "@kwiz/common";
2
+ import { GetMSALToken } from "../auth/msal";
3
+ import { getAxiosConfigBearer } from "../axios";
4
+
5
+ /** "https://graph.microsoft.com" */
6
+ export const graphScope = "https://graph.microsoft.com";
7
+
8
+ var auth: AuthContextType = null;
9
+ export function ConfigureGraphAuth(config?: AuthContextType) {
10
+ auth = config;
11
+ }
12
+ export async function getAxiosConfigGraph(tenantInfo: ITenantInfo, clearCache?: boolean) {
13
+ if (isNullOrUndefined(auth)) throw Error("Call ConfigureGraphAuth first");
14
+
15
+ // secret or certificate supported
16
+ let token = await GetMSALToken(tenantInfo, graphScope, auth, clearCache);
17
+ return getAxiosConfigBearer(token);
18
18
  }
package/src/index.ts CHANGED
@@ -1 +1 @@
1
- export * from "./exports-index";
1
+ export * from "./exports-index";
@@ -1,15 +1,15 @@
1
- import { isNullOrEmptyString } from "@kwiz/common";
2
- import axios from "axios";
3
-
4
- export async function IsAzuriteRunning() {
5
- let responseServer = "";
6
- try {
7
- //make a request for http://127.0.0.1:10000/ expect response headers "Server" to contain "Azurite"
8
- const result = await axios.get("http://127.0.0.1:10000/");
9
- responseServer = result.headers.server;
10
- } catch (e) {
11
- responseServer = e.response && e.response.headers && e.response.headers.server;
12
- }
13
-
14
- return isNullOrEmptyString(responseServer) ? false : responseServer.toLowerCase().indexOf("azurite") >= 0;
15
- }
1
+ import { isNullOrEmptyString } from "@kwiz/common";
2
+ import axios from "axios";
3
+
4
+ export async function IsAzuriteRunning() {
5
+ let responseServer = "";
6
+ try {
7
+ //make a request for http://127.0.0.1:10000/ expect response headers "Server" to contain "Azurite"
8
+ const result = await axios.get("http://127.0.0.1:10000/");
9
+ responseServer = result.headers.server;
10
+ } catch (e) {
11
+ responseServer = e.response && e.response.headers && e.response.headers.server;
12
+ }
13
+
14
+ return isNullOrEmptyString(responseServer) ? false : responseServer.toLowerCase().indexOf("azurite") >= 0;
15
+ }
@@ -1,87 +1,87 @@
1
- import { isNullOrEmptyArray, isNullOrEmptyString, isNullOrUndefined } from "@kwiz/common";
2
-
3
- export enum ODataOperators {
4
- equal = "eq",
5
- notEqual = "ne",
6
- greater = "gt",
7
- greaterOrEqual = "ge",
8
- less = "lt",
9
- lessOrEqual = "le",
10
- contains = "in",
11
- startswith = "startswith"
12
- }
13
- export enum ODataJoinOperators {
14
- and = "and",
15
- or = "or"
16
- }
17
-
18
- export interface IOdataFilter<DataType> {
19
- property: keyof DataType;
20
- operator: ODataOperators;
21
- value: string | Date | number | boolean;
22
- not?: boolean;
23
- }
24
- export interface IOdataFilterStatement<DataType> {
25
- filters: (IOdataFilter<DataType> | IOdataFilterStatement<DataType>)[];
26
- /** default: or */
27
- join?: ODataJoinOperators;
28
- not?: boolean;
29
- }
30
- function isIOdataFilter<DataType>(f: IOdataFilter<DataType> | IOdataFilterStatement<DataType>): f is IOdataFilter<DataType> {
31
- if (typeof (f as IOdataFilter<DataType>).property === "string")
32
- return true;
33
- return false;
34
- }
35
- function isIOdataFilterStatement<DataType>(f: IOdataFilter<DataType> | IOdataFilterStatement<DataType>): f is IOdataFilter<DataType> {
36
- if (typeof (f as IOdataFilterStatement<DataType>).filters === "object" && Array.isArray((f as IOdataFilterStatement<DataType>).filters))
37
- return true;
38
- return false;
39
- }
40
-
41
- enum TableStorageKnownColumns {
42
- partitionKey = "PartitionKey",
43
- rowKey = "RowKey"
44
- }
45
-
46
- function getPropNameForFilter(prop: string | number | symbol) {
47
- return TableStorageKnownColumns[prop] || prop as string;
48
- }
49
- function getOdataFilterStatement<DataType>(filter: IOdataFilter<DataType>) {
50
- let filterValue = isNullOrUndefined(filter.value)
51
- ? `null`
52
- : typeof filter.value === "string"
53
- ? `'${filter.value.replace(/'/g, "''")}'`
54
- : filter.value instanceof Date
55
- ? `'${filter.value.toISOString()}'`
56
- : `${filter.value}`;
57
-
58
- if (filter.operator === ODataOperators.startswith)
59
- return `${filter.not ? 'not ' : ''}${filter.operator}(${getPropNameForFilter(filter.property)}, ${filterValue})`;
60
- return `${filter.not ? 'not ' : ''}${getPropNameForFilter(filter.property)} ${filter.operator} ${filterValue}`;
61
- }
62
-
63
- export function getOdataFilter<DataType>(statement: IOdataFilterStatement<DataType>) {
64
- if (isNullOrUndefined(statement) || isNullOrEmptyArray(statement.filters)) return "";
65
- if (isNullOrEmptyString(statement.join)) statement.join = ODataJoinOperators.or;
66
-
67
- let filterStatements: string[] = [];
68
- statement.filters.forEach(filter => {
69
- if (isIOdataFilter(filter)) {
70
- filterStatements.push(getOdataFilterStatement<DataType>(filter));
71
- }
72
- else {
73
- let subStatement = getOdataFilter(filter);
74
- if (!isNullOrEmptyString(subStatement))
75
- filterStatements.push(subStatement);
76
- }
77
- });
78
- if (filterStatements.length === 0) return "";
79
-
80
- let result = "";
81
- if (filterStatements.length === 1) result = filterStatements[0];
82
- else if (filterStatements.length > 1) {
83
- result = `(${filterStatements.join(` ${statement.join} `)})`;
84
- }
85
-
86
- return `${statement.not ? '(not ' : ''}${result}${statement.not ? ')' : ''}`;
1
+ import { isNullOrEmptyArray, isNullOrEmptyString, isNullOrUndefined } from "@kwiz/common";
2
+
3
+ export enum ODataOperators {
4
+ equal = "eq",
5
+ notEqual = "ne",
6
+ greater = "gt",
7
+ greaterOrEqual = "ge",
8
+ less = "lt",
9
+ lessOrEqual = "le",
10
+ contains = "in",
11
+ startswith = "startswith"
12
+ }
13
+ export enum ODataJoinOperators {
14
+ and = "and",
15
+ or = "or"
16
+ }
17
+
18
+ export interface IOdataFilter<DataType> {
19
+ property: keyof DataType;
20
+ operator: ODataOperators;
21
+ value: string | Date | number | boolean;
22
+ not?: boolean;
23
+ }
24
+ export interface IOdataFilterStatement<DataType> {
25
+ filters: (IOdataFilter<DataType> | IOdataFilterStatement<DataType>)[];
26
+ /** default: or */
27
+ join?: ODataJoinOperators;
28
+ not?: boolean;
29
+ }
30
+ function isIOdataFilter<DataType>(f: IOdataFilter<DataType> | IOdataFilterStatement<DataType>): f is IOdataFilter<DataType> {
31
+ if (typeof (f as IOdataFilter<DataType>).property === "string")
32
+ return true;
33
+ return false;
34
+ }
35
+ function isIOdataFilterStatement<DataType>(f: IOdataFilter<DataType> | IOdataFilterStatement<DataType>): f is IOdataFilter<DataType> {
36
+ if (typeof (f as IOdataFilterStatement<DataType>).filters === "object" && Array.isArray((f as IOdataFilterStatement<DataType>).filters))
37
+ return true;
38
+ return false;
39
+ }
40
+
41
+ enum TableStorageKnownColumns {
42
+ partitionKey = "PartitionKey",
43
+ rowKey = "RowKey"
44
+ }
45
+
46
+ function getPropNameForFilter(prop: string | number | symbol) {
47
+ return TableStorageKnownColumns[prop] || prop as string;
48
+ }
49
+ function getOdataFilterStatement<DataType>(filter: IOdataFilter<DataType>) {
50
+ let filterValue = isNullOrUndefined(filter.value)
51
+ ? `null`
52
+ : typeof filter.value === "string"
53
+ ? `'${filter.value.replace(/'/g, "''")}'`
54
+ : filter.value instanceof Date
55
+ ? `'${filter.value.toISOString()}'`
56
+ : `${filter.value}`;
57
+
58
+ if (filter.operator === ODataOperators.startswith)
59
+ return `${filter.not ? 'not ' : ''}${filter.operator}(${getPropNameForFilter(filter.property)}, ${filterValue})`;
60
+ return `${filter.not ? 'not ' : ''}${getPropNameForFilter(filter.property)} ${filter.operator} ${filterValue}`;
61
+ }
62
+
63
+ export function getOdataFilter<DataType>(statement: IOdataFilterStatement<DataType>) {
64
+ if (isNullOrUndefined(statement) || isNullOrEmptyArray(statement.filters)) return "";
65
+ if (isNullOrEmptyString(statement.join)) statement.join = ODataJoinOperators.or;
66
+
67
+ let filterStatements: string[] = [];
68
+ statement.filters.forEach(filter => {
69
+ if (isIOdataFilter(filter)) {
70
+ filterStatements.push(getOdataFilterStatement<DataType>(filter));
71
+ }
72
+ else {
73
+ let subStatement = getOdataFilter(filter);
74
+ if (!isNullOrEmptyString(subStatement))
75
+ filterStatements.push(subStatement);
76
+ }
77
+ });
78
+ if (filterStatements.length === 0) return "";
79
+
80
+ let result = "";
81
+ if (filterStatements.length === 1) result = filterStatements[0];
82
+ else if (filterStatements.length > 1) {
83
+ result = `(${filterStatements.join(` ${statement.join} `)})`;
84
+ }
85
+
86
+ return `${statement.not ? '(not ' : ''}${result}${statement.not ? ')' : ''}`;
87
87
  }
@@ -1,135 +1,135 @@
1
- import assert from 'assert/strict';
2
- import test from 'node:test';
3
- import { IsAzuriteRunning } from "./common";
4
- import { ODataOperators } from "./odata";
5
- import { ConfigureTableStorage, Table, addItem, ensureTable } from "./table-storage";
6
-
7
- test('testTableStorage', async t => {
8
- if (!(await IsAzuriteRunning())) {
9
- console.log('Skipping table-storage tests - azurite is not running.');
10
- return;
11
- }
12
- //configure storage
13
- ConfigureTableStorage({ connectionString: "UseDevelopmentStorage=true" });
14
-
15
- const tableName = "TestTable";
16
- const table = new Table(tableName, {
17
- getKeys: p => p,
18
- transform: {
19
- load: v => ({ ...v, schedule: JSON.parse(v.schedule) }),
20
- save: v => ({ ...v, schedule: JSON.stringify(v.schedule) })
21
- }
22
- });
23
- const partitionKey = "PK1";
24
- const partitionKey2 = "PK2";
25
- const rowKey1 = "0b8612bb-377d-4897-be8f-a532a1ad3e73|d2e32b93-c096-431c-8a79-fcce9a4d7bce";
26
- const rowKey2 = "0b8612bb-377d-4897-be8f-a532a1ad3e73|cd24aa15-0d03-4892-bb46-af32e5fb9361";
27
- //start fresh
28
- let result = await table.delete();
29
- //don't test this - it might have a table to delete and might not... depending if cleanup didn't work last run
30
- //await t.test("Delete table", t => assert.strictEqual(result, true));
31
-
32
- //provoke table name not allowed
33
- result = await ensureTable("T2");
34
- await t.test("Table name not allowed", t => assert.strictEqual(result, false));
35
-
36
- //create table
37
- result = await table.ensure();
38
- await t.test("Create table", t => assert.strictEqual(result, true));
39
-
40
- //provoke table already exists
41
- result = await table.ensure();
42
- await t.test("Ensure existing table", t => assert.strictEqual(result, true));
43
-
44
- //add item
45
- result = await table.addItem({
46
- partitionKey: partitionKey,
47
- rowKey: rowKey1,
48
- list: "1bd32599-375e-4c98-9e1c-ce9dd2f2e17d",
49
- action: "6b964dd7-6e62-42f6-89e4-5e79d6b6cbb0",
50
- nextUTC: "2023010105",
51
- schedule: { days: 4, hours: [1, 2, 3] }
52
- });
53
- await t.test("Create item 1", t => assert.strictEqual(result, true));
54
-
55
- result = await table.addItem({
56
- partitionKey: partitionKey,
57
- rowKey: rowKey2,
58
- list: "1bd32599-375e-4c98-9e1c-ce9dd2f2e17d",
59
- action: "fab4094b-c000-4ff4-bb52-0f8538b2bc49",
60
- nextUTC: "2023010105",
61
- schedule: { days: 4, hours: [1, 2, 3] }
62
- });
63
- await t.test("Create item 2", t => assert.strictEqual(result, true));
64
-
65
- result = await table.addItem({
66
- partitionKey: partitionKey2,
67
- rowKey: rowKey1,
68
- list: "b98211e2-809a-4761-b928-559eddc28dfc",
69
- action: "d20196e5-feb9-4202-bd03-718b49bf029e",
70
- nextUTC: "2023010105",
71
- schedule: { days: 4, hours: [1, 2, 3] }
72
- });
73
- await t.test("Create item in second partition", t => assert.strictEqual(result, true));
74
-
75
- //provoke add second item with same key
76
- result = await table.addItem({
77
- partitionKey: partitionKey,
78
- rowKey: rowKey1,
79
- list: "1bd32599-375e-4c98-9e1c-ce9dd2f2e17d",
80
- action: "6b964dd7-6e62-42f6-89e4-5e79d6b6cbb0",
81
- nextUTC: "2023010105",
82
- schedule: { days: 4, hours: [1, 2, 3] }
83
- });
84
- await t.test("Create item with existing key", t => assert.strictEqual(result, false));
85
-
86
- //provoke add second item with same key
87
- result = await table.upsertItem({
88
- partitionKey: partitionKey,
89
- rowKey: rowKey1,
90
- list: "1bd32599-375e-4c98-9e1c-ce9dd2f2e17d",
91
- action: "6b964dd7-6e62-42f6-89e4-5e79d6b6cbb0",
92
- nextUTC: "2023020202",
93
- schedule: { days: 4, hours: [1, 2, 3] }
94
- });
95
- await t.test("Update item 1", t => assert.strictEqual(result, true));
96
-
97
- //provoke add item to table that does not exist
98
- result = await addItem(tableName + "DoeNotExist", {
99
- partitionKey: partitionKey,
100
- rowKey: rowKey1,
101
- list: "1bd32599-375e-4c98-9e1c-ce9dd2f2e17d",
102
- action: "6b964dd7-6e62-42f6-89e4-5e79d6b6cbb0",
103
- nextUTC: "2023020202",
104
- schedule: { days: 4, hours: [1, 2, 3] }
105
- });
106
- await t.test("Create item in table that does not exist", t => assert.strictEqual(result, false));
107
-
108
- let allItems = await table.getItems();
109
- await t.test("Get items", t => assert.strictEqual(allItems.length, 3));
110
-
111
- //find items by partition
112
- let partitionItems = await table.getItems({
113
- filterStatment: {
114
- filters: [
115
- {
116
- property: "partitionKey",
117
- operator: ODataOperators.equal,
118
- value: partitionKey
119
- }
120
- ]
121
- }
122
- });
123
-
124
- await t.test("Get items with filter", t => assert.strictEqual(partitionItems.length, 2));
125
- await t.test("Update values", t => assert.strictEqual(partitionItems[1].nextUTC, "2023020202"));
126
-
127
- let deleteResult = await table.deleteItem({ partitionKey: partitionKey, rowKey: rowKey1 });
128
- await t.test("delete item", t => assert.strictEqual(deleteResult, true));
129
- deleteResult = await table.deleteItem({ partitionKey: partitionKey, rowKey: rowKey1 });
130
- await t.test("delete item that was already deleted", t => assert.strictEqual(deleteResult, true));
131
-
132
- //cleanup
133
- result = await table.delete();
134
- await t.test("Delete table", t => assert.strictEqual(result, true));
1
+ import assert from 'assert/strict';
2
+ import test from 'node:test';
3
+ import { IsAzuriteRunning } from "./common";
4
+ import { ODataOperators } from "./odata";
5
+ import { ConfigureTableStorage, Table, addItem, ensureTable } from "./table-storage";
6
+
7
+ test('testTableStorage', async t => {
8
+ if (!(await IsAzuriteRunning())) {
9
+ console.log('Skipping table-storage tests - azurite is not running.');
10
+ return;
11
+ }
12
+ //configure storage
13
+ ConfigureTableStorage({ connectionString: "UseDevelopmentStorage=true" });
14
+
15
+ const tableName = "TestTable";
16
+ const table = new Table(tableName, {
17
+ getKeys: p => p,
18
+ transform: {
19
+ load: v => ({ ...v, schedule: JSON.parse(v.schedule) }),
20
+ save: v => ({ ...v, schedule: JSON.stringify(v.schedule) })
21
+ }
22
+ });
23
+ const partitionKey = "PK1";
24
+ const partitionKey2 = "PK2";
25
+ const rowKey1 = "0b8612bb-377d-4897-be8f-a532a1ad3e73|d2e32b93-c096-431c-8a79-fcce9a4d7bce";
26
+ const rowKey2 = "0b8612bb-377d-4897-be8f-a532a1ad3e73|cd24aa15-0d03-4892-bb46-af32e5fb9361";
27
+ //start fresh
28
+ let result = await table.delete();
29
+ //don't test this - it might have a table to delete and might not... depending if cleanup didn't work last run
30
+ //await t.test("Delete table", t => assert.strictEqual(result, true));
31
+
32
+ //provoke table name not allowed
33
+ result = await ensureTable("T2");
34
+ await t.test("Table name not allowed", t => assert.strictEqual(result, false));
35
+
36
+ //create table
37
+ result = await table.ensure();
38
+ await t.test("Create table", t => assert.strictEqual(result, true));
39
+
40
+ //provoke table already exists
41
+ result = await table.ensure();
42
+ await t.test("Ensure existing table", t => assert.strictEqual(result, true));
43
+
44
+ //add item
45
+ result = await table.addItem({
46
+ partitionKey: partitionKey,
47
+ rowKey: rowKey1,
48
+ list: "1bd32599-375e-4c98-9e1c-ce9dd2f2e17d",
49
+ action: "6b964dd7-6e62-42f6-89e4-5e79d6b6cbb0",
50
+ nextUTC: "2023010105",
51
+ schedule: { days: 4, hours: [1, 2, 3] }
52
+ });
53
+ await t.test("Create item 1", t => assert.strictEqual(result, true));
54
+
55
+ result = await table.addItem({
56
+ partitionKey: partitionKey,
57
+ rowKey: rowKey2,
58
+ list: "1bd32599-375e-4c98-9e1c-ce9dd2f2e17d",
59
+ action: "fab4094b-c000-4ff4-bb52-0f8538b2bc49",
60
+ nextUTC: "2023010105",
61
+ schedule: { days: 4, hours: [1, 2, 3] }
62
+ });
63
+ await t.test("Create item 2", t => assert.strictEqual(result, true));
64
+
65
+ result = await table.addItem({
66
+ partitionKey: partitionKey2,
67
+ rowKey: rowKey1,
68
+ list: "b98211e2-809a-4761-b928-559eddc28dfc",
69
+ action: "d20196e5-feb9-4202-bd03-718b49bf029e",
70
+ nextUTC: "2023010105",
71
+ schedule: { days: 4, hours: [1, 2, 3] }
72
+ });
73
+ await t.test("Create item in second partition", t => assert.strictEqual(result, true));
74
+
75
+ //provoke add second item with same key
76
+ result = await table.addItem({
77
+ partitionKey: partitionKey,
78
+ rowKey: rowKey1,
79
+ list: "1bd32599-375e-4c98-9e1c-ce9dd2f2e17d",
80
+ action: "6b964dd7-6e62-42f6-89e4-5e79d6b6cbb0",
81
+ nextUTC: "2023010105",
82
+ schedule: { days: 4, hours: [1, 2, 3] }
83
+ });
84
+ await t.test("Create item with existing key", t => assert.strictEqual(result, false));
85
+
86
+ //provoke add second item with same key
87
+ result = await table.upsertItem({
88
+ partitionKey: partitionKey,
89
+ rowKey: rowKey1,
90
+ list: "1bd32599-375e-4c98-9e1c-ce9dd2f2e17d",
91
+ action: "6b964dd7-6e62-42f6-89e4-5e79d6b6cbb0",
92
+ nextUTC: "2023020202",
93
+ schedule: { days: 4, hours: [1, 2, 3] }
94
+ });
95
+ await t.test("Update item 1", t => assert.strictEqual(result, true));
96
+
97
+ //provoke add item to table that does not exist
98
+ result = await addItem(tableName + "DoeNotExist", {
99
+ partitionKey: partitionKey,
100
+ rowKey: rowKey1,
101
+ list: "1bd32599-375e-4c98-9e1c-ce9dd2f2e17d",
102
+ action: "6b964dd7-6e62-42f6-89e4-5e79d6b6cbb0",
103
+ nextUTC: "2023020202",
104
+ schedule: { days: 4, hours: [1, 2, 3] }
105
+ });
106
+ await t.test("Create item in table that does not exist", t => assert.strictEqual(result, false));
107
+
108
+ let allItems = await table.getItems();
109
+ await t.test("Get items", t => assert.strictEqual(allItems.length, 3));
110
+
111
+ //find items by partition
112
+ let partitionItems = await table.getItems({
113
+ filterStatment: {
114
+ filters: [
115
+ {
116
+ property: "partitionKey",
117
+ operator: ODataOperators.equal,
118
+ value: partitionKey
119
+ }
120
+ ]
121
+ }
122
+ });
123
+
124
+ await t.test("Get items with filter", t => assert.strictEqual(partitionItems.length, 2));
125
+ await t.test("Update values", t => assert.strictEqual(partitionItems[1].nextUTC, "2023020202"));
126
+
127
+ let deleteResult = await table.deleteItem({ partitionKey: partitionKey, rowKey: rowKey1 });
128
+ await t.test("delete item", t => assert.strictEqual(deleteResult, true));
129
+ deleteResult = await table.deleteItem({ partitionKey: partitionKey, rowKey: rowKey1 });
130
+ await t.test("delete item that was already deleted", t => assert.strictEqual(deleteResult, true));
131
+
132
+ //cleanup
133
+ result = await table.delete();
134
+ await t.test("Delete table", t => assert.strictEqual(result, true));
135
135
  });