11from datetime import datetime
22import azure .functions as func
3+ from azure .identity import DefaultAzureCredential
34import logging
45import json
56import os
6- import pymssql
7+ import pyodbc
78import pandas as pd
9+ import struct
810# from dotenv import load_dotenv
911# load_dotenv()
1012
1113app = func .FunctionApp (http_auth_level = func .AuthLevel .ANONYMOUS )
1214
15+ # get database connection
16+ def get_db_connection ():
17+ driver = "{ODBC Driver 17 for SQL Server}"
18+ server = os .environ .get ("SQLDB_SERVER" )
19+ database = os .environ .get ("SQLDB_DATABASE" )
20+ username = os .environ .get ("SQLDB_USERNAME" )
21+ password = os .environ .get ("SQLDB_PASSWORD" )
22+
23+ # Attempt connection using Username & Password
24+ try :
25+ conn = pyodbc .connect (
26+ f"DRIVER={ driver } ;SERVER={ server } ;DATABASE={ database } ;UID={ username } ;PWD={ password } " ,
27+ timeout = 5
28+ )
29+ logging .info ("Connected using Username & Password" )
30+ return conn
31+ except pyodbc .Error as e :
32+ print (f"Failed with Username & Password: { str (e )} " )
33+
34+ # If first attempt fails, try Azure Default Credential
35+ try :
36+ credential = DefaultAzureCredential ()
37+
38+ token_bytes = credential .get_token (
39+ "https://database.windows.net/.default"
40+ ).token .encode ("utf-16-LE" )
41+ token_struct = struct .pack (f"<I{ len (token_bytes )} s" , len (token_bytes ), token_bytes )
42+ SQL_COPT_SS_ACCESS_TOKEN = (
43+ 1256 # This connection option is defined by microsoft in msodbcsql.h
44+ )
45+
46+ # Set up the connection
47+ connection_string = f"DRIVER={ driver } ;SERVER={ server } ;DATABASE={ database } ;"
48+ conn = pyodbc .connect (
49+ connection_string , attrs_before = {SQL_COPT_SS_ACCESS_TOKEN : token_struct }
50+ )
51+
52+ logging .info ("Connected using Default Azure Credential" )
53+ return conn
54+ except Exception as e :
55+ logging .error (f"Failed with Default Credential: { str (e )} " )
56+ return None # Return None if both attempts fail
57+
1358# add post methods - filters will come in the body (request.body), if body is not empty, update the where clause in the query
1459@app .route (route = "get_metrics" , methods = ["GET" ,"POST" ], auth_level = func .AuthLevel .ANONYMOUS )
1560def get_metrics (req : func .HttpRequest ) -> func .HttpResponse :
@@ -19,12 +64,7 @@ def get_metrics(req: func.HttpRequest) -> func.HttpResponse:
1964 if not data_type :
2065 data_type = 'filters'
2166
22- server = os .environ .get ("SQLDB_SERVER" )
23- database = os .environ .get ("SQLDB_DATABASE" )
24- username = os .environ .get ("SQLDB_USERNAME" )
25- password = os .environ .get ("SQLDB_PASSWORD" )
26-
27- conn = pymssql .connect (server , username , password , database )
67+ conn = get_db_connection ()
2868 cursor = conn .cursor ()
2969
3070 # Adjust the dates to the current date
@@ -73,8 +113,12 @@ def get_metrics(req: func.HttpRequest) -> func.HttpResponse:
73113 ) t'''
74114
75115 cursor .execute (sql_stmt )
76- rows = cursor .fetchall ()
116+ #rows = cursor.fetchall()
117+
118+ # Convert pyodbc.Row objects to tuples
119+ rows = [tuple (row ) for row in cursor .fetchall ()]
77120
121+ # Define column names
78122 column_names = [i [0 ] for i in cursor .description ]
79123 df = pd .DataFrame (rows , columns = column_names )
80124 df .rename (columns = {'key1' :'key' }, inplace = True )
@@ -167,7 +211,8 @@ def get_metrics(req: func.HttpRequest) -> func.HttpResponse:
167211 #charts pt1
168212 cursor .execute (sql_stmt )
169213
170- rows = cursor .fetchall ()
214+ # rows = cursor.fetchall()
215+ rows = [tuple (row ) for row in cursor .fetchall ()]
171216
172217 column_names = [i [0 ] for i in cursor .description ]
173218 df = pd .DataFrame (rows , columns = column_names )
@@ -208,7 +253,8 @@ def get_metrics(req: func.HttpRequest) -> func.HttpResponse:
208253
209254 cursor .execute (sql_stmt )
210255
211- rows = cursor .fetchall ()
256+ # rows = cursor.fetchall()
257+ rows = [tuple (row ) for row in cursor .fetchall ()]
212258
213259 column_names = [i [0 ] for i in cursor .description ]
214260 df = pd .DataFrame (rows , columns = column_names )
@@ -286,7 +332,8 @@ def get_metrics(req: func.HttpRequest) -> func.HttpResponse:
286332
287333 cursor .execute (sql_stmt )
288334
289- rows = cursor .fetchall ()
335+ # rows = cursor.fetchall()
336+ rows = [tuple (row ) for row in cursor .fetchall ()]
290337
291338 column_names = [i [0 ] for i in cursor .description ]
292339 df = pd .DataFrame (rows , columns = column_names )
0 commit comments