diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5bb0edd --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +# macOS +.DS_Store + +# JetBrains +.idea/ diff --git a/dotnet/.gitignore b/dotnet/.gitignore new file mode 100644 index 0000000..47a94ef --- /dev/null +++ b/dotnet/.gitignore @@ -0,0 +1,428 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates +*.env + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ + +[Dd]ebug/x64/ +[Dd]ebugPublic/x64/ +[Rr]elease/x64/ +[Rr]eleases/x64/ +bin/x64/ +obj/x64/ + +[Dd]ebug/x86/ +[Dd]ebugPublic/x86/ +[Rr]elease/x86/ +[Rr]eleases/x86/ +bin/x86/ +obj/x86/ + +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +[Aa][Rr][Mm]64[Ee][Cc]/ +bld/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Build results on 'Bin' directories +**/[Bb]in/* +# Uncomment if you have tasks that rely on *.refresh files to move binaries +# (https://github.com/github/gitignore/pull/3736) +#!**/[Bb]in/*.refresh + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* +*.trx + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Approval Tests result files +*.received.* + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.idb +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +# but not Directory.Build.rsp, as it configures directory-level build defaults +!Directory.Build.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +**/.paket/paket.exe +paket-files/ + +# FAKE - F# Make +**/.fake/ + +# CodeRush personal settings +**/.cr/personal + +# Python Tools for Visual Studio (PTVS) +**/__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +#tools/** +#!tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog +MSBuild_Logs/ + +# AWS SAM Build and Temporary Artifacts folder +.aws-sam + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +**/.mfractor/ + +# Local History for Visual Studio +**/.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +**/.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp diff --git a/dotnet/001-connect-passwordless/Program.cs b/dotnet/001-connect-passwordless/Program.cs new file mode 100644 index 0000000..186f8b4 --- /dev/null +++ b/dotnet/001-connect-passwordless/Program.cs @@ -0,0 +1,43 @@ +#:package Azure.Identity@1.13.2 +#:package Microsoft.Azure.Cosmos@3.47.0 +#:package Microsoft.Extensions.Configuration.UserSecrets@10.* +#:property UserSecretsId=azurecosmosdb-samples-dotnet-001-connect-passwordless + +using Azure.Identity; +using Microsoft.Azure.Cosmos; +using Microsoft.Extensions.Configuration; + +IConfigurationRoot configuration = new ConfigurationBuilder() + .AddUserSecrets() + .Build(); + +string endpoint = configuration["COSMOS_ENDPOINT"] + ?? throw new InvalidOperationException("COSMOS_ENDPOINT is not configured. Run: dotnet user-secrets set --file Program.cs \"COSMOS_ENDPOINT\" \"\""); + +var credential = new DefaultAzureCredential(); +var client = new CosmosClient(endpoint, credential); + +Database database = await client.CreateDatabaseIfNotExistsAsync("cosmicworks"); +Console.WriteLine($"Created/retrieved database: {database.Id}"); + +Container container = await database.CreateContainerIfNotExistsAsync("products", "/category"); +Console.WriteLine($"Created/retrieved container: {container.Id}"); + +Product newItem = new( + id: "70b63682-b93a-4c77-aad2-65501347265f", + category: "gear-surf-surfboards", + name: "Yamba Surfboard", + quantity: 12, + sale: false +); + +ItemResponse createResponse = await container.UpsertItemAsync(newItem, new PartitionKey(newItem.category)); +Console.WriteLine($"Upserted item: {createResponse.Resource.id} (status: {createResponse.StatusCode})"); + +ItemResponse readResponse = await container.ReadItemAsync( + newItem.id, + new PartitionKey(newItem.category) +); +Console.WriteLine($"Read item: {readResponse.Resource.name} | Quantity: {readResponse.Resource.quantity}"); + +record Product(string id, string category, string name, int quantity, bool sale); diff --git a/dotnet/001-connect-passwordless/readme.md b/dotnet/001-connect-passwordless/readme.md new file mode 100644 index 0000000..76c3a84 --- /dev/null +++ b/dotnet/001-connect-passwordless/readme.md @@ -0,0 +1,56 @@ +# Connect to Azure Cosmos DB for NoSQL — Passwordless (.NET) + +This sample demonstrates how to authenticate to Azure Cosmos DB for NoSQL using **passwordless authentication** via `DefaultAzureCredential` from the Azure Identity library. No connection strings or keys are required. + +## Prerequisites + +- An [Azure subscription](https://azure.microsoft.com/free/) +- An Azure Cosmos DB for NoSQL account +- [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0) +- [Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli) (for local development login) + +## Setup + +### 1. Assign the required role + +Grant your Azure AD identity the **Cosmos DB Built-in Data Contributor** role on your Cosmos DB account: + +```bash +az cosmosdb sql role assignment create \ + --account-name \ + --resource-group \ + --role-definition-name "Cosmos DB Built-in Data Contributor" \ + --principal-id $(az ad signed-in-user show --query id -o tsv) \ + --scope "/" +``` + +## Run + +### 1. Set your endpoint using user secrets + +```shell +dotnet user-secrets set --file Program.cs "COSMOS_ENDPOINT" "https://.documents.azure.com:443/" +``` + +### 2. Log in with Azure CLI + +```shell +az login +``` + +### 3. Run the sample + +```shell +dotnet run Program.cs +``` + +`DefaultAzureCredential` automatically uses your Azure CLI login locally. In production (Azure App Service, Azure Functions, Azure Container Apps, etc.) it uses the managed identity assigned to the resource — no code changes needed. + +## What this sample does + +1. Reads `COSMOS_ENDPOINT` from user secrets (via `Microsoft.Extensions.Configuration.UserSecrets`) +2. Authenticates using `DefaultAzureCredential` (Azure CLI / Managed Identity / etc.) +3. Creates (or retrieves) a database named `cosmicworks` +4. Creates (or retrieves) a container named `products` with partition key `/category` +5. Creates a product item +6. Reads the item back and prints its details diff --git a/go/.gitignore b/go/.gitignore new file mode 100644 index 0000000..aaadf73 --- /dev/null +++ b/go/.gitignore @@ -0,0 +1,32 @@ +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Code coverage profiles and other test artifacts +*.out +coverage.* +*.coverprofile +profile.cov + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work +go.work.sum + +# env file +.env + +# Editor/IDE +# .idea/ +# .vscode/ diff --git a/go/101-create-item/go.mod b/go/101-create-item/go.mod new file mode 100644 index 0000000..b02ab08 --- /dev/null +++ b/go/101-create-item/go.mod @@ -0,0 +1,15 @@ +module github.com/AzureCosmosDB/samples/go/101-create-item + +go 1.23.0 + +toolchain go1.24.13 + +require github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v1.4.2 + +require ( + github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect + golang.org/x/net v0.38.0 // indirect + golang.org/x/text v0.23.0 // indirect +) diff --git a/go/101-create-item/go.sum b/go/101-create-item/go.sum new file mode 100644 index 0000000..ab69555 --- /dev/null +++ b/go/101-create-item/go.sum @@ -0,0 +1,36 @@ +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1 h1:DSDNVxqkoXJiko6x8a90zidoYqnYYa6c1MTzDKzKkTo= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1/go.mod h1:zGqV2R4Cr/k8Uye5w+dgQ06WJtEcbQG/8J7BB6hnCr4= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 h1:F0gBpfdPLGsw+nsgk6aqqkZS1jiixa5WwFe3fk/T3Ys= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE= +github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v1.4.2 h1:zqxnp53f5Jn5PFU5Av4mvyWEbZ7whg72AoOCEzlXFKc= +github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v1.4.2/go.mod h1:Krtog/7tz27z75TwM5cIS8bxEH4dcBUezcq+kGVeZEo= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA= +github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs= +github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/go/101-create-item/main.go b/go/101-create-item/main.go new file mode 100644 index 0000000..d7ebd28 --- /dev/null +++ b/go/101-create-item/main.go @@ -0,0 +1,129 @@ +package main + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "log" + "net/http" + "os" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos" +) + +type Product struct { + ID string `json:"id"` + Category string `json:"category"` + Name string `json:"name"` + Quantity int `json:"quantity"` + Sale bool `json:"sale"` +} + +func main() { + endpoint := os.Getenv("COSMOS_ENDPOINT") + if endpoint == "" { + log.Fatalf("COSMOS_ENDPOINT environment variable is not set") + } + key := os.Getenv("COSMOS_KEY") + if key == "" { + log.Fatalf("COSMOS_KEY environment variable is not set") + } + + cred, err := azcosmos.NewKeyCredential(key) + if err != nil { + log.Fatalf("failed to create key credential: %v", err) + } + + client, err := azcosmos.NewClientWithKey(endpoint, cred, nil) + if err != nil { + log.Fatalf("failed to create cosmos client: %v", err) + } + + ctx := context.Background() + + // Create database (ignore conflict if already exists) + _, err = client.CreateDatabase(ctx, azcosmos.DatabaseProperties{ID: "cosmicworks"}, nil) + if err != nil && !isConflict(err) { + log.Fatalf("failed to create database: %v", err) + } + fmt.Println("Created/retrieved database: cosmicworks") + + dbClient, err := client.NewDatabase("cosmicworks") + if err != nil { + log.Fatalf("failed to get database client: %v", err) + } + + // Create container (ignore conflict if already exists) + _, err = dbClient.CreateContainer(ctx, azcosmos.ContainerProperties{ + ID: "products", + PartitionKeyDefinition: azcosmos.PartitionKeyDefinition{ + Paths: []string{"/category"}, + }, + }, nil) + if err != nil && !isConflict(err) { + log.Fatalf("failed to create container: %v", err) + } + fmt.Println("Created/retrieved container: products") + + containerClient, err := client.NewContainer("cosmicworks", "products") + if err != nil { + log.Fatalf("failed to get container client: %v", err) + } + + product := Product{ + ID: "70b63682-b93a-4c77-aad2-65501347265f", + Category: "gear-surf-surfboards", + Name: "Yamba Surfboard", + Quantity: 12, + Sale: false, + } + pk := azcosmos.NewPartitionKeyString(product.Category) + + // CREATE + itemBytes, err := json.Marshal(product) + if err != nil { + log.Fatalf("failed to marshal product: %v", err) + } + _, err = containerClient.UpsertItem(ctx, pk, itemBytes, nil) + if err != nil { + log.Fatalf("failed to upsert item: %v", err) + } + fmt.Printf("Upserted item: %s\n", product.ID) + + // READ + readResp, err := containerClient.ReadItem(ctx, pk, product.ID, nil) + if err != nil { + log.Fatalf("failed to read item: %v", err) + } + var readProduct Product + if err = json.Unmarshal(readResp.Value, &readProduct); err != nil { + log.Fatalf("failed to unmarshal read response: %v", err) + } + fmt.Printf("Read item: %s | Quantity: %d\n", readProduct.Name, readProduct.Quantity) + + // UPDATE + readProduct.Quantity = 20 + updatedBytes, err := json.Marshal(readProduct) + if err != nil { + log.Fatalf("failed to marshal updated product: %v", err) + } + _, err = containerClient.ReplaceItem(ctx, pk, readProduct.ID, updatedBytes, nil) + if err != nil { + log.Fatalf("failed to replace item: %v", err) + } + fmt.Printf("Updated item: %s | New quantity: %d\n", readProduct.ID, readProduct.Quantity) + + // DELETE + _, err = containerClient.DeleteItem(ctx, pk, product.ID, nil) + if err != nil { + log.Fatalf("failed to delete item: %v", err) + } + fmt.Printf("Deleted item: %s\n", product.ID) +} + +func isConflict(err error) bool { + var responseErr *azcore.ResponseError + return errors.As(err, &responseErr) && responseErr.StatusCode == http.StatusConflict +} diff --git a/go/101-create-item/readme.md b/go/101-create-item/readme.md new file mode 100644 index 0000000..20841e9 --- /dev/null +++ b/go/101-create-item/readme.md @@ -0,0 +1,43 @@ +# CRUD Operations with Azure Cosmos DB for NoSQL (Go) + +This sample demonstrates the four fundamental **CRUD** operations (Create, Read, Update, Delete) against Azure Cosmos DB for NoSQL using the Azure SDK for Go. + +## Prerequisites + +- An [Azure subscription](https://azure.microsoft.com/free/) +- An Azure Cosmos DB for NoSQL account +- [Go 1.21+](https://go.dev/dl/) + +## Run + +> [!IMPORTANT] +> These environment variables are set **only for the current terminal session** and do **not persist** after you close the window. + +### macOS / Linux + +```bash +export COSMOS_ENDPOINT="https://.documents.azure.com:443/" +export COSMOS_KEY="" +go run main.go +``` + +### Windows (PowerShell) + +```powershell +$Env:COSMOS_ENDPOINT="https://.documents.azure.com:443/" +$Env:COSMOS_KEY="" +go run main.go +``` + +You can find your endpoint and primary key in the Azure portal under your Cosmos DB account → **Keys**. + +## Operations demonstrated + +| Operation | Description | +|-----------|-------------| +| **Create** | Inserts a new `Product` item into the `products` container | +| **Read** | Retrieves the item by ID and partition key, prints its name and quantity | +| **Update** | Modifies the `quantity` field to `20` and replaces the item | +| **Delete** | Removes the item from the container | + +The sample uses key-based authentication (`COSMOS_KEY`) and creates the `cosmicworks` database and `products` container (partitioned by `/category`) if they do not already exist. diff --git a/python/.gitignore b/python/.gitignore new file mode 100644 index 0000000..e15106e --- /dev/null +++ b/python/.gitignore @@ -0,0 +1,216 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[codz] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py.cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +# Pipfile.lock + +# UV +# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# uv.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +# poetry.lock +# poetry.toml + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python. +# https://pdm-project.org/en/latest/usage/project/#working-with-version-control +# pdm.lock +# pdm.toml +.pdm-python +.pdm-build/ + +# pixi +# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control. +# pixi.lock +# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one +# in the .venv directory. It is recommended not to include this directory in version control. +.pixi + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# Redis +*.rdb +*.aof +*.pid + +# RabbitMQ +mnesia/ +rabbitmq/ +rabbitmq-data/ + +# ActiveMQ +activemq-data/ + +# SageMath parsed files +*.sage.py + +# Environments +.env +.envrc +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +# .idea/ + +# Abstra +# Abstra is an AI-powered process automation framework. +# Ignore directories containing user credentials, local state, and settings. +# Learn more at https://abstra.io/docs +.abstra/ + +# Visual Studio Code +# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore +# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore +# and can be added to the global gitignore or merged into this file. However, if you prefer, +# you could uncomment the following to ignore the entire vscode folder +# .vscode/ + +# Ruff stuff: +.ruff_cache/ + +# PyPI configuration file +.pypirc + +# Marimo +marimo/_static/ +marimo/_lsp/ +__marimo__/ + +# Streamlit +.streamlit/secrets.toml diff --git a/python/002-connect-connection-string/app.py b/python/002-connect-connection-string/app.py new file mode 100644 index 0000000..38570bb --- /dev/null +++ b/python/002-connect-connection-string/app.py @@ -0,0 +1,40 @@ +import os + +from azure.cosmos import CosmosClient, PartitionKey + +endpoint = os.environ.get("COSMOS_ENDPOINT") +if not endpoint: + raise ValueError("COSMOS_ENDPOINT environment variable is not set.") + +key = os.environ.get("COSMOS_KEY") +if not key: + raise ValueError("COSMOS_KEY environment variable is not set.") + +client = CosmosClient(url=endpoint, credential=key) + +database = client.create_database_if_not_exists("cosmicworks") +print(f"Created/retrieved database: {database.id}") + +container = database.create_container_if_not_exists( + id="products", + partition_key=PartitionKey(path="/category"), +) +print(f"Created/retrieved container: {container.id}") + +new_item = { + "id": "70b63682-b93a-4c77-aad2-65501347265f", + "category": "gear-surf-surfboards", + "name": "Yamba Surfboard", + "quantity": 12, + "sale": False, +} + +created = container.upsert_item(body=new_item) +print(f"Upserted item: {created['id']}") + +query = "SELECT * FROM products p WHERE p.category = @category" +parameters = [{"name": "@category", "value": "gear-surf-surfboards"}] + +items = list(container.query_items(query=query, parameters=parameters, enable_cross_partition_query=False)) +for item in items: + print(f"Read item: {item['name']} | Quantity: {item['quantity']} | Sale: {item['sale']}") diff --git a/python/002-connect-connection-string/readme.md b/python/002-connect-connection-string/readme.md new file mode 100644 index 0000000..6a4d83b --- /dev/null +++ b/python/002-connect-connection-string/readme.md @@ -0,0 +1,41 @@ +# Connect to Azure Cosmos DB for NoSQL — Key Auth (Python) + +This sample demonstrates how to authenticate to Azure Cosmos DB for NoSQL using an **account key**. This is a quick way to get started, especially for local development and testing. + +## Prerequisites + +- An [Azure subscription](https://azure.microsoft.com/free/) +- An Azure Cosmos DB for NoSQL account +- [Python 3.8+](https://www.python.org/downloads/) + +## Run + +> [!IMPORTANT] +> These environment variables are set **only for the current terminal session** and do **not persist** after you close the window. + +### macOS / Linux + +```bash +export COSMOS_ENDPOINT="https://.documents.azure.com:443/" +export COSMOS_KEY="" +pip install -r requirements.txt && python app.py +``` + +### Windows (PowerShell) + +```powershell +$Env:COSMOS_ENDPOINT="https://.documents.azure.com:443/" +$Env:COSMOS_KEY="" +pip install -r requirements.txt; python app.py +``` + +You can find your endpoint and primary key in the Azure portal under your Cosmos DB account → **Keys**. + +## What this sample does + +1. Reads `COSMOS_ENDPOINT` and `COSMOS_KEY` from the environment +2. Creates a `CosmosClient` using the endpoint and key +3. Creates (or retrieves) a database named `cosmicworks` +4. Creates (or retrieves) a container named `products` with partition key `/category` +5. Creates a product item +6. Queries items filtered by category and prints the results diff --git a/python/002-connect-connection-string/requirements.txt b/python/002-connect-connection-string/requirements.txt new file mode 100644 index 0000000..3623bed --- /dev/null +++ b/python/002-connect-connection-string/requirements.txt @@ -0,0 +1 @@ +azure-cosmos==4.9.0