diff --git a/sdk/tables/data-tables/CHANGELOG.md b/sdk/tables/data-tables/CHANGELOG.md index d1b57367a60f..fa3f4232e3e2 100644 --- a/sdk/tables/data-tables/CHANGELOG.md +++ b/sdk/tables/data-tables/CHANGELOG.md @@ -1,5 +1,15 @@ # Release History +## 13.0.1 (Unreleased) + +### Features Added + +### Breaking Changes + +### Bugs Fixed + +### Other Changes + ## 13.0.0 (2021-11-11) ### Acknowledgments diff --git a/sdk/tables/data-tables/package.json b/sdk/tables/data-tables/package.json index e90b8b1ef564..c0201a0ae634 100644 --- a/sdk/tables/data-tables/package.json +++ b/sdk/tables/data-tables/package.json @@ -1,6 +1,6 @@ { "name": "@azure/data-tables", - "version": "13.0.0", + "version": "13.0.1", "description": "An isomorphic client library for the Azure Tables service.", "sdk-type": "client", "main": "dist/index.js", diff --git a/sdk/tables/data-tables/samples/v13/javascript/README.md b/sdk/tables/data-tables/samples/v13/javascript/README.md new file mode 100644 index 000000000000..6a6528aa1bb3 --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/javascript/README.md @@ -0,0 +1,85 @@ +--- +page_type: sample +languages: + - javascript +products: + - azure + - azure-table-storage +urlFragment: data-tables-javascript +--- + +# Azure Data Tables client library samples for JavaScript + +These sample programs show how to use the JavaScript client libraries for Azure Data Tables in some common scenarios. + +| **File Name** | **Description** | +| ----------------------------------------------------- | ------------------------------------------------------------------------- | +| [workingWithBigInt.js][workingwithbigint] | creates and works with an entity containing a bigint | +| [workingWithInt64.js][workingwithint64] | creates and works with an entity containing an Int64 value | +| [transactionWithHelper.js][transactionwithhelper] | sends transactional request using TableTransaction helper | +| [transactionOperations.js][transactionoperations] | sends transactional batch requests | +| [usingContinuationToken.js][usingcontinuationtoken] | queries entities in a table by page manually handling continuation tokens | +| [authenticationMethods.js][authenticationmethods] | authenticates using different authentication methods | +| [createAndDeleteEntities.js][createanddeleteentities] | creates and deletes a entities in a table | +| [createAndDeleteTable.js][createanddeletetable] | creates and deletes a table | +| [generateTableSAS.js][generatetablesas] | generate a Table Account SAS token | +| [queryEntities.js][queryentities] | queries entities in a table | +| [queryTables.js][querytables] | queries tables | +| [updateAndUpsertEntities.js][updateandupsertentities] | updates and upserts entities in a table | + +## Prerequisites + +The sample programs are compatible with [LTS versions of Node.js](https://nodejs.org/about/releases/). + +You need [an Azure subscription][freesub] and the following Azure resources to run these sample programs: + +- [Azure Storage instance][createinstance_azurestorageinstance] + +Samples retrieve credentials to access the service endpoint from environment variables. Alternatively, edit the source code to include the appropriate credentials. See each individual sample for details on which environment variables/credentials it requires to function. + +Adapting the samples to run in the browser may require some additional consideration. For details, please see the [package README][package]. + +## Setup + +To run the samples using the published version of the package: + +1. Install the dependencies using `npm`: + +```bash +npm install +``` + +2. Edit the file `sample.env`, adding the correct credentials to access the Azure service and run the samples. Then rename the file from `sample.env` to just `.env`. The sample programs will read this file automatically. + +3. Run whichever samples you like (note that some samples may require additional setup, see the table above): + +```bash +node workingWithBigInt.js +``` + +Alternatively, run a single sample with the correct environment variables set (setting up the `.env` file is not required if you do this), for example (cross-platform): + +```bash +npx cross-env TABLES_URL="" ACCOUNT_NAME="" ACCOUNT_KEY="" node workingWithBigInt.js +``` + +## Next Steps + +Take a look at our [API Documentation][apiref] for more information about the APIs that are available in the clients. + +[workingwithbigint]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/javascript/workingWithBigInt.js +[workingwithint64]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/javascript/workingWithInt64.js +[transactionwithhelper]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/javascript/transactionWithHelper.js +[transactionoperations]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/javascript/transactionOperations.js +[usingcontinuationtoken]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/javascript/usingContinuationToken.js +[authenticationmethods]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/javascript/authenticationMethods.js +[createanddeleteentities]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/javascript/createAndDeleteEntities.js +[createanddeletetable]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/javascript/createAndDeleteTable.js +[generatetablesas]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/javascript/generateTableSAS.js +[queryentities]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/javascript/queryEntities.js +[querytables]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/javascript/queryTables.js +[updateandupsertentities]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/javascript/updateAndUpsertEntities.js +[apiref]: https://docs.microsoft.com/javascript/api/@azure/data-tables +[freesub]: https://azure.microsoft.com/free/ +[createinstance_azurestorageinstance]: https://docs.microsoft.com/azure/storage/tables/table-storage-quickstart-portal +[package]: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/tables/data-tables/README.md diff --git a/sdk/tables/data-tables/samples/v13/javascript/authenticationMethods.js b/sdk/tables/data-tables/samples/v13/javascript/authenticationMethods.js new file mode 100644 index 000000000000..0ba7377d9502 --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/javascript/authenticationMethods.js @@ -0,0 +1,111 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/** + * This sample demonstrates how to use the different methods of authentication + * to make calls to the Azure Tables Service + * + * @summary authenticates using different authentication methods + */ +const { + TableServiceClient, + AzureNamedKeyCredential, + AzureSASCredential +} = require("@azure/data-tables"); + +const { DefaultAzureCredential } = require("@azure/identity"); + +// Load the .env file if it exists +const dotenv = require("dotenv"); +dotenv.config(); + +// URL of the tables endpoint +const tablesUrl = process.env["TABLES_URL"] || ""; + +// You can find your storage account's name, connection strings and keys in the Azure portal. +// Navigate to Settings > Access keys in your storage account's menu blade to see connection strings for both primary and secondary access keys +const accountConnectionString = process.env["ACCOUNT_CONNECTION_STRING"] || ""; +const accountName = process.env["ACCOUNT_NAME"] || ""; +const accountKey = process.env["ACCOUNT_KEY"] || ""; + +// You can generate a SAS connection string and token for your storage account in the Azure Portal +// Navigate to Settings > "Shared access signature" in your storage account's menu blade select the Allowed services, resource types, permissions and expiry options +// and generate your SAS and connection string. +const sasConnectionString = process.env["SAS_CONNECTION_STRING"] || ""; +const sasToken = process.env["SAS_TOKEN"] || ""; + +/** + * Create a TableServiceCLient using a SAS connection String + */ +async function tableServiceClientWithSasConnectionString() { + const client = TableServiceClient.fromConnectionString(sasConnectionString); + countTablesWithClient(client); +} + +/** + * Create a TableServiceCLient using a SAS connection String + */ +async function tableServiceClientWithAAD() { + // DefaultAzureCredential expects the following three environment variables: + // - AZURE_TENANT_ID: The tenant ID in Azure Active Directory + // - AZURE_CLIENT_ID: The application (client) ID registered in the AAD tenant + // - AZURE_CLIENT_SECRET: The client secret for the registered application + const credential = new DefaultAzureCredential(); + const client = new TableServiceClient(tablesUrl, credential); + countTablesWithClient(client); +} + +/** + * Create a TableServiceCLient using a SAS token + */ +async function tableServiceClientWithSasToken() { + const client = new TableServiceClient(tablesUrl, new AzureSASCredential(sasToken)); + countTablesWithClient(client); +} + +/** + * Create a TableServiceCLient using an Account connection String. + * Note that this authentication method is only supported in Node, + * and it is not available for browsers + */ +async function tableServiceClientWithAccountConnectionString() { + const client = TableServiceClient.fromConnectionString(accountConnectionString); + countTablesWithClient(client); +} + +/** + * Create a TableServiceCLient using account name and account key + * Note that this authentication method is only supported in Node, + * and it is not available for browsers + */ +async function tableServiceClientWithAccountKey() { + const creds = new AzureNamedKeyCredential(accountName, accountKey); + const client = new TableServiceClient(tablesUrl, creds); + countTablesWithClient(client); +} + +async function countTablesWithClient(client) { + const tablesIterator = client.listTables(); + let count = 0; + for await (const _table of tablesIterator) { + count++; + } + + console.log(`Listed ${count} tables`); +} + +async function main() { + console.log("== Client Authentication Methods Sample =="); + + await tableServiceClientWithSasConnectionString(); + await tableServiceClientWithSasToken(); + + await tableServiceClientWithAccountConnectionString(); + await tableServiceClientWithAccountKey(); + + await tableServiceClientWithAAD(); +} + +main().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/javascript/createAndDeleteEntities.js b/sdk/tables/data-tables/samples/v13/javascript/createAndDeleteEntities.js new file mode 100644 index 000000000000..70cf4c0c3b40 --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/javascript/createAndDeleteEntities.js @@ -0,0 +1,105 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/** + * This sample demonstrates create and delete entities in a table + * + * @summary creates and deletes a entities in a table + */ + +const { TableClient, AzureNamedKeyCredential } = require("@azure/data-tables"); + +// Load the .env file if it exists +const dotenv = require("dotenv"); +dotenv.config(); + +const tablesUrl = process.env["TABLES_URL"] || ""; +const accountName = process.env["ACCOUNT_NAME"] || ""; +const accountKey = process.env["ACCOUNT_KEY"] || ""; + +async function createSimpleDateEntity() { + // Note that this sample assumes that a table with tableName exists + const tableName = `createSimpleDateEntityTable`; + + // See authenticationMethods sample for other options of creating a new client + const creds = new AzureNamedKeyCredential(accountName, accountKey); + const client = new TableClient(tablesUrl, tableName, creds); + + await client.createTable(); + + const entity = { + partitionKey: "p1", + rowKey: "r1", + date: new Date() + }; + + await client.createEntity(entity); + + await client.deleteTable(); +} + +async function createComplexDateEntity() { + // Note that this sample assumes that a table with tableName exists + const tableName = `createComplexDateEntityTable`; + + // See authenticationMethods sample for other options of creating a new client + const creds = new AzureNamedKeyCredential(accountName, accountKey); + const client = new TableClient(tablesUrl, tableName, creds); + + await client.createTable(); + + // For higher precision dates we need to pass the + const date = { type: "DateTime", value: "2016-06-10T21:42:24.7607389" }; + + const entity = { + partitionKey: "p2", + rowKey: "r2", + date + }; + + await client.createEntity(entity); + + await client.deleteTable(); +} + +async function createAndDeleteEntities() { + console.log("== Create and delete entities Sample =="); + + // Note that this sample assumes that a table with tableName exists + const tableName = `createAndDeleteEntitiesTable`; + + // See authenticationMethods sample for other options of creating a new client + const creds = new AzureNamedKeyCredential(accountName, accountKey); + const client = new TableClient(tablesUrl, tableName, creds); + + // Create the table + await client.createTable(); + + const entity = { + partitionKey: "Stationery", + rowKey: "A1", + name: "Marker Set", + price: 5.0, + quantity: 21 + }; + + // Create the new entity + await client.createEntity(entity); + + // Delete the entity + await client.deleteEntity(entity.partitionKey, entity.rowKey); + + // Delete the table for cleanup + // Create the table + await client.deleteTable(); +} + +async function main() { + await createAndDeleteEntities(); + await createSimpleDateEntity(); + await createComplexDateEntity(); +} + +main().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/javascript/createAndDeleteTable.js b/sdk/tables/data-tables/samples/v13/javascript/createAndDeleteTable.js new file mode 100644 index 000000000000..87c6e142a2e3 --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/javascript/createAndDeleteTable.js @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * This sample demonstrates create and delete a table + * + * @summary creates and deletes a table + */ + +const { TableServiceClient, TableClient } = require("@azure/data-tables"); +const { v4 } = require("uuid"); + +// Load the .env file if it exists +const dotenv = require("dotenv"); +dotenv.config(); + +const sasConnectionString = process.env["SAS_CONNECTION_STRING"] || ""; +const tableSufix = v4().replace(/-/g, ""); + +async function createAndDeleteTable() { + console.log("== Delete and create table Sample =="); + + // See authenticationMethods sample for other options of creating a new client + const serviceClient = TableServiceClient.fromConnectionString(sasConnectionString); + + // Create a new table + const tableName = `SampleCreateAndDeleteTable${tableSufix}`; + await serviceClient.createTable(tableName); + + // Deletes the table + await serviceClient.deleteTable(tableName); +} + +async function createAndDeleteTableWithTableClient() { + // A table can also be created and deleted using a TableClient + console.log("== Delete and create table with TableClient Sample =="); + + const tableName = "SampleCreateAndDeleteTable2"; + + // Creating a new table client doesn't do a network call + const client = TableClient.fromConnectionString(sasConnectionString, tableName); + + // Will attempt to create a table with the tableName specified above + await client.createTable(); + + // Will attempt to delete the table with the tableName specified above + await client.deleteTable(); +} + +async function main() { + await createAndDeleteTable(); + await createAndDeleteTableWithTableClient(); +} + +main().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/javascript/generateTableSAS.js b/sdk/tables/data-tables/samples/v13/javascript/generateTableSAS.js new file mode 100644 index 000000000000..489f91615d65 --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/javascript/generateTableSAS.js @@ -0,0 +1,111 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * This sample demonstrates how to create an Account SAS token. An account SAS token + * provides access to the whole Tables Service account, given the permissions selected, + * by default the only permission granted is list + * + * @summary generate a Table Account SAS token + */ + +const { + generateAccountSas, + generateTableSas, + TableClient, + TableServiceClient +} = require("@azure/data-tables"); +const { AzureNamedKeyCredential, AzureSASCredential } = require("@azure/core-auth"); + +// Load the .env file if it exists +const dotenv = require("dotenv"); +dotenv.config(); + +const tablesUrl = process.env["TABLES_URL"] || ""; +const accountKey = process.env["ACCOUNT_KEY"] || ""; +const accountName = process.env["ACCOUNT_NAME"] || ""; + +async function generateTableSasSample() { + console.log("== Generate Table Account SAS Sample =="); + + // We need a NamedKeyCredential to generate the SAS token + const cred = new AzureNamedKeyCredential(accountName, accountKey); + + // We can optionally set the permissions we want on the SAS token + // If non is specified, only list is granted + const permissions = { + // Grants permission to list tables + list: true, + // Grants permission to create tables + write: true, + // Grants permission to create entities + add: true, + // Grants permission to query entities + query: true, + // Grants permission to delete tables and entities + delete: true + }; + + // Generate an account SAS with the NamedKeyCredential and the permissions set previously + const accountSas = generateAccountSas(cred, { + permissions, + expiresOn: new Date("2021-12-12") + }); + + const tableService = new TableServiceClient(tablesUrl, new AzureSASCredential(accountSas)); + + // Create a new table + const tableName = "fooTable"; + await tableService.createTable(tableName); + + // List all the tables in the service account + const tables = tableService.listTables(); + for await (const table of tables) { + console.log(table); + } + + // We are going to create a new SAS token scoped down to the specific table we just created. + // If no permissions are provided, by default the token would have only query permission + const tablePermissions = { + // Allows adding entities + add: true, + // Allows querying entities + query: true, + // Allows deleting entities + delete: true, + // Allows updating entities + update: true + }; + + // Create the table SAS token + const tableSas = generateTableSas(tableName, cred, { + expiresOn: new Date("2021-12-12"), + permissions: tablePermissions + }); + + // Create a new client for the table we just created. Alternatively the Table Account SAS token could be used here as well + // however using Table level SAS tokens offers a more granular access control + const table = new TableClient(tablesUrl, tableName, new AzureSASCredential(tableSas)); + + // Create an entity in the table + await table.createEntity({ partitionKey: "test", rowKey: "1", foo: "bar" }); + + // List all the entities in the table + const entities = table.listEntities(); + for await (const entity of entities) { + console.log(entity); + } + + // Delete the entity we just created + await table.deleteEntity("test", "1"); + + // Delete the Table + await tableService.deleteTable(tableName); +} + +async function main() { + await generateTableSasSample(); +} + +main().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/javascript/package.json b/sdk/tables/data-tables/samples/v13/javascript/package.json new file mode 100644 index 000000000000..2dcd66a6c087 --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/javascript/package.json @@ -0,0 +1,31 @@ +{ + "name": "azure-data-tables-samples-js", + "private": true, + "version": "1.0.0", + "description": "Azure Data Tables client library samples for JavaScript", + "engines": { + "node": ">=12.0.0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Azure/azure-sdk-for-js.git", + "directory": "sdk/tables/data-tables" + }, + "keywords": [ + "azure", + "cloud" + ], + "author": "Microsoft Corporation", + "license": "MIT", + "bugs": { + "url": "https://github.com/Azure/azure-sdk-for-js/issues" + }, + "homepage": "https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/tables/data-tables", + "dependencies": { + "@azure/data-tables": "latest", + "dotenv": "latest", + "@azure/identity": "^2.0.1", + "uuid": "^8.3.0", + "@azure/core-auth": "^1.3.0" + } +} diff --git a/sdk/tables/data-tables/samples/v13/javascript/queryEntities.js b/sdk/tables/data-tables/samples/v13/javascript/queryEntities.js new file mode 100644 index 000000000000..ccd445e5a598 --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/javascript/queryEntities.js @@ -0,0 +1,115 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * This sample demonstrates how to query entities in a table + * + * @summary queries entities in a table + */ + +const { odata, TableClient } = require("@azure/data-tables"); + +// Load the .env file if it exists +const dotenv = require("dotenv"); +dotenv.config(); + +const tablesUrl = process.env["TABLES_URL"] || ""; +const sasToken = process.env["SAS_TOKEN"] || ""; + +async function listEntities() { + console.log("== List entities Sample =="); + + // Note that this sample assumes that a table with tableName exists + const tableName = `queryEntitiesTable`; + console.log(tableName); + + // See authenticationMethods sample for other options of creating a new client + const client = new TableClient(`${tablesUrl}${sasToken}`, tableName); + // Create the table + await client.createTable(); + + const partitionKey = "Stationery"; + const marker = { + partitionKey, + rowKey: "1", + name: "Markers", + price: 5.0, + quantity: 34 + }; + + const planner = { + partitionKey, + rowKey: "2", + name: "Planner", + price: 7.0, + quantity: 34 + }; + + // create entities for marker and planner + await client.createEntity(marker); + await client.createEntity(planner); + + // List all entities with PartitionKey "Stationery" + const listResults = client.listEntities({ + queryOptions: { filter: odata`PartitionKey eq ${partitionKey}` } + }); + + for await (const product of listResults) { + console.log(`${product.name}: ${product.price}`); + } + + // List all entities with a price less than 6.0 + const priceListResults = client.listEntities({ + queryOptions: { filter: odata`price le 6` } + }); + + console.log("-- Products with a price less or equals to 6.00"); + for await (const product of priceListResults) { + console.log(`${product.name}: ${product.price}`); + } +} + +// Sample of how to retreive the top N entities for a query +async function listTopNEntities() { + // This is the max number of items + const topN = 1; + const partitionKey = "Stationery"; + + // Note that this sample assumes that a table with tableName exists + const tableName = `queryEntitiesTable`; + + // See authenticationMethods sample for other options of creating a new client + const client = new TableClient(`${tablesUrl}${sasToken}`, tableName); + + // List all entities with PartitionKey "Stationery" + const listResults = client.listEntities({ + queryOptions: { + filter: odata`PartitionKey eq ${partitionKey}` + } + }); + + let topEntities = []; + const iterator = listResults.byPage({ maxPageSize: topN }); + + for await (const page of iterator) { + // Take the first page as the topEntires result + topEntities = page; + // We break to only get the first page + // this only sends a single request to the service + break; + } + + console.log(`Top entities: ${topEntities.length}`); + // Top entities: 1 + + // Delete the table to cleanup + await client.deleteTable(); +} + +async function main() { + await listEntities(); + await listTopNEntities(); +} + +main().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/javascript/queryTables.js b/sdk/tables/data-tables/samples/v13/javascript/queryTables.js new file mode 100644 index 000000000000..18b929b6aa8e --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/javascript/queryTables.js @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * This sample demonstrates how to query tables + * + * @summary queries tables + */ + +const { odata, TableServiceClient } = require("@azure/data-tables"); + +// Load the .env file if it exists +const dotenv = require("dotenv"); +dotenv.config(); + +const accountConnectionString = process.env["ACCOUNT_CONNECTION_STRING"] || ""; + +async function queryTables() { + console.log("== Query tables Sample =="); + + // See authenticationMethods sample for other options of creating a new client + const serviceClient = TableServiceClient.fromConnectionString(accountConnectionString); + + // Create a new table + const tableName = `queryTables`; + await serviceClient.createTable(tableName); + + // list the tables with a filter query, queryOptions is optional. + // odata is a helper function that takes care of encoding the query + // filter, in this sample it will add quotes around tableName + const queryTableResults = serviceClient.listTables({ + queryOptions: { filter: odata`TableName eq ${tableName}` } + }); + + // Iterate the results + for await (const table of queryTableResults) { + console.log(table.name); + } + + // Deletes the table + await serviceClient.deleteTable(tableName); +} + +async function main() { + await queryTables(); +} + +main().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/javascript/sample.env b/sdk/tables/data-tables/samples/v13/javascript/sample.env new file mode 100644 index 000000000000..a53dc827f4af --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/javascript/sample.env @@ -0,0 +1,8 @@ +ACCOUNT_CONNECTION_STRING= +SAS_CONNECTION_STRING= +ACCOUNT_NAME= +ACCOUNT_KEY= +ACCOUNT_URL= +ACCOUNT_SAS= +TABLES_URL= +SAS_TOKEN= diff --git a/sdk/tables/data-tables/samples/v13/javascript/transactionOperations.js b/sdk/tables/data-tables/samples/v13/javascript/transactionOperations.js new file mode 100644 index 000000000000..04d4a13338e3 --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/javascript/transactionOperations.js @@ -0,0 +1,118 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * This sample demonstrates how to send a transactional request + * with multiple operations in a single request + * + * @summary sends transactional batch requests + */ + +const { TableClient } = require("@azure/data-tables"); + +// Load the .env file if it exists +const dotenv = require("dotenv"); +dotenv.config(); + +const connectionString = process.env["ACCOUNT_CONNECTION_STRING"] || ""; + +async function batchOperations() { + console.log("== Batch Operations Sample =="); + const tableName = `transactionsSample`; + + // See authenticationMethods sample for other options of creating a new client + const client = TableClient.fromConnectionString(connectionString, tableName); + + // Create the table + await client.createTable(); + + const partitionKey = "Stationery"; + + const actions = [ + [ + "create", + { + partitionKey, + rowKey: "A1", + name: "Marker Set", + price: 5.0, + quantity: 21 + } + ], + [ + "create", + { + partitionKey, + rowKey: "A2", + name: "Pen Set", + price: 2.0, + quantity: 6 + } + ], + [ + "create", + { + partitionKey, + rowKey: "A3", + name: "Pencil", + price: 1.5, + quantity: 100 + } + ] + ]; + + // Submit the transaction with the list of actions. + // Note that all the operations within a transaction must target the same partition key + const transactionResult = await client.submitTransaction(actions); + + console.log(transactionResult.subResponses); + // Output: + // [ + // { + // status: 204, + // rowKey: 'A1', + // etag: `W/"datetime'2020-10-02T03%3A31%3A09.9324186Z'"` + // }, + // { + // status: 204, + // rowKey: 'A2', + // etag: `W/"datetime'2020-10-02T03%3A31%3A09.9324186Z'"` + // }, + // { + // status: 204, + // rowKey: 'A3', + // etag: `W/"datetime'2020-10-02T03%3A31%3A09.9324186Z'"` + // } + // ] + + // We can also send transactions with update operations + const updateTransaction = [ + // The default update mode is "Merge" which only replaces the properties in the entity we send + // all other properties are kept as they are stored + ["update", { partitionKey, rowKey: "A1", name: "[Updated - Merge] Marker Set" }], + // If we set the update mode to "Replace", the original entity will be replaced with exactly what we send. + // We need to be careful when using replace, because if we forget to pass a property it will get deleted. + [ + "update", + { partitionKey, rowKey: "A2", name: "[Updated - Replace] Pen Set", price: 99, quantity: 33 }, + "Replace" + ] + ]; + + const updateResult = await client.submitTransaction(updateTransaction); + + console.log(updateResult); + + // Now we'll query our entities + const entities = client.listEntities(); + + for await (const entity of entities) { + console.log(entity); + } + + // Delete the table to clean up + await client.deleteTable(); +} + +batchOperations().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/javascript/transactionWithHelper.js b/sdk/tables/data-tables/samples/v13/javascript/transactionWithHelper.js new file mode 100644 index 000000000000..59f5d5b5172e --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/javascript/transactionWithHelper.js @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * This sample demonstrates how to use the TableTransaction helper + * to build a transaction request. + * + * @summary sends transactional request using TableTransaction helper + */ + +const { TableClient, TableTransaction } = require("@azure/data-tables"); + +// Load the .env file if it exists +const dotenv = require("dotenv"); +dotenv.config(); + +const connectionString = process.env["ACCOUNT_CONNECTION_STRING"] || ""; +async function batchOperations() { + console.log("== TableTransaction Sample =="); + + // Note that this sample assumes that a table with tableName exists + const tableName = `transactionHelper`; + + // See authenticationMethods sample for other options of creating a new client + const client = TableClient.fromConnectionString(connectionString, tableName); + + // Create the table + await client.createTable(); + + const partitionKey = "Stationery"; + + const transaction = new TableTransaction(); + + // Add actions to the transaction + transaction.createEntity({ + partitionKey, + rowKey: "A1", + name: "Marker Set", + price: 5.0, + quantity: 21 + }); + transaction.createEntity({ + partitionKey, + rowKey: "A2", + name: "Pen Set", + price: 2.0, + quantity: 6 + }); + transaction.createEntity({ + partitionKey, + rowKey: "A3", + name: "Pencil", + price: 1.5, + quantity: 100 + }); + + // Submit the transaction using the actions list built by the helper + const transactionResult = await client.submitTransaction(transaction.actions); + + console.log(transactionResult.subResponses); + // Output: + // [ + // { + // status: 204, + // rowKey: 'A1', + // etag: `W/"datetime'2020-10-02T03%3A31%3A09.9324186Z'"` + // }, + // { + // status: 204, + // rowKey: 'A2', + // etag: `W/"datetime'2020-10-02T03%3A31%3A09.9324186Z'"` + // }, + // { + // status: 204, + // rowKey: 'A3', + // etag: `W/"datetime'2020-10-02T03%3A31%3A09.9324186Z'"` + // } + // ] + + // Delete the table to clean up + await client.deleteTable(); +} + +batchOperations().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/javascript/updateAndUpsertEntities.js b/sdk/tables/data-tables/samples/v13/javascript/updateAndUpsertEntities.js new file mode 100644 index 000000000000..fc88a00b9567 --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/javascript/updateAndUpsertEntities.js @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * This sample demonstrates how to perform entity update and upsert operations in a table + * + * @summary updates and upserts entities in a table + */ + +const { TableClient } = require("@azure/data-tables"); + +// Load the .env file if it exists +const dotenv = require("dotenv"); +dotenv.config(); + +const tablesUrl = process.env["TABLES_URL"] || ""; +const sasToken = process.env["SAS_TOKEN"] || ""; + +async function updateAndUpsertEntities() { + console.log("== Update and Upsert entities Sample =="); + + // Note that this sample assumes that a table with tableName exists + const tableName = `updateAndUpsertEntitiesTable`; + + // See authenticationMethods sample for other options of creating a new client + const client = new TableClient(`${tablesUrl}${sasToken}`, tableName); + + // Create the table + await client.createTable(); + + const entity = { + partitionKey: "Stationery", + rowKey: "A1", + name: "Marker Set", + price: 5.0, + brand: "myCompany" + }; + + // Entity doesn't exist in table, so calling upsertEntity will simply insert the entity. + await client.upsertEntity(entity, "Merge"); + + // Entity does exist in the table, so calling upsertEntity will update using the given UpdateMode. + // Because we are passing "Replace" as update mode, the existing entity will be replaced and delete the "brand" property. + await client.upsertEntity( + { + partitionKey: "Stationery", + rowKey: "A1", + name: "Marker Set", + price: 5.0, + // Replace with the same entity but without a brand + brand: undefined + }, + "Replace" + ); + + // Getting the entity we just created should give us an entity similar to the one that we first inserted + // but without a brand property + const noBrandEntity = await client.getEntity(entity.partitionKey, entity.rowKey); + + // Now we update the price setting, the default update mode is "Merge" which will only update the properties + // of the entity that are different to what is already stored, in this case we just need to update the price + // so we can just send an entity with the partition and row keys plus the new price + await client.updateEntity({ + partitionKey: noBrandEntity.partitionKey, + rowKey: noBrandEntity.rowKey, + price: 7.0 + }); + + // Getting the entity should gice us an entity like the original, but without a brand and with a price of 7 + const updatedEntity = await client.getEntity(entity.partitionKey, entity.rowKey); + console.log(`Original entity: ${JSON.stringify(entity)}`); + console.log(`Updated entity: ${JSON.stringify(updatedEntity)}`); + + // Delete the table for cleanup + await client.deleteTable(); +} + +async function main() { + await updateAndUpsertEntities(); +} + +main().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/javascript/usingContinuationToken.js b/sdk/tables/data-tables/samples/v13/javascript/usingContinuationToken.js new file mode 100644 index 000000000000..b2066f237a60 --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/javascript/usingContinuationToken.js @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * This sample demonstrates how to query entities in a table by page by manually handling the continuation token + * + * @summary queries entities in a table by page manually handling continuation tokens + */ + +const { TableClient, AzureSASCredential } = require("@azure/data-tables"); + +// Load the .env file if it exists +const dotenv = require("dotenv"); +dotenv.config(); + +const tablesUrl = process.env["TABLES_URL"] || ""; +const sasToken = process.env["SAS_TOKEN"] || ""; + +async function usingContinuationToken() { + const tableName = `manualListByPage`; + + // See authenticationMethods sample for other options of creating a new client + const client = new TableClient(tablesUrl, tableName, new AzureSASCredential(sasToken)); + // Create the table + await client.createTable(); + + let actions = []; + + // Create 100 entities + for (let i = 0; i < 100; i++) { + actions.push(["create", { partitionKey: `one`, rowKey: `${i}`, foo: i }]); + } + await client.submitTransaction(actions); + + // Limit the size to 2 entities by page + let iterator = client.listEntities().byPage({ maxPageSize: 2 }); + + // Iterating the pages to find the page that contains row key 50 + let interestingPage; + for await (const page of iterator) { + if (page.some((p) => p.rowKey === "50")) { + interestingPage = page.continuationToken; + } + } + + if (!interestingPage) { + console.error("Didn't find entity with rowKey = 50"); + return; + } + + // Fetch only the page that contains rowKey 50; + const page = await client + .listEntities() + .byPage({ maxPageSize: 2, continuationToken: interestingPage }) + .next(); + + if (!page.done) { + for (const entity of page.value) { + console.log(entity.rowKey); + } + } +} + +usingContinuationToken().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/javascript/workingWithBigInt.js b/sdk/tables/data-tables/samples/v13/javascript/workingWithBigInt.js new file mode 100644 index 000000000000..d22e1172cd29 --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/javascript/workingWithBigInt.js @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/** + * This sample demonstrates how to create and consume Int64 values using bigint + * + * @summary creates and works with an entity containing a bigint + */ + +const { TableClient, AzureNamedKeyCredential } = require("@azure/data-tables"); + +// Load the .env file if it exists +const dotenv = require("dotenv"); +dotenv.config(); + +const tablesUrl = process.env["TABLES_URL"] || ""; +const accountName = process.env["ACCOUNT_NAME"] || ""; +const accountKey = process.env["ACCOUNT_KEY"] || ""; + +async function workingWithBigint() { + console.log("Working with bigint sample"); + const client = new TableClient( + tablesUrl, + "testbigint", + new AzureNamedKeyCredential(accountName, accountKey) + ); + + await client.createTable(); + + await client.createEntity({ partitionKey: "p1", rowKey: "1", foo: BigInt("12345") }); + + const entity = await client.getEntity("p1", "1"); + + // Do arithmetic operations with bigint + const resultPlusOne = entity.foo + BigInt(1); + + console.log(resultPlusOne); + + await client.deleteTable(); +} + +async function main() { + await workingWithBigint(); +} + +main().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/javascript/workingWithInt64.js b/sdk/tables/data-tables/samples/v13/javascript/workingWithInt64.js new file mode 100644 index 000000000000..d2629f8d67a1 --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/javascript/workingWithInt64.js @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/** + * This sample demonstrates how to create and consume Int64 values + * + * @summary creates and works with an entity containing an Int64 value + */ + +const { TableClient, AzureNamedKeyCredential } = require("@azure/data-tables"); + +// Load the .env file if it exists +const dotenv = require("dotenv"); +dotenv.config(); + +const tablesUrl = process.env["TABLES_URL"] || ""; +const accountName = process.env["ACCOUNT_NAME"] || ""; +const accountKey = process.env["ACCOUNT_KEY"] || ""; + +async function workingWithInt64() { + console.log("working with Int64 sample"); + const client = new TableClient( + tablesUrl, + "testInt64", + new AzureNamedKeyCredential(accountName, accountKey) + ); + + await client.createTable(); + + await client.createEntity({ + partitionKey: "p1", + rowKey: "1", + // To work with Int64 we need to use an object that includes + // the value as a string and a notation of the type, in this case Int64 + foo: { value: "12345", type: "Int64" } + }); + + const entity = await client.getEntity("p1", "1", { disableTypeConversion: true }); + + // In order to do arithmetic operations with Int64 you need to use + // bigint or a third party library such as 'long' + console.log(entity); + + await client.deleteTable(); +} + +async function main() { + await workingWithInt64(); +} + +main().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/typescript/README.md b/sdk/tables/data-tables/samples/v13/typescript/README.md new file mode 100644 index 000000000000..030811f2b90e --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/typescript/README.md @@ -0,0 +1,98 @@ +--- +page_type: sample +languages: + - typescript +products: + - azure + - azure-table-storage +urlFragment: data-tables-typescript +--- + +# Azure Data Tables client library samples for TypeScript + +These sample programs show how to use the TypeScript client libraries for Azure Data Tables in some common scenarios. + +| **File Name** | **Description** | +| ----------------------------------------------------- | ------------------------------------------------------------------------- | +| [workingWithBigInt.ts][workingwithbigint] | creates and works with an entity containing a bigint | +| [workingWithInt64.ts][workingwithint64] | creates and works with an entity containing an Int64 value | +| [transactionWithHelper.ts][transactionwithhelper] | sends transactional request using TableTransaction helper | +| [transactionOperations.ts][transactionoperations] | sends transactional batch requests | +| [usingContinuationToken.ts][usingcontinuationtoken] | queries entities in a table by page manually handling continuation tokens | +| [authenticationMethods.ts][authenticationmethods] | authenticates using different authentication methods | +| [createAndDeleteEntities.ts][createanddeleteentities] | creates and deletes a entities in a table | +| [createAndDeleteTable.ts][createanddeletetable] | creates and deletes a table | +| [generateTableSAS.ts][generatetablesas] | generate a Table Account SAS token | +| [queryEntities.ts][queryentities] | queries entities in a table | +| [queryTables.ts][querytables] | queries tables | +| [updateAndUpsertEntities.ts][updateandupsertentities] | updates and upserts entities in a table | + +## Prerequisites + +The sample programs are compatible with [LTS versions of Node.js](https://nodejs.org/about/releases/). + +Before running the samples in Node, they must be compiled to JavaScript using the TypeScript compiler. For more information on TypeScript, see the [TypeScript documentation][typescript]. Install the TypeScript compiler using: + +```bash +npm install -g typescript +``` + +You need [an Azure subscription][freesub] and the following Azure resources to run these sample programs: + +- [Azure Storage instance][createinstance_azurestorageinstance] + +Samples retrieve credentials to access the service endpoint from environment variables. Alternatively, edit the source code to include the appropriate credentials. See each individual sample for details on which environment variables/credentials it requires to function. + +Adapting the samples to run in the browser may require some additional consideration. For details, please see the [package README][package]. + +## Setup + +To run the samples using the published version of the package: + +1. Install the dependencies using `npm`: + +```bash +npm install +``` + +2. Compile the samples: + +```bash +npm run build +``` + +3. Edit the file `sample.env`, adding the correct credentials to access the Azure service and run the samples. Then rename the file from `sample.env` to just `.env`. The sample programs will read this file automatically. + +4. Run whichever samples you like (note that some samples may require additional setup, see the table above): + +```bash +node dist/workingWithBigInt.js +``` + +Alternatively, run a single sample with the correct environment variables set (setting up the `.env` file is not required if you do this), for example (cross-platform): + +```bash +npx cross-env TABLES_URL="" ACCOUNT_NAME="" ACCOUNT_KEY="" node dist/workingWithBigInt.js +``` + +## Next Steps + +Take a look at our [API Documentation][apiref] for more information about the APIs that are available in the clients. + +[workingwithbigint]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/typescript/src/workingWithBigInt.ts +[workingwithint64]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/typescript/src/workingWithInt64.ts +[transactionwithhelper]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/typescript/src/transactionWithHelper.ts +[transactionoperations]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/typescript/src/transactionOperations.ts +[usingcontinuationtoken]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/typescript/src/usingContinuationToken.ts +[authenticationmethods]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/typescript/src/authenticationMethods.ts +[createanddeleteentities]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/typescript/src/createAndDeleteEntities.ts +[createanddeletetable]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/typescript/src/createAndDeleteTable.ts +[generatetablesas]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/typescript/src/generateTableSAS.ts +[queryentities]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/typescript/src/queryEntities.ts +[querytables]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/typescript/src/queryTables.ts +[updateandupsertentities]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/tables/data-tables/samples/v13/typescript/src/updateAndUpsertEntities.ts +[apiref]: https://docs.microsoft.com/javascript/api/@azure/data-tables +[freesub]: https://azure.microsoft.com/free/ +[createinstance_azurestorageinstance]: https://docs.microsoft.com/azure/storage/tables/table-storage-quickstart-portal +[package]: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/tables/data-tables/README.md +[typescript]: https://www.typescriptlang.org/docs/home.html diff --git a/sdk/tables/data-tables/samples/v13/typescript/package.json b/sdk/tables/data-tables/samples/v13/typescript/package.json new file mode 100644 index 000000000000..e4b500d5997c --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/typescript/package.json @@ -0,0 +1,40 @@ +{ + "name": "azure-data-tables-samples-ts", + "private": true, + "version": "1.0.0", + "description": "Azure Data Tables client library samples for TypeScript", + "engines": { + "node": ">=12.0.0" + }, + "scripts": { + "build": "tsc", + "prebuild": "rimraf dist/" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Azure/azure-sdk-for-js.git", + "directory": "sdk/tables/data-tables" + }, + "keywords": [ + "azure", + "cloud" + ], + "author": "Microsoft Corporation", + "license": "MIT", + "bugs": { + "url": "https://github.com/Azure/azure-sdk-for-js/issues" + }, + "homepage": "https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/tables/data-tables", + "dependencies": { + "@azure/data-tables": "latest", + "dotenv": "latest", + "@azure/identity": "^2.0.1", + "uuid": "^8.3.0", + "@azure/core-auth": "^1.3.0" + }, + "devDependencies": { + "@types/uuid": "^8.0.0", + "typescript": "~4.4.0", + "rimraf": "latest" + } +} diff --git a/sdk/tables/data-tables/samples/v13/typescript/sample.env b/sdk/tables/data-tables/samples/v13/typescript/sample.env new file mode 100644 index 000000000000..a53dc827f4af --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/typescript/sample.env @@ -0,0 +1,8 @@ +ACCOUNT_CONNECTION_STRING= +SAS_CONNECTION_STRING= +ACCOUNT_NAME= +ACCOUNT_KEY= +ACCOUNT_URL= +ACCOUNT_SAS= +TABLES_URL= +SAS_TOKEN= diff --git a/sdk/tables/data-tables/samples/v13/typescript/src/authenticationMethods.ts b/sdk/tables/data-tables/samples/v13/typescript/src/authenticationMethods.ts new file mode 100644 index 000000000000..50d310074400 --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/typescript/src/authenticationMethods.ts @@ -0,0 +1,111 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/** + * This sample demonstrates how to use the different methods of authentication + * to make calls to the Azure Tables Service + * + * @summary authenticates using different authentication methods + */ +import { + TableServiceClient, + AzureNamedKeyCredential, + AzureSASCredential +} from "@azure/data-tables"; + +import { DefaultAzureCredential } from "@azure/identity"; + +// Load the .env file if it exists +import * as dotenv from "dotenv"; +dotenv.config(); + +// URL of the tables endpoint +const tablesUrl = process.env["TABLES_URL"] || ""; + +// You can find your storage account's name, connection strings and keys in the Azure portal. +// Navigate to Settings > Access keys in your storage account's menu blade to see connection strings for both primary and secondary access keys +const accountConnectionString = process.env["ACCOUNT_CONNECTION_STRING"] || ""; +const accountName = process.env["ACCOUNT_NAME"] || ""; +const accountKey = process.env["ACCOUNT_KEY"] || ""; + +// You can generate a SAS connection string and token for your storage account in the Azure Portal +// Navigate to Settings > "Shared access signature" in your storage account's menu blade select the Allowed services, resource types, permissions and expiry options +// and generate your SAS and connection string. +const sasConnectionString = process.env["SAS_CONNECTION_STRING"] || ""; +const sasToken = process.env["SAS_TOKEN"] || ""; + +/** + * Create a TableServiceCLient using a SAS connection String + */ +async function tableServiceClientWithSasConnectionString() { + const client = TableServiceClient.fromConnectionString(sasConnectionString); + countTablesWithClient(client); +} + +/** + * Create a TableServiceCLient using a SAS connection String + */ +async function tableServiceClientWithAAD() { + // DefaultAzureCredential expects the following three environment variables: + // - AZURE_TENANT_ID: The tenant ID in Azure Active Directory + // - AZURE_CLIENT_ID: The application (client) ID registered in the AAD tenant + // - AZURE_CLIENT_SECRET: The client secret for the registered application + const credential = new DefaultAzureCredential(); + const client = new TableServiceClient(tablesUrl, credential); + countTablesWithClient(client); +} + +/** + * Create a TableServiceCLient using a SAS token + */ +async function tableServiceClientWithSasToken() { + const client = new TableServiceClient(tablesUrl, new AzureSASCredential(sasToken)); + countTablesWithClient(client); +} + +/** + * Create a TableServiceCLient using an Account connection String. + * Note that this authentication method is only supported in Node, + * and it is not available for browsers + */ +async function tableServiceClientWithAccountConnectionString() { + const client = TableServiceClient.fromConnectionString(accountConnectionString); + countTablesWithClient(client); +} + +/** + * Create a TableServiceCLient using account name and account key + * Note that this authentication method is only supported in Node, + * and it is not available for browsers + */ +async function tableServiceClientWithAccountKey() { + const creds = new AzureNamedKeyCredential(accountName, accountKey); + const client = new TableServiceClient(tablesUrl, creds); + countTablesWithClient(client); +} + +async function countTablesWithClient(client: TableServiceClient) { + const tablesIterator = client.listTables(); + let count = 0; + for await (const _table of tablesIterator) { + count++; + } + + console.log(`Listed ${count} tables`); +} + +export async function main() { + console.log("== Client Authentication Methods Sample =="); + + await tableServiceClientWithSasConnectionString(); + await tableServiceClientWithSasToken(); + + await tableServiceClientWithAccountConnectionString(); + await tableServiceClientWithAccountKey(); + + await tableServiceClientWithAAD(); +} + +main().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/typescript/src/createAndDeleteEntities.ts b/sdk/tables/data-tables/samples/v13/typescript/src/createAndDeleteEntities.ts new file mode 100644 index 000000000000..ac3eafb6bed0 --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/typescript/src/createAndDeleteEntities.ts @@ -0,0 +1,113 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/** + * This sample demonstrates create and delete entities in a table + * + * @summary creates and deletes a entities in a table + */ + +import { Edm, TableClient, AzureNamedKeyCredential } from "@azure/data-tables"; + +// Load the .env file if it exists +import * as dotenv from "dotenv"; +dotenv.config(); + +const tablesUrl = process.env["TABLES_URL"] || ""; +const accountName = process.env["ACCOUNT_NAME"] || ""; +const accountKey = process.env["ACCOUNT_KEY"] || ""; + +async function createSimpleDateEntity() { + // Note that this sample assumes that a table with tableName exists + const tableName = `createSimpleDateEntityTable`; + + // See authenticationMethods sample for other options of creating a new client + const creds = new AzureNamedKeyCredential(accountName, accountKey); + const client = new TableClient(tablesUrl, tableName, creds); + + await client.createTable(); + + const entity = { + partitionKey: "p1", + rowKey: "r1", + date: new Date() + }; + + await client.createEntity(entity); + + await client.deleteTable(); +} + +async function createComplexDateEntity() { + // Note that this sample assumes that a table with tableName exists + const tableName = `createComplexDateEntityTable`; + + // See authenticationMethods sample for other options of creating a new client + const creds = new AzureNamedKeyCredential(accountName, accountKey); + const client = new TableClient(tablesUrl, tableName, creds); + + await client.createTable(); + + // For higher precision dates we need to pass the + const date: Edm<"DateTime"> = { type: "DateTime", value: "2016-06-10T21:42:24.7607389" }; + + const entity = { + partitionKey: "p2", + rowKey: "r2", + date + }; + + await client.createEntity(entity); + + await client.deleteTable(); +} + +async function createAndDeleteEntities() { + console.log("== Create and delete entities Sample =="); + + // Note that this sample assumes that a table with tableName exists + const tableName = `createAndDeleteEntitiesTable`; + + // See authenticationMethods sample for other options of creating a new client + const creds = new AzureNamedKeyCredential(accountName, accountKey); + const client = new TableClient(tablesUrl, tableName, creds); + + // Create the table + await client.createTable(); + + const entity: Entity = { + partitionKey: "Stationery", + rowKey: "A1", + name: "Marker Set", + price: 5.0, + quantity: 21 + }; + + // Create the new entity + await client.createEntity(entity); + + // Delete the entity + await client.deleteEntity(entity.partitionKey, entity.rowKey); + + // Delete the table for cleanup + // Create the table + await client.deleteTable(); +} + +interface Entity { + partitionKey: string; + rowKey: string; + name: string; + price: number; + quantity: number; +} + +export async function main() { + await createAndDeleteEntities(); + await createSimpleDateEntity(); + await createComplexDateEntity(); +} + +main().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/typescript/src/createAndDeleteTable.ts b/sdk/tables/data-tables/samples/v13/typescript/src/createAndDeleteTable.ts new file mode 100644 index 000000000000..03af158f1415 --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/typescript/src/createAndDeleteTable.ts @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * This sample demonstrates create and delete a table + * + * @summary creates and deletes a table + */ + +import { TableServiceClient, TableClient } from "@azure/data-tables"; +import { v4 } from "uuid"; + +// Load the .env file if it exists +import * as dotenv from "dotenv"; +dotenv.config(); + +const sasConnectionString = process.env["SAS_CONNECTION_STRING"] || ""; +const tableSufix = v4().replace(/-/g, ""); + +async function createAndDeleteTable() { + console.log("== Delete and create table Sample =="); + + // See authenticationMethods sample for other options of creating a new client + const serviceClient = TableServiceClient.fromConnectionString(sasConnectionString); + + // Create a new table + const tableName = `SampleCreateAndDeleteTable${tableSufix}`; + await serviceClient.createTable(tableName); + + // Deletes the table + await serviceClient.deleteTable(tableName); +} + +async function createAndDeleteTableWithTableClient() { + // A table can also be created and deleted using a TableClient + console.log("== Delete and create table with TableClient Sample =="); + + const tableName = "SampleCreateAndDeleteTable2"; + + // Creating a new table client doesn't do a network call + const client = TableClient.fromConnectionString(sasConnectionString, tableName); + + // Will attempt to create a table with the tableName specified above + await client.createTable(); + + // Will attempt to delete the table with the tableName specified above + await client.deleteTable(); +} + +export async function main() { + await createAndDeleteTable(); + await createAndDeleteTableWithTableClient(); +} + +main().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/typescript/src/generateTableSAS.ts b/sdk/tables/data-tables/samples/v13/typescript/src/generateTableSAS.ts new file mode 100644 index 000000000000..663c8e100079 --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/typescript/src/generateTableSAS.ts @@ -0,0 +1,113 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * This sample demonstrates how to create an Account SAS token. An account SAS token + * provides access to the whole Tables Service account, given the permissions selected, + * by default the only permission granted is list + * + * @summary generate a Table Account SAS token + */ + +import { + generateAccountSas, + generateTableSas, + TableClient, + TableServiceClient, + AccountSasPermissions, + TableSasPermissions +} from "@azure/data-tables"; +import { AzureNamedKeyCredential, AzureSASCredential } from "@azure/core-auth"; + +// Load the .env file if it exists +import * as dotenv from "dotenv"; +dotenv.config(); + +const tablesUrl = process.env["TABLES_URL"] || ""; +const accountKey = process.env["ACCOUNT_KEY"] || ""; +const accountName = process.env["ACCOUNT_NAME"] || ""; + +async function generateTableSasSample() { + console.log("== Generate Table Account SAS Sample =="); + + // We need a NamedKeyCredential to generate the SAS token + const cred = new AzureNamedKeyCredential(accountName, accountKey); + + // We can optionally set the permissions we want on the SAS token + // If non is specified, only list is granted + const permissions: AccountSasPermissions = { + // Grants permission to list tables + list: true, + // Grants permission to create tables + write: true, + // Grants permission to create entities + add: true, + // Grants permission to query entities + query: true, + // Grants permission to delete tables and entities + delete: true + }; + + // Generate an account SAS with the NamedKeyCredential and the permissions set previously + const accountSas = generateAccountSas(cred, { + permissions, + expiresOn: new Date("2021-12-12") + }); + + const tableService = new TableServiceClient(tablesUrl, new AzureSASCredential(accountSas)); + + // Create a new table + const tableName = "fooTable"; + await tableService.createTable(tableName); + + // List all the tables in the service account + const tables = tableService.listTables(); + for await (const table of tables) { + console.log(table); + } + + // We are going to create a new SAS token scoped down to the specific table we just created. + // If no permissions are provided, by default the token would have only query permission + const tablePermissions: TableSasPermissions = { + // Allows adding entities + add: true, + // Allows querying entities + query: true, + // Allows deleting entities + delete: true, + // Allows updating entities + update: true + }; + + // Create the table SAS token + const tableSas = generateTableSas(tableName, cred, { + expiresOn: new Date("2021-12-12"), + permissions: tablePermissions + }); + + // Create a new client for the table we just created. Alternatively the Table Account SAS token could be used here as well + // however using Table level SAS tokens offers a more granular access control + const table = new TableClient(tablesUrl, tableName, new AzureSASCredential(tableSas)); + + // Create an entity in the table + await table.createEntity({ partitionKey: "test", rowKey: "1", foo: "bar" }); + + // List all the entities in the table + const entities = table.listEntities(); + for await (const entity of entities) { + console.log(entity); + } + + // Delete the entity we just created + await table.deleteEntity("test", "1"); + + // Delete the Table + await tableService.deleteTable(tableName); +} + +export async function main() { + await generateTableSasSample(); +} + +main().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/typescript/src/queryEntities.ts b/sdk/tables/data-tables/samples/v13/typescript/src/queryEntities.ts new file mode 100644 index 000000000000..468dd3705433 --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/typescript/src/queryEntities.ts @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * This sample demonstrates how to query entities in a table + * + * @summary queries entities in a table + */ + +import { odata, TableClient } from "@azure/data-tables"; + +// Load the .env file if it exists +import * as dotenv from "dotenv"; +dotenv.config(); + +const tablesUrl = process.env["TABLES_URL"] || ""; +const sasToken = process.env["SAS_TOKEN"] || ""; + +async function listEntities() { + console.log("== List entities Sample =="); + + // Note that this sample assumes that a table with tableName exists + const tableName = `queryEntitiesTable`; + console.log(tableName); + + // See authenticationMethods sample for other options of creating a new client + const client = new TableClient(`${tablesUrl}${sasToken}`, tableName); + // Create the table + await client.createTable(); + + const partitionKey = "Stationery"; + const marker: Entity = { + partitionKey, + rowKey: "1", + name: "Markers", + price: 5.0, + quantity: 34 + }; + + const planner: Entity = { + partitionKey, + rowKey: "2", + name: "Planner", + price: 7.0, + quantity: 34 + }; + + // create entities for marker and planner + await client.createEntity(marker); + await client.createEntity(planner); + + // List all entities with PartitionKey "Stationery" + const listResults = client.listEntities({ + queryOptions: { filter: odata`PartitionKey eq ${partitionKey}` } + }); + + for await (const product of listResults) { + console.log(`${product.name}: ${product.price}`); + } + + // List all entities with a price less than 6.0 + const priceListResults = client.listEntities({ + queryOptions: { filter: odata`price le 6` } + }); + + console.log("-- Products with a price less or equals to 6.00"); + for await (const product of priceListResults) { + console.log(`${product.name}: ${product.price}`); + } +} + +// Sample of how to retreive the top N entities for a query +async function listTopNEntities() { + // This is the max number of items + const topN = 1; + const partitionKey = "Stationery"; + + // Note that this sample assumes that a table with tableName exists + const tableName = `queryEntitiesTable`; + + // See authenticationMethods sample for other options of creating a new client + const client = new TableClient(`${tablesUrl}${sasToken}`, tableName); + + // List all entities with PartitionKey "Stationery" + const listResults = client.listEntities({ + queryOptions: { + filter: odata`PartitionKey eq ${partitionKey}` + } + }); + + let topEntities = []; + const iterator = listResults.byPage({ maxPageSize: topN }); + + for await (const page of iterator) { + // Take the first page as the topEntires result + topEntities = page; + // We break to only get the first page + // this only sends a single request to the service + break; + } + + console.log(`Top entities: ${topEntities.length}`); + // Top entities: 1 + + // Delete the table to cleanup + await client.deleteTable(); +} + +interface Entity { + partitionKey: string; + rowKey: string; + name: string; + price: number; + quantity: number; +} + +export async function main() { + await listEntities(); + await listTopNEntities(); +} + +main().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/typescript/src/queryTables.ts b/sdk/tables/data-tables/samples/v13/typescript/src/queryTables.ts new file mode 100644 index 000000000000..b5940f3ee1d3 --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/typescript/src/queryTables.ts @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * This sample demonstrates how to query tables + * + * @summary queries tables + */ + +import { odata, TableServiceClient } from "@azure/data-tables"; + +// Load the .env file if it exists +import * as dotenv from "dotenv"; +dotenv.config(); + +const accountConnectionString = process.env["ACCOUNT_CONNECTION_STRING"] || ""; + +async function queryTables() { + console.log("== Query tables Sample =="); + + // See authenticationMethods sample for other options of creating a new client + const serviceClient = TableServiceClient.fromConnectionString(accountConnectionString); + + // Create a new table + const tableName = `queryTables`; + await serviceClient.createTable(tableName); + + // list the tables with a filter query, queryOptions is optional. + // odata is a helper function that takes care of encoding the query + // filter, in this sample it will add quotes around tableName + const queryTableResults = serviceClient.listTables({ + queryOptions: { filter: odata`TableName eq ${tableName}` } + }); + + // Iterate the results + for await (const table of queryTableResults) { + console.log(table.name); + } + + // Deletes the table + await serviceClient.deleteTable(tableName); +} + +export async function main() { + await queryTables(); +} + +main().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/typescript/src/transactionOperations.ts b/sdk/tables/data-tables/samples/v13/typescript/src/transactionOperations.ts new file mode 100644 index 000000000000..1f9b867be6ae --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/typescript/src/transactionOperations.ts @@ -0,0 +1,118 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * This sample demonstrates how to send a transactional request + * with multiple operations in a single request + * + * @summary sends transactional batch requests + */ + +import { TableClient, TransactionAction } from "@azure/data-tables"; + +// Load the .env file if it exists +import * as dotenv from "dotenv"; +dotenv.config(); + +const connectionString = process.env["ACCOUNT_CONNECTION_STRING"] || ""; + +async function batchOperations() { + console.log("== Batch Operations Sample =="); + const tableName = `transactionsSample`; + + // See authenticationMethods sample for other options of creating a new client + const client = TableClient.fromConnectionString(connectionString, tableName); + + // Create the table + await client.createTable(); + + const partitionKey = "Stationery"; + + const actions: TransactionAction[] = [ + [ + "create", + { + partitionKey, + rowKey: "A1", + name: "Marker Set", + price: 5.0, + quantity: 21 + } + ], + [ + "create", + { + partitionKey, + rowKey: "A2", + name: "Pen Set", + price: 2.0, + quantity: 6 + } + ], + [ + "create", + { + partitionKey, + rowKey: "A3", + name: "Pencil", + price: 1.5, + quantity: 100 + } + ] + ]; + + // Submit the transaction with the list of actions. + // Note that all the operations within a transaction must target the same partition key + const transactionResult = await client.submitTransaction(actions); + + console.log(transactionResult.subResponses); + // Output: + // [ + // { + // status: 204, + // rowKey: 'A1', + // etag: `W/"datetime'2020-10-02T03%3A31%3A09.9324186Z'"` + // }, + // { + // status: 204, + // rowKey: 'A2', + // etag: `W/"datetime'2020-10-02T03%3A31%3A09.9324186Z'"` + // }, + // { + // status: 204, + // rowKey: 'A3', + // etag: `W/"datetime'2020-10-02T03%3A31%3A09.9324186Z'"` + // } + // ] + + // We can also send transactions with update operations + const updateTransaction: TransactionAction[] = [ + // The default update mode is "Merge" which only replaces the properties in the entity we send + // all other properties are kept as they are stored + ["update", { partitionKey, rowKey: "A1", name: "[Updated - Merge] Marker Set" }], + // If we set the update mode to "Replace", the original entity will be replaced with exactly what we send. + // We need to be careful when using replace, because if we forget to pass a property it will get deleted. + [ + "update", + { partitionKey, rowKey: "A2", name: "[Updated - Replace] Pen Set", price: 99, quantity: 33 }, + "Replace" + ] + ]; + + const updateResult = await client.submitTransaction(updateTransaction); + + console.log(updateResult); + + // Now we'll query our entities + const entities = client.listEntities(); + + for await (const entity of entities) { + console.log(entity); + } + + // Delete the table to clean up + await client.deleteTable(); +} + +batchOperations().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/typescript/src/transactionWithHelper.ts b/sdk/tables/data-tables/samples/v13/typescript/src/transactionWithHelper.ts new file mode 100644 index 000000000000..38c7159eb3e3 --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/typescript/src/transactionWithHelper.ts @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * This sample demonstrates how to use the TableTransaction helper + * to build a transaction request. + * + * @summary sends transactional request using TableTransaction helper + */ + +import { TableClient, TableTransaction } from "@azure/data-tables"; + +// Load the .env file if it exists +import * as dotenv from "dotenv"; +dotenv.config(); + +const connectionString = process.env["ACCOUNT_CONNECTION_STRING"] || ""; +async function batchOperations() { + console.log("== TableTransaction Sample =="); + + // Note that this sample assumes that a table with tableName exists + const tableName = `transactionHelper`; + + // See authenticationMethods sample for other options of creating a new client + const client = TableClient.fromConnectionString(connectionString, tableName); + + // Create the table + await client.createTable(); + + const partitionKey = "Stationery"; + + const transaction = new TableTransaction(); + + // Add actions to the transaction + transaction.createEntity({ + partitionKey, + rowKey: "A1", + name: "Marker Set", + price: 5.0, + quantity: 21 + }); + transaction.createEntity({ + partitionKey, + rowKey: "A2", + name: "Pen Set", + price: 2.0, + quantity: 6 + }); + transaction.createEntity({ + partitionKey, + rowKey: "A3", + name: "Pencil", + price: 1.5, + quantity: 100 + }); + + // Submit the transaction using the actions list built by the helper + const transactionResult = await client.submitTransaction(transaction.actions); + + console.log(transactionResult.subResponses); + // Output: + // [ + // { + // status: 204, + // rowKey: 'A1', + // etag: `W/"datetime'2020-10-02T03%3A31%3A09.9324186Z'"` + // }, + // { + // status: 204, + // rowKey: 'A2', + // etag: `W/"datetime'2020-10-02T03%3A31%3A09.9324186Z'"` + // }, + // { + // status: 204, + // rowKey: 'A3', + // etag: `W/"datetime'2020-10-02T03%3A31%3A09.9324186Z'"` + // } + // ] + + // Delete the table to clean up + await client.deleteTable(); +} + +batchOperations().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/typescript/src/updateAndUpsertEntities.ts b/sdk/tables/data-tables/samples/v13/typescript/src/updateAndUpsertEntities.ts new file mode 100644 index 000000000000..1f786b4d2c11 --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/typescript/src/updateAndUpsertEntities.ts @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * This sample demonstrates how to perform entity update and upsert operations in a table + * + * @summary updates and upserts entities in a table + */ + +import { TableClient } from "@azure/data-tables"; + +// Load the .env file if it exists +import * as dotenv from "dotenv"; +dotenv.config(); + +const tablesUrl = process.env["TABLES_URL"] || ""; +const sasToken = process.env["SAS_TOKEN"] || ""; + +async function updateAndUpsertEntities() { + console.log("== Update and Upsert entities Sample =="); + + // Note that this sample assumes that a table with tableName exists + const tableName = `updateAndUpsertEntitiesTable`; + + // See authenticationMethods sample for other options of creating a new client + const client = new TableClient(`${tablesUrl}${sasToken}`, tableName); + + // Create the table + await client.createTable(); + + const entity: Entity = { + partitionKey: "Stationery", + rowKey: "A1", + name: "Marker Set", + price: 5.0, + brand: "myCompany" + }; + + // Entity doesn't exist in table, so calling upsertEntity will simply insert the entity. + await client.upsertEntity(entity, "Merge"); + + // Entity does exist in the table, so calling upsertEntity will update using the given UpdateMode. + // Because we are passing "Replace" as update mode, the existing entity will be replaced and delete the "brand" property. + await client.upsertEntity( + { + partitionKey: "Stationery", + rowKey: "A1", + name: "Marker Set", + price: 5.0, + // Replace with the same entity but without a brand + brand: undefined + }, + "Replace" + ); + + // Getting the entity we just created should give us an entity similar to the one that we first inserted + // but without a brand property + const noBrandEntity = await client.getEntity(entity.partitionKey, entity.rowKey); + + // Now we update the price setting, the default update mode is "Merge" which will only update the properties + // of the entity that are different to what is already stored, in this case we just need to update the price + // so we can just send an entity with the partition and row keys plus the new price + await client.updateEntity({ + partitionKey: noBrandEntity.partitionKey, + rowKey: noBrandEntity.rowKey, + price: 7.0 + }); + + // Getting the entity should gice us an entity like the original, but without a brand and with a price of 7 + const updatedEntity = await client.getEntity(entity.partitionKey, entity.rowKey); + console.log(`Original entity: ${JSON.stringify(entity)}`); + console.log(`Updated entity: ${JSON.stringify(updatedEntity)}`); + + // Delete the table for cleanup + await client.deleteTable(); +} + +interface Entity { + partitionKey: string; + rowKey: string; + name: string; + price: number; + brand?: string; +} + +export async function main() { + await updateAndUpsertEntities(); +} + +main().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/typescript/src/usingContinuationToken.ts b/sdk/tables/data-tables/samples/v13/typescript/src/usingContinuationToken.ts new file mode 100644 index 000000000000..c02fecdb7400 --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/typescript/src/usingContinuationToken.ts @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * This sample demonstrates how to query entities in a table by page by manually handling the continuation token + * + * @summary queries entities in a table by page manually handling continuation tokens + */ + +import { TableClient, AzureSASCredential, TransactionAction } from "@azure/data-tables"; + +// Load the .env file if it exists +import * as dotenv from "dotenv"; +dotenv.config(); + +const tablesUrl = process.env["TABLES_URL"] || ""; +const sasToken = process.env["SAS_TOKEN"] || ""; + +async function usingContinuationToken() { + const tableName = `manualListByPage`; + + // See authenticationMethods sample for other options of creating a new client + const client = new TableClient(tablesUrl, tableName, new AzureSASCredential(sasToken)); + // Create the table + await client.createTable(); + + let actions: TransactionAction[] = []; + + // Create 100 entities + for (let i = 0; i < 100; i++) { + actions.push(["create", { partitionKey: `one`, rowKey: `${i}`, foo: i }]); + } + await client.submitTransaction(actions); + + // Limit the size to 2 entities by page + let iterator = client.listEntities().byPage({ maxPageSize: 2 }); + + // Iterating the pages to find the page that contains row key 50 + let interestingPage: string | undefined; + for await (const page of iterator) { + if (page.some((p) => p.rowKey === "50")) { + interestingPage = page.continuationToken; + } + } + + if (!interestingPage) { + console.error("Didn't find entity with rowKey = 50"); + return; + } + + // Fetch only the page that contains rowKey 50; + const page = await client + .listEntities() + .byPage({ maxPageSize: 2, continuationToken: interestingPage }) + .next(); + + if (!page.done) { + for (const entity of page.value) { + console.log(entity.rowKey); + } + } +} + +usingContinuationToken().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/typescript/src/workingWithBigInt.ts b/sdk/tables/data-tables/samples/v13/typescript/src/workingWithBigInt.ts new file mode 100644 index 000000000000..3dd316068d3a --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/typescript/src/workingWithBigInt.ts @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/** + * This sample demonstrates how to create and consume Int64 values using bigint + * + * @summary creates and works with an entity containing a bigint + */ + +import { TableClient, AzureNamedKeyCredential } from "@azure/data-tables"; + +// Load the .env file if it exists +import * as dotenv from "dotenv"; +dotenv.config(); + +const tablesUrl = process.env["TABLES_URL"] || ""; +const accountName = process.env["ACCOUNT_NAME"] || ""; +const accountKey = process.env["ACCOUNT_KEY"] || ""; + +async function workingWithBigint() { + console.log("Working with bigint sample"); + const client = new TableClient( + tablesUrl, + "testbigint", + new AzureNamedKeyCredential(accountName, accountKey) + ); + + await client.createTable(); + + type FooEntity = { + foo: bigint; + }; + + await client.createEntity({ partitionKey: "p1", rowKey: "1", foo: BigInt("12345") }); + + const entity = await client.getEntity("p1", "1"); + + // Do arithmetic operations with bigint + const resultPlusOne = entity.foo + BigInt(1); + + console.log(resultPlusOne); + + await client.deleteTable(); +} + +export async function main() { + await workingWithBigint(); +} + +main().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/typescript/src/workingWithInt64.ts b/sdk/tables/data-tables/samples/v13/typescript/src/workingWithInt64.ts new file mode 100644 index 000000000000..7c9c15e1a0ba --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/typescript/src/workingWithInt64.ts @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/** + * This sample demonstrates how to create and consume Int64 values + * + * @summary creates and works with an entity containing an Int64 value + */ + +import { Edm, TableClient, AzureNamedKeyCredential } from "@azure/data-tables"; + +// Load the .env file if it exists +import * as dotenv from "dotenv"; +dotenv.config(); + +const tablesUrl = process.env["TABLES_URL"] || ""; +const accountName = process.env["ACCOUNT_NAME"] || ""; +const accountKey = process.env["ACCOUNT_KEY"] || ""; + +async function workingWithInt64() { + console.log("working with Int64 sample"); + const client = new TableClient( + tablesUrl, + "testInt64", + new AzureNamedKeyCredential(accountName, accountKey) + ); + + await client.createTable(); + + type FooEntity = { + foo: Edm<"Int64">; + }; + + await client.createEntity({ + partitionKey: "p1", + rowKey: "1", + // To work with Int64 we need to use an object that includes + // the value as a string and a notation of the type, in this case Int64 + foo: { value: "12345", type: "Int64" } + }); + + const entity = await client.getEntity("p1", "1", { disableTypeConversion: true }); + + // In order to do arithmetic operations with Int64 you need to use + // bigint or a third party library such as 'long' + console.log(entity); + + await client.deleteTable(); +} + +export async function main() { + await workingWithInt64(); +} + +main().catch((err) => { + console.error("The sample encountered an error:", err); +}); diff --git a/sdk/tables/data-tables/samples/v13/typescript/tsconfig.json b/sdk/tables/data-tables/samples/v13/typescript/tsconfig.json new file mode 100644 index 000000000000..416c2dd82e00 --- /dev/null +++ b/sdk/tables/data-tables/samples/v13/typescript/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2018", + "module": "commonjs", + "moduleResolution": "node", + "resolveJsonModule": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "alwaysStrict": true, + "outDir": "dist", + "rootDir": "src" + }, + "include": [ + "src/**.ts" + ] +} diff --git a/sdk/tables/data-tables/src/generated/generatedClientContext.ts b/sdk/tables/data-tables/src/generated/generatedClientContext.ts index b264fe13158f..afe772d26f07 100644 --- a/sdk/tables/data-tables/src/generated/generatedClientContext.ts +++ b/sdk/tables/data-tables/src/generated/generatedClientContext.ts @@ -32,7 +32,7 @@ export class GeneratedClientContext extends coreClient.ServiceClient { requestContentType: "application/json; charset=utf-8" }; - const packageDetails = `azsdk-js-data-tables/13.0.0`; + const packageDetails = `azsdk-js-data-tables/13.0.1`; const userAgentPrefix = options.userAgentOptions && options.userAgentOptions.userAgentPrefix ? `${options.userAgentOptions.userAgentPrefix} ${packageDetails}` diff --git a/sdk/tables/data-tables/swagger/README.md b/sdk/tables/data-tables/swagger/README.md index a5e70c885a87..789b48772f33 100644 --- a/sdk/tables/data-tables/swagger/README.md +++ b/sdk/tables/data-tables/swagger/README.md @@ -6,7 +6,7 @@ ```yaml v3: true -package-version: 13.0.0 +package-version: 13.0.1 package-name: "@azure/data-tables" title: TablesClient description: Tables Client