new file: __pycache__/config.cpython-313.pyc new file: _type_code.py new file: config.py new file: connectAS.py new file: msnet/Microsoft.AnalysisServices.AdomdClient.dll new file: msnet/Microsoft.AnalysisServices.DLL new file: msnet/Microsoft.AnalysisServices.Tabular.DLL new file: test.ipynb
270 lines
6.8 KiB
Python
270 lines
6.8 KiB
Python
from __future__ import annotations
|
|
|
|
# from pyadomd import *
|
|
|
|
|
|
import clr
|
|
import os
|
|
from System.IO import FileNotFoundException
|
|
from config import CURRENT_DIR_PATH, NET_FOLDER
|
|
|
|
# MS.NET path
|
|
AnalysisServices_path = os.path.join(
|
|
CURRENT_DIR_PATH, NET_FOLDER, "Microsoft.AnalysisServices"
|
|
)
|
|
AdomdClient_path = os.path.join(
|
|
CURRENT_DIR_PATH, NET_FOLDER, "Microsoft.AnalysisServices.AdomdClient"
|
|
)
|
|
Tabular_path = os.path.join(
|
|
CURRENT_DIR_PATH, NET_FOLDER, "Microsoft.AnalysisServices.Tabular"
|
|
)
|
|
|
|
# Add reference
|
|
try:
|
|
clr.AddReference(AdomdClient_path)
|
|
clr.AddReference(Tabular_path)
|
|
from Microsoft.AnalysisServices.AdomdClient import AdomdConnection, AdomdCommand
|
|
from Microsoft.AnalysisServices.Tabular import (
|
|
Database,
|
|
Server,
|
|
Table,
|
|
Column,
|
|
Measure,
|
|
Partition,
|
|
Level,
|
|
Hierarchy,
|
|
Trace
|
|
)
|
|
except FileNotFoundException as e:
|
|
print(
|
|
"========================================================================================"
|
|
)
|
|
print(e.ToString())
|
|
print(
|
|
"========================================================================================"
|
|
)
|
|
|
|
|
|
from _type_code import adomd_type_map, convert, TypeVar, NamedTuple
|
|
|
|
# Types
|
|
T = TypeVar("T")
|
|
|
|
|
|
class Description(NamedTuple):
|
|
"""
|
|
:param [name]: Column name
|
|
:param [type_code]: The column data type
|
|
"""
|
|
|
|
name: str
|
|
type_code: str
|
|
|
|
|
|
class Cursor:
|
|
|
|
def __init__(self, connection: AdomdConnection):
|
|
self._conn = connection
|
|
self._description: List[Description] = []
|
|
|
|
def close(self) -> None:
|
|
"""
|
|
Closes the cursor
|
|
"""
|
|
if self.is_closed:
|
|
return
|
|
self._reader.Close()
|
|
|
|
def execute(self, query: str) -> Cursor:
|
|
"""
|
|
Executes a query against the data source
|
|
|
|
:params [query]: The query to be executed
|
|
"""
|
|
self._cmd = AdomdCommand(query, self._conn)
|
|
self._reader = self._cmd.ExecuteReader()
|
|
self._field_count = self._reader.FieldCount
|
|
|
|
for i in range(self._field_count):
|
|
self._description.append(
|
|
Description(
|
|
self._reader.GetName(i),
|
|
adomd_type_map[self._reader.GetFieldType(i).ToString()].type_name,
|
|
)
|
|
)
|
|
return self
|
|
|
|
def fetchone(self) -> Iterator[Tuple[T, ...]]:
|
|
"""
|
|
Fetches the current line from the last executed query
|
|
"""
|
|
while self._reader.Read():
|
|
yield tuple(
|
|
convert(
|
|
self._reader.GetFieldType(i).ToString(),
|
|
self._reader[i],
|
|
adomd_type_map,
|
|
)
|
|
for i in range(self._field_count)
|
|
)
|
|
|
|
def fetchmany(self, size=1) -> List[Tuple[T, ...]]:
|
|
"""
|
|
Fetches one or more lines from the last executed query
|
|
|
|
:params [size]: The number of rows to fetch.
|
|
If the size parameter exceeds the number of rows returned from the last executed query then fetchmany will return all rows from that query.
|
|
"""
|
|
l: List[Tuple[T, ...]] = []
|
|
try:
|
|
for i in range(size):
|
|
l.append(next(self.fetchone()))
|
|
except StopIteration:
|
|
pass
|
|
return l
|
|
|
|
def fetchall(self) -> List[Tuple[T, ...]]:
|
|
"""
|
|
Fetches all the rows from the last executed query
|
|
"""
|
|
# mypy issues with list comprehension :-(
|
|
return [i for i in self.fetchone()] # type: ignore
|
|
|
|
@property
|
|
def is_closed(self) -> bool:
|
|
try:
|
|
state = self._reader.IsClosed
|
|
except AttributeError:
|
|
return True
|
|
return state
|
|
|
|
@property
|
|
def description(self) -> List[Description]:
|
|
return self._description
|
|
|
|
def __enter__(self) -> Cursor:
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback) -> None:
|
|
self.close()
|
|
|
|
class Pyadomd:
|
|
|
|
def __init__(self, conn_str:str):
|
|
self.conn = AdomdConnection()
|
|
self.conn.ConnectionString = conn_str
|
|
|
|
def close(self) -> None:
|
|
"""
|
|
Closes the connection
|
|
"""
|
|
self.conn.Close()
|
|
|
|
def open(self) -> None:
|
|
"""
|
|
Opens the connection
|
|
"""
|
|
self.conn.Open()
|
|
|
|
def cursor(self) -> Cursor:
|
|
"""
|
|
Creates a cursor object
|
|
"""
|
|
c = Cursor(self.conn)
|
|
return c
|
|
|
|
@property
|
|
def state(self) -> int:
|
|
"""
|
|
1 = Open
|
|
0 = Closed
|
|
"""
|
|
return self.conn.State
|
|
|
|
def __enter__(self) -> Pyadomd:
|
|
self.open()
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback) -> None:
|
|
self.close()
|
|
|
|
|
|
class Pytabular:
|
|
def __init__(self, conn_str: str):
|
|
self.server = Server()
|
|
self.server.Connect(conn_str)
|
|
|
|
def close(self) -> None:
|
|
"""Closes the connection"""
|
|
if self.server is not None:
|
|
self.server.Disconnect()
|
|
|
|
@property
|
|
def databases(self) -> List[str]:
|
|
"""Returns a list of database names in the server"""
|
|
return [db.Name for db in self.server.Databases]
|
|
|
|
@property
|
|
def state(self) -> int:
|
|
"""1 = Open, 0 = Closed"""
|
|
return 1 if self.server is not None and self.server.Connected else 0
|
|
|
|
def __enter__(self) -> Pytabular:
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback) -> None:
|
|
self.close()
|
|
|
|
# @property
|
|
# def tables(self) -> List[Table]:
|
|
# """
|
|
# Returns a list of tables in the database
|
|
# """
|
|
# return self.db.Model.Tables
|
|
|
|
# @property
|
|
# def partitions(self) -> List[Partition]:
|
|
# """
|
|
# Returns a list of partitions in the database
|
|
# """
|
|
# return self.db.Model.Partitions
|
|
|
|
# @property
|
|
# def levels(self) -> List[Level]:
|
|
# """
|
|
# Returns a list of levels in the database
|
|
# """
|
|
# return self.db.Model.Levels
|
|
|
|
# @property
|
|
# def hierarchies(self) -> List[Hierarchy]:
|
|
# """
|
|
# Returns a list of hierarchies in the database
|
|
# """
|
|
# return self.db.Model.Hierarchies
|
|
|
|
# @property
|
|
# def measures(self) -> List[Measure]:
|
|
# """
|
|
# Returns a list of measures in the database
|
|
# """
|
|
# return self.db.Model.Measures
|
|
|
|
# @property
|
|
# def traces(self) -> List[Trace]:
|
|
# """
|
|
# Returns a list of traces in the database
|
|
# """
|
|
# return self.db.Model.Traces
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
conn_str = "Provider=MSOLAP;Data Source=localhost"
|
|
with Pytabular(conn_str) as conn:
|
|
print("Connected to Analysis Services server")
|
|
print("Available databases:")
|
|
for db in conn.databases:
|
|
print(f"- {db}") |