gamsapi 52.5.0__cp312-cp312-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gams/__init__.py +27 -0
- gams/_version.py +1 -0
- gams/connect/__init__.py +28 -0
- gams/connect/agents/__init__.py +24 -0
- gams/connect/agents/_excel/__init__.py +32 -0
- gams/connect/agents/_excel/excelagent.py +312 -0
- gams/connect/agents/_excel/workbook.py +155 -0
- gams/connect/agents/_sqlconnectors/__init__.py +42 -0
- gams/connect/agents/_sqlconnectors/_accesshandler.py +211 -0
- gams/connect/agents/_sqlconnectors/_databasehandler.py +250 -0
- gams/connect/agents/_sqlconnectors/_mysqlhandler.py +168 -0
- gams/connect/agents/_sqlconnectors/_postgreshandler.py +131 -0
- gams/connect/agents/_sqlconnectors/_pyodbchandler.py +112 -0
- gams/connect/agents/_sqlconnectors/_sqlalchemyhandler.py +74 -0
- gams/connect/agents/_sqlconnectors/_sqlitehandler.py +262 -0
- gams/connect/agents/_sqlconnectors/_sqlserverhandler.py +179 -0
- gams/connect/agents/concatenate.py +440 -0
- gams/connect/agents/connectagent.py +743 -0
- gams/connect/agents/csvreader.py +675 -0
- gams/connect/agents/csvwriter.py +151 -0
- gams/connect/agents/domainwriter.py +143 -0
- gams/connect/agents/excelreader.py +756 -0
- gams/connect/agents/excelwriter.py +467 -0
- gams/connect/agents/filter.py +223 -0
- gams/connect/agents/gamsreader.py +112 -0
- gams/connect/agents/gamswriter.py +239 -0
- gams/connect/agents/gdxreader.py +109 -0
- gams/connect/agents/gdxwriter.py +146 -0
- gams/connect/agents/labelmanipulator.py +303 -0
- gams/connect/agents/projection.py +539 -0
- gams/connect/agents/pythoncode.py +71 -0
- gams/connect/agents/rawcsvreader.py +248 -0
- gams/connect/agents/rawexcelreader.py +312 -0
- gams/connect/agents/schema/CSVReader.yaml +92 -0
- gams/connect/agents/schema/CSVWriter.yaml +44 -0
- gams/connect/agents/schema/Concatenate.yaml +52 -0
- gams/connect/agents/schema/DomainWriter.yaml +25 -0
- gams/connect/agents/schema/ExcelReader.yaml +121 -0
- gams/connect/agents/schema/ExcelWriter.yaml +78 -0
- gams/connect/agents/schema/Filter.yaml +74 -0
- gams/connect/agents/schema/GAMSReader.yaml +20 -0
- gams/connect/agents/schema/GAMSWriter.yaml +47 -0
- gams/connect/agents/schema/GDXReader.yaml +23 -0
- gams/connect/agents/schema/GDXWriter.yaml +32 -0
- gams/connect/agents/schema/LabelManipulator.yaml +99 -0
- gams/connect/agents/schema/Projection.yaml +24 -0
- gams/connect/agents/schema/PythonCode.yaml +6 -0
- gams/connect/agents/schema/RawCSVReader.yaml +34 -0
- gams/connect/agents/schema/RawExcelReader.yaml +42 -0
- gams/connect/agents/schema/SQLReader.yaml +75 -0
- gams/connect/agents/schema/SQLWriter.yaml +103 -0
- gams/connect/agents/sqlreader.py +301 -0
- gams/connect/agents/sqlwriter.py +276 -0
- gams/connect/connectdatabase.py +275 -0
- gams/connect/connectvalidator.py +93 -0
- gams/connect/errors.py +34 -0
- gams/control/__init__.py +136 -0
- gams/control/database.py +2231 -0
- gams/control/execution.py +1900 -0
- gams/control/options.py +2792 -0
- gams/control/workspace.py +1198 -0
- gams/core/__init__.py +24 -0
- gams/core/cfg/__init__.py +26 -0
- gams/core/cfg/_cfgmcc.cp312-win_amd64.pyd +0 -0
- gams/core/cfg/cfgmcc.py +519 -0
- gams/core/dct/__init__.py +26 -0
- gams/core/dct/_dctmcc.cp312-win_amd64.pyd +0 -0
- gams/core/dct/dctmcc.py +574 -0
- gams/core/embedded/__init__.py +26 -0
- gams/core/embedded/gamsemb.py +1024 -0
- gams/core/emp/__init__.py +24 -0
- gams/core/emp/emplexer.py +89 -0
- gams/core/emp/empyacc.py +281 -0
- gams/core/gdx/__init__.py +26 -0
- gams/core/gdx/_gdxcc.cp312-win_amd64.pyd +0 -0
- gams/core/gdx/gdxcc.py +866 -0
- gams/core/gev/__init__.py +26 -0
- gams/core/gev/_gevmcc.cp312-win_amd64.pyd +0 -0
- gams/core/gev/gevmcc.py +855 -0
- gams/core/gmd/__init__.py +26 -0
- gams/core/gmd/_gmdcc.cp312-win_amd64.pyd +0 -0
- gams/core/gmd/gmdcc.py +917 -0
- gams/core/gmo/__init__.py +26 -0
- gams/core/gmo/_gmomcc.cp312-win_amd64.pyd +0 -0
- gams/core/gmo/gmomcc.py +2046 -0
- gams/core/idx/__init__.py +26 -0
- gams/core/idx/_idxcc.cp312-win_amd64.pyd +0 -0
- gams/core/idx/idxcc.py +510 -0
- gams/core/numpy/__init__.py +29 -0
- gams/core/numpy/_gams2numpy.cp312-win_amd64.pyd +0 -0
- gams/core/numpy/gams2numpy.py +1048 -0
- gams/core/opt/__init__.py +26 -0
- gams/core/opt/_optcc.cp312-win_amd64.pyd +0 -0
- gams/core/opt/optcc.py +840 -0
- gams/engine/__init__.py +204 -0
- gams/engine/api/__init__.py +13 -0
- gams/engine/api/auth_api.py +7653 -0
- gams/engine/api/cleanup_api.py +751 -0
- gams/engine/api/default_api.py +887 -0
- gams/engine/api/hypercube_api.py +2629 -0
- gams/engine/api/jobs_api.py +5229 -0
- gams/engine/api/licenses_api.py +2220 -0
- gams/engine/api/namespaces_api.py +7783 -0
- gams/engine/api/usage_api.py +5627 -0
- gams/engine/api/users_api.py +5931 -0
- gams/engine/api_client.py +804 -0
- gams/engine/api_response.py +21 -0
- gams/engine/configuration.py +601 -0
- gams/engine/exceptions.py +216 -0
- gams/engine/models/__init__.py +86 -0
- gams/engine/models/bad_input.py +89 -0
- gams/engine/models/cleanable_job_result.py +104 -0
- gams/engine/models/cleanable_job_result_page.py +113 -0
- gams/engine/models/engine_license.py +107 -0
- gams/engine/models/files_not_found.py +93 -0
- gams/engine/models/forwarded_token_response.py +112 -0
- gams/engine/models/generic_key_value_pair.py +89 -0
- gams/engine/models/hypercube.py +160 -0
- gams/engine/models/hypercube_page.py +111 -0
- gams/engine/models/hypercube_summary.py +91 -0
- gams/engine/models/hypercube_token.py +97 -0
- gams/engine/models/identity_provider.py +107 -0
- gams/engine/models/identity_provider_ldap.py +121 -0
- gams/engine/models/identity_provider_oauth2.py +146 -0
- gams/engine/models/identity_provider_oauth2_scope.py +89 -0
- gams/engine/models/identity_provider_oauth2_with_secret.py +152 -0
- gams/engine/models/identity_provider_oidc.py +133 -0
- gams/engine/models/identity_provider_oidc_with_secret.py +143 -0
- gams/engine/models/inex.py +91 -0
- gams/engine/models/invitation.py +136 -0
- gams/engine/models/invitation_quota.py +106 -0
- gams/engine/models/invitation_token.py +87 -0
- gams/engine/models/job.py +165 -0
- gams/engine/models/job_no_text_entry.py +138 -0
- gams/engine/models/job_no_text_entry_page.py +111 -0
- gams/engine/models/license.py +91 -0
- gams/engine/models/log_piece.py +96 -0
- gams/engine/models/message.py +87 -0
- gams/engine/models/message_and_token.py +99 -0
- gams/engine/models/message_with_webhook_id.py +89 -0
- gams/engine/models/model_auth_token.py +87 -0
- gams/engine/models/model_configuration.py +125 -0
- gams/engine/models/model_default_instance.py +99 -0
- gams/engine/models/model_default_user_instance.py +98 -0
- gams/engine/models/model_hypercube_job.py +106 -0
- gams/engine/models/model_hypercube_usage.py +130 -0
- gams/engine/models/model_instance_info.py +116 -0
- gams/engine/models/model_instance_info_full.py +123 -0
- gams/engine/models/model_instance_pool_info.py +112 -0
- gams/engine/models/model_job_labels.py +179 -0
- gams/engine/models/model_job_usage.py +133 -0
- gams/engine/models/model_pool_usage.py +124 -0
- gams/engine/models/model_usage.py +115 -0
- gams/engine/models/model_user.py +96 -0
- gams/engine/models/model_userinstance_info.py +119 -0
- gams/engine/models/model_userinstancepool_info.py +95 -0
- gams/engine/models/model_version.py +91 -0
- gams/engine/models/models.py +120 -0
- gams/engine/models/namespace.py +104 -0
- gams/engine/models/namespace_quota.py +96 -0
- gams/engine/models/namespace_with_permission.py +96 -0
- gams/engine/models/not_found.py +91 -0
- gams/engine/models/password_policy.py +97 -0
- gams/engine/models/perm_and_username.py +89 -0
- gams/engine/models/quota.py +117 -0
- gams/engine/models/quota_exceeded.py +97 -0
- gams/engine/models/status_code_meaning.py +89 -0
- gams/engine/models/stream_entry.py +89 -0
- gams/engine/models/system_wide_license.py +92 -0
- gams/engine/models/text_entries.py +87 -0
- gams/engine/models/text_entry.py +101 -0
- gams/engine/models/time_span.py +95 -0
- gams/engine/models/time_span_pool_worker.py +99 -0
- gams/engine/models/token_forward_error.py +87 -0
- gams/engine/models/user.py +127 -0
- gams/engine/models/user_group_member.py +96 -0
- gams/engine/models/user_groups.py +108 -0
- gams/engine/models/vapid_info.py +87 -0
- gams/engine/models/webhook.py +138 -0
- gams/engine/models/webhook_parameterized_event.py +99 -0
- gams/engine/py.typed +0 -0
- gams/engine/rest.py +258 -0
- gams/magic/__init__.py +32 -0
- gams/magic/gams_magic.py +142 -0
- gams/magic/interactive.py +402 -0
- gams/tools/__init__.py +30 -0
- gams/tools/errors.py +34 -0
- gams/tools/toolcollection/__init__.py +24 -0
- gams/tools/toolcollection/alg/__init__.py +24 -0
- gams/tools/toolcollection/alg/rank.py +51 -0
- gams/tools/toolcollection/data/__init__.py +24 -0
- gams/tools/toolcollection/data/csvread.py +444 -0
- gams/tools/toolcollection/data/csvwrite.py +311 -0
- gams/tools/toolcollection/data/exceldump.py +47 -0
- gams/tools/toolcollection/data/sqlitewrite.py +276 -0
- gams/tools/toolcollection/gdxservice/__init__.py +24 -0
- gams/tools/toolcollection/gdxservice/gdxencoding.py +104 -0
- gams/tools/toolcollection/gdxservice/gdxrename.py +94 -0
- gams/tools/toolcollection/linalg/__init__.py +24 -0
- gams/tools/toolcollection/linalg/cholesky.py +57 -0
- gams/tools/toolcollection/linalg/eigenvalue.py +56 -0
- gams/tools/toolcollection/linalg/eigenvector.py +58 -0
- gams/tools/toolcollection/linalg/invert.py +55 -0
- gams/tools/toolcollection/linalg/ols.py +138 -0
- gams/tools/toolcollection/tooltemplate.py +321 -0
- gams/tools/toolcollection/win32/__init__.py +24 -0
- gams/tools/toolcollection/win32/excelmerge.py +93 -0
- gams/tools/toolcollection/win32/exceltalk.py +76 -0
- gams/tools/toolcollection/win32/msappavail.py +49 -0
- gams/tools/toolcollection/win32/shellexecute.py +54 -0
- gams/tools/tools.py +116 -0
- gams/transfer/__init__.py +35 -0
- gams/transfer/_abcs/__init__.py +37 -0
- gams/transfer/_abcs/container_abcs.py +433 -0
- gams/transfer/_internals/__init__.py +63 -0
- gams/transfer/_internals/algorithms.py +436 -0
- gams/transfer/_internals/casepreservingdict.py +124 -0
- gams/transfer/_internals/constants.py +270 -0
- gams/transfer/_internals/domainviolation.py +103 -0
- gams/transfer/_internals/specialvalues.py +172 -0
- gams/transfer/containers/__init__.py +26 -0
- gams/transfer/containers/_container.py +1794 -0
- gams/transfer/containers/_io/__init__.py +28 -0
- gams/transfer/containers/_io/containers.py +164 -0
- gams/transfer/containers/_io/gdx.py +1029 -0
- gams/transfer/containers/_io/gmd.py +872 -0
- gams/transfer/containers/_mixins/__init__.py +26 -0
- gams/transfer/containers/_mixins/ccc.py +1274 -0
- gams/transfer/syms/__init__.py +33 -0
- gams/transfer/syms/_methods/__init__.py +24 -0
- gams/transfer/syms/_methods/tables.py +120 -0
- gams/transfer/syms/_methods/toDict.py +115 -0
- gams/transfer/syms/_methods/toList.py +83 -0
- gams/transfer/syms/_methods/toValue.py +60 -0
- gams/transfer/syms/_mixins/__init__.py +32 -0
- gams/transfer/syms/_mixins/equals.py +626 -0
- gams/transfer/syms/_mixins/generateRecords.py +499 -0
- gams/transfer/syms/_mixins/pivot.py +313 -0
- gams/transfer/syms/_mixins/pve.py +627 -0
- gams/transfer/syms/_mixins/sa.py +27 -0
- gams/transfer/syms/_mixins/sapve.py +27 -0
- gams/transfer/syms/_mixins/saua.py +27 -0
- gams/transfer/syms/_mixins/sauapve.py +199 -0
- gams/transfer/syms/_mixins/spve.py +1528 -0
- gams/transfer/syms/_mixins/ve.py +936 -0
- gams/transfer/syms/container_syms/__init__.py +31 -0
- gams/transfer/syms/container_syms/_alias.py +984 -0
- gams/transfer/syms/container_syms/_equation.py +333 -0
- gams/transfer/syms/container_syms/_parameter.py +973 -0
- gams/transfer/syms/container_syms/_set.py +604 -0
- gams/transfer/syms/container_syms/_universe_alias.py +461 -0
- gams/transfer/syms/container_syms/_variable.py +321 -0
- gamsapi-52.5.0.dist-info/METADATA +150 -0
- gamsapi-52.5.0.dist-info/RECORD +257 -0
- gamsapi-52.5.0.dist-info/WHEEL +5 -0
- gamsapi-52.5.0.dist-info/licenses/LICENSE +22 -0
- gamsapi-52.5.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#
|
|
2
|
+
# GAMS - General Algebraic Modeling System Python API
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2017-2026 GAMS Development Corp. <support@gams.com>
|
|
5
|
+
# Copyright (c) 2017-2026 GAMS Software GmbH <support@gams.com>
|
|
6
|
+
#
|
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
# in the Software without restriction, including without limitation the rights
|
|
10
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
# furnished to do so, subject to the following conditions:
|
|
13
|
+
#
|
|
14
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
# copies or substantial portions of the Software.
|
|
16
|
+
#
|
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
# SOFTWARE.
|
|
24
|
+
#
|
|
25
|
+
|
|
26
|
+
import pandas as pd
|
|
27
|
+
from gams.connect.agents._sqlconnectors._databasehandler import DatabaseConnector
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class PostgresConnector(DatabaseConnector):
|
|
31
|
+
SUPPORTED_INSERT_METHODS = ["default", "bulkInsert"]
|
|
32
|
+
|
|
33
|
+
def connect(self, connection_details, connection_args, **kwargs) -> None:
|
|
34
|
+
|
|
35
|
+
import psycopg2 as sql
|
|
36
|
+
|
|
37
|
+
if kwargs.get("isWrite", True):
|
|
38
|
+
# autocommit is relevant only for SQLWriter
|
|
39
|
+
self._pg_autocommit = connection_args.pop("autocommit", False)
|
|
40
|
+
|
|
41
|
+
self._engine = sql.connect(**connection_details, **connection_args)
|
|
42
|
+
self._conn = self._engine.cursor()
|
|
43
|
+
|
|
44
|
+
def create_transaction(self):
|
|
45
|
+
self._engine.autocommit = self._pg_autocommit
|
|
46
|
+
|
|
47
|
+
def _check_table_exists(self, tableName: str, schema: str | None) -> bool:
|
|
48
|
+
tableExists = False
|
|
49
|
+
|
|
50
|
+
# striping escape characters is not required. SQLSServer is insensitive to use of escape character.
|
|
51
|
+
qualified_table_name = f"{schema}.{tableName}" if schema else tableName
|
|
52
|
+
|
|
53
|
+
query = f"""SELECT to_regclass('{qualified_table_name}')"""
|
|
54
|
+
self._conn.execute(query)
|
|
55
|
+
res = self._conn.fetchone()
|
|
56
|
+
# TODO: check for POSTGRES type(res)
|
|
57
|
+
### res can be = (obj,) | None | (None,)
|
|
58
|
+
if isinstance(res, tuple):
|
|
59
|
+
if res[0]:
|
|
60
|
+
tableExists = True
|
|
61
|
+
|
|
62
|
+
return tableExists
|
|
63
|
+
|
|
64
|
+
def _create_table(
|
|
65
|
+
self,
|
|
66
|
+
df: pd.DataFrame,
|
|
67
|
+
tableName: str,
|
|
68
|
+
schema: str | None,
|
|
69
|
+
ifExists: str,
|
|
70
|
+
**kwargs,
|
|
71
|
+
) -> None:
|
|
72
|
+
"""
|
|
73
|
+
Drops an exisiting table and creates a new table with the same name. Uses specific SQL queries for each DBMS flavour.
|
|
74
|
+
"""
|
|
75
|
+
tableCols = ""
|
|
76
|
+
for col, dtype in df.dtypes.items():
|
|
77
|
+
if dtype == "float64":
|
|
78
|
+
tableCols += f'"{col}" FLOAT,'
|
|
79
|
+
elif dtype == "int64":
|
|
80
|
+
tableCols += f'"{col}" BIGINT,'
|
|
81
|
+
elif dtype in ["object", "category"]:
|
|
82
|
+
tableCols += f'"{col}" TEXT,'
|
|
83
|
+
|
|
84
|
+
tableCols = tableCols[:-1]
|
|
85
|
+
|
|
86
|
+
if schema:
|
|
87
|
+
tableName = schema + "." + tableName
|
|
88
|
+
|
|
89
|
+
if ifExists == "replace":
|
|
90
|
+
try:
|
|
91
|
+
self._conn.execute(f"""DROP TABLE IF EXISTS {tableName};""")
|
|
92
|
+
except Exception as e:
|
|
93
|
+
self._raise_error(
|
|
94
|
+
f"Cannot drop table >{tableName}<.\nException from {type(e).__module__}: {type(e).__name__}> {e}"
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
self._conn.execute(f"""CREATE TABLE {tableName}({tableCols});""")
|
|
98
|
+
if self._traceValue > 1:
|
|
99
|
+
self._traceLog(
|
|
100
|
+
f"Created new table: >{tableName}< with columns: >{tableCols}<"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
def _insert_data(self, df: pd.DataFrame, writeFunction_args: dict):
|
|
104
|
+
"""
|
|
105
|
+
default: uses .execute_batch with page_size=100 (fixed and default)
|
|
106
|
+
bulkInsert: uses the .copy_expert method to stream a csv file into the DB
|
|
107
|
+
"""
|
|
108
|
+
tableName = writeFunction_args["name"]
|
|
109
|
+
insertMethod = writeFunction_args["insertMethod"]
|
|
110
|
+
|
|
111
|
+
if writeFunction_args["schema"]:
|
|
112
|
+
tableName = writeFunction_args["schema"] + "." + tableName
|
|
113
|
+
|
|
114
|
+
if insertMethod == "bulkInsert":
|
|
115
|
+
import io
|
|
116
|
+
|
|
117
|
+
s_buf = io.StringIO()
|
|
118
|
+
df.to_csv(s_buf, index=False, header=False)
|
|
119
|
+
s_buf.seek(0)
|
|
120
|
+
colNames = ", ".join(f'"{ele}"' for ele in df.columns)
|
|
121
|
+
query = f"""COPY {tableName} ({colNames}) FROM STDIN WITH CSV"""
|
|
122
|
+
self._conn.copy_expert(query, file=s_buf)
|
|
123
|
+
elif insertMethod == "default":
|
|
124
|
+
from psycopg2.extras import execute_batch
|
|
125
|
+
|
|
126
|
+
placeHolder = "%s," * (len(df.columns) - 1)
|
|
127
|
+
query = f"INSERT INTO {tableName} VALUES(" + placeHolder + "%s)"
|
|
128
|
+
if df.isnull().values.any(): # replace NaN with None, for SQL NULL
|
|
129
|
+
df = df.astype(object).where(pd.notnull(df), None)
|
|
130
|
+
df_list = df.values.tolist()
|
|
131
|
+
execute_batch(self._conn, query, df_list)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#
|
|
2
|
+
# GAMS - General Algebraic Modeling System Python API
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2017-2026 GAMS Development Corp. <support@gams.com>
|
|
5
|
+
# Copyright (c) 2017-2026 GAMS Software GmbH <support@gams.com>
|
|
6
|
+
#
|
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
# in the Software without restriction, including without limitation the rights
|
|
10
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
# furnished to do so, subject to the following conditions:
|
|
13
|
+
#
|
|
14
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
# copies or substantial portions of the Software.
|
|
16
|
+
#
|
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
# SOFTWARE.
|
|
24
|
+
#
|
|
25
|
+
|
|
26
|
+
import pandas as pd
|
|
27
|
+
from gams.connect.agents._sqlconnectors._databasehandler import DatabaseConnector
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class PyodbcConnector(DatabaseConnector):
|
|
31
|
+
SUPPORTED_INSERT_METHODS = ["default"]
|
|
32
|
+
QUOTE_CHAR = ["[]", '""', "``"]
|
|
33
|
+
|
|
34
|
+
def connect(self, connection_details, connection_args, **kwargs) -> None:
|
|
35
|
+
import pyodbc as sql
|
|
36
|
+
|
|
37
|
+
self._engine = sql.connect(**connection_details, **connection_args)
|
|
38
|
+
self._conn = self._engine.cursor()
|
|
39
|
+
|
|
40
|
+
def create_transaction(self) -> None:
|
|
41
|
+
"""Autocommit = False by default. One can change this directly by setting the option in the >connection< dictionary."""
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
def _check_table_exists(self, tableName, schema):
|
|
45
|
+
tableExists = False
|
|
46
|
+
rawTableName = self._strip_escape_chars(
|
|
47
|
+
tableName=tableName, quote_chars=self.QUOTE_CHAR
|
|
48
|
+
)
|
|
49
|
+
for ele in self._conn.tables().fetchall():
|
|
50
|
+
if ele[2].lower() == rawTableName.lower():
|
|
51
|
+
tableExists = True
|
|
52
|
+
|
|
53
|
+
return tableExists
|
|
54
|
+
|
|
55
|
+
def _create_table(self, df, tableName, schema, ifExists, **kwargs):
|
|
56
|
+
"""
|
|
57
|
+
Drops an exisiting table and creates a new table with the same name. Uses specific SQL queries for each DBMS flavour.
|
|
58
|
+
"""
|
|
59
|
+
dtype_map: dict = kwargs["dtype_map"]
|
|
60
|
+
col_encloser: str = kwargs["columnEncloser"]
|
|
61
|
+
tableCols = ""
|
|
62
|
+
for col, dtype in df.dtypes.items():
|
|
63
|
+
new_col = (
|
|
64
|
+
f"{col_encloser[0]}{col}{col_encloser[1]}"
|
|
65
|
+
if len(col_encloser) > 1
|
|
66
|
+
else f"{col_encloser[0]}{col}{col_encloser[0]}"
|
|
67
|
+
)
|
|
68
|
+
if dtype == "float64":
|
|
69
|
+
tableCols += f"{new_col} {dtype_map.get('float', 'FLOAT')},"
|
|
70
|
+
elif dtype == "int64":
|
|
71
|
+
tableCols += f"{new_col} {dtype_map.get('integer', 'BIGINT')},"
|
|
72
|
+
elif dtype in ["object", "category"]:
|
|
73
|
+
tableCols += f"{new_col} {dtype_map.get('text', 'TEXT')},"
|
|
74
|
+
|
|
75
|
+
tableCols = tableCols[:-1]
|
|
76
|
+
|
|
77
|
+
if schema:
|
|
78
|
+
tableName = schema + "." + tableName
|
|
79
|
+
|
|
80
|
+
if ifExists == "replace":
|
|
81
|
+
try:
|
|
82
|
+
if self._check_table_exists(tableName, schema=None):
|
|
83
|
+
self._conn.execute(f"""DROP TABLE {tableName};""")
|
|
84
|
+
except Exception as e:
|
|
85
|
+
self._raise_error(
|
|
86
|
+
f"Cannot drop table >{tableName}<.\nException from {type(e).__module__}: {type(e).__name__}> {e}"
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
self._conn.execute(f"""CREATE TABLE {tableName}({tableCols});""")
|
|
90
|
+
|
|
91
|
+
if self._traceValue > 1:
|
|
92
|
+
self._traceLog(
|
|
93
|
+
f"Created new table: >{tableName}< with columns: >{tableCols}<"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
def _insert_data(self, df: pd.DataFrame, writeFunction_args: dict) -> None:
|
|
97
|
+
placeHolder = "?," * (len(df.columns) - 1)
|
|
98
|
+
tableName = writeFunction_args["name"]
|
|
99
|
+
if df.isnull().values.any(): # replace NaN with None, for SQL NULL
|
|
100
|
+
df = df.astype(object).where(pd.notnull(df), None)
|
|
101
|
+
df_list = list(df.itertuples(index=False, name=None))
|
|
102
|
+
if writeFunction_args["schema"]:
|
|
103
|
+
tableName = writeFunction_args["schema"] + "." + tableName
|
|
104
|
+
query = f"INSERT INTO {tableName} VALUES(" + placeHolder + "?)"
|
|
105
|
+
|
|
106
|
+
if len(df_list) > 0:
|
|
107
|
+
self._conn.executemany(query, df_list)
|
|
108
|
+
|
|
109
|
+
elif self._traceValue > 1:
|
|
110
|
+
self._traceLog(
|
|
111
|
+
f"Empty symbol. No rows were inserted in table >{tableName}<."
|
|
112
|
+
)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#
|
|
2
|
+
# GAMS - General Algebraic Modeling System Python API
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2017-2026 GAMS Development Corp. <support@gams.com>
|
|
5
|
+
# Copyright (c) 2017-2026 GAMS Software GmbH <support@gams.com>
|
|
6
|
+
#
|
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
# in the Software without restriction, including without limitation the rights
|
|
10
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
# furnished to do so, subject to the following conditions:
|
|
13
|
+
#
|
|
14
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
# copies or substantial portions of the Software.
|
|
16
|
+
#
|
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
# SOFTWARE.
|
|
24
|
+
#
|
|
25
|
+
|
|
26
|
+
import pandas as pd
|
|
27
|
+
from gams.connect.agents._sqlconnectors._databasehandler import DatabaseConnector
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class SQLAlchemyConnector(DatabaseConnector):
|
|
31
|
+
SUPPORTED_INSERT_METHODS = ["default"]
|
|
32
|
+
|
|
33
|
+
def connect(self, connection_details, connection_args, **kwargs) -> None:
|
|
34
|
+
import sqlalchemy
|
|
35
|
+
|
|
36
|
+
con_str = sqlalchemy.engine.URL.create(**connection_details)
|
|
37
|
+
self._engine = sqlalchemy.create_engine(con_str, **connection_args)
|
|
38
|
+
self._conn = self._engine.connect()
|
|
39
|
+
|
|
40
|
+
def create_transaction(self) -> None:
|
|
41
|
+
self._conn.begin()
|
|
42
|
+
|
|
43
|
+
def read_table(self, sql_query: str, read_sql_args: dict) -> pd.DataFrame:
|
|
44
|
+
return pd.read_sql(sql=sql_query, con=self._conn, **read_sql_args)
|
|
45
|
+
|
|
46
|
+
def _execute_write(
|
|
47
|
+
self,
|
|
48
|
+
df: pd.DataFrame,
|
|
49
|
+
writeFunction_args: dict,
|
|
50
|
+
):
|
|
51
|
+
to_sql_args = {
|
|
52
|
+
key: writeFunction_args[key]
|
|
53
|
+
for key in ["name", "schema", "if_exists", "index"]
|
|
54
|
+
}
|
|
55
|
+
to_sql_args.update(writeFunction_args["toSQLArguments"])
|
|
56
|
+
df.to_sql(con=self._conn, **to_sql_args)
|
|
57
|
+
|
|
58
|
+
def commit(self):
|
|
59
|
+
self._conn.commit()
|
|
60
|
+
|
|
61
|
+
def rollback(self):
|
|
62
|
+
self._conn.rollback()
|
|
63
|
+
|
|
64
|
+
def close(self):
|
|
65
|
+
self._engine.dispose()
|
|
66
|
+
|
|
67
|
+
def _check_table_exists(self, tableName, schema):
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
def _create_table(self, df, tableName, schema, ifExists, **kwargs):
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
def _insert_data(self, df, writeFunction_args):
|
|
74
|
+
pass
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
#
|
|
2
|
+
# GAMS - General Algebraic Modeling System Python API
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2017-2026 GAMS Development Corp. <support@gams.com>
|
|
5
|
+
# Copyright (c) 2017-2026 GAMS Software GmbH <support@gams.com>
|
|
6
|
+
#
|
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
# in the Software without restriction, including without limitation the rights
|
|
10
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
# furnished to do so, subject to the following conditions:
|
|
13
|
+
#
|
|
14
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
# copies or substantial portions of the Software.
|
|
16
|
+
#
|
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
# SOFTWARE.
|
|
24
|
+
#
|
|
25
|
+
|
|
26
|
+
import pandas as pd
|
|
27
|
+
from gams import transfer as gt
|
|
28
|
+
from gams.connect.agents._sqlconnectors._databasehandler import DatabaseConnector
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class SQLiteConnector(DatabaseConnector):
|
|
32
|
+
SUPPORTED_INSERT_METHODS = ["default"]
|
|
33
|
+
QUOTE_CHAR = ["[]", '""', "``"]
|
|
34
|
+
|
|
35
|
+
def connect(self, connection_details, connection_args, **kwargs) -> None:
|
|
36
|
+
|
|
37
|
+
import sqlite3 as sql
|
|
38
|
+
|
|
39
|
+
isWrite: bool = kwargs.get("isWrite", True)
|
|
40
|
+
self._globalCommit: bool = kwargs.get("_sqlitewrite_globalCommit", False)
|
|
41
|
+
self._smallFlag: bool = kwargs.get("small", False)
|
|
42
|
+
self._fastFlag: bool = kwargs.get("fast", False)
|
|
43
|
+
|
|
44
|
+
if isWrite:
|
|
45
|
+
from pathlib import Path
|
|
46
|
+
|
|
47
|
+
if self._smallFlag and Path(connection_details["database"]).is_file():
|
|
48
|
+
self._raise_error(
|
|
49
|
+
f"SQLite database file >{connection_details['database']}< already exists.\
|
|
50
|
+
Option small can only be enabled when writing a new SQLite database file."
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
self._engine = sql.connect(**connection_details, **connection_args)
|
|
54
|
+
self._conn = self._engine.cursor()
|
|
55
|
+
|
|
56
|
+
if self._fastFlag and isWrite:
|
|
57
|
+
self._special_pragma_control()
|
|
58
|
+
|
|
59
|
+
def _special_pragma_control(self):
|
|
60
|
+
### Needs to be done before the beginning of a transaction
|
|
61
|
+
### Tried the following PRAGMAs but little to no effect:
|
|
62
|
+
### PRAGMA threads = 8; SQLite 3.15+
|
|
63
|
+
### PRAGMA cache_size = -200000;
|
|
64
|
+
### PRAGMA temp_store = MEMORY; for temporary objects
|
|
65
|
+
self._conn.execute("PRAGMA synchronous = OFF;")
|
|
66
|
+
self._conn.execute("PRAGMA journal_mode = OFF;")
|
|
67
|
+
|
|
68
|
+
def create_transaction(self) -> None:
|
|
69
|
+
self._conn.execute("BEGIN")
|
|
70
|
+
|
|
71
|
+
def _check_table_exists(self, tableName: str, schema: str | None) -> bool:
|
|
72
|
+
tableExists = False
|
|
73
|
+
rawTableName = self._strip_escape_chars(
|
|
74
|
+
tableName=tableName, quote_chars=self.QUOTE_CHAR
|
|
75
|
+
)
|
|
76
|
+
query = f"""SELECT name FROM sqlite_master WHERE type='table' AND name='{rawTableName}'"""
|
|
77
|
+
self._conn.execute(query)
|
|
78
|
+
|
|
79
|
+
res = self._conn.fetchone()
|
|
80
|
+
|
|
81
|
+
# TODO: check type(res) for sqlite
|
|
82
|
+
### res can be = (obj,) | None | (None,)
|
|
83
|
+
if isinstance(res, tuple):
|
|
84
|
+
if res[0]:
|
|
85
|
+
tableExists = True
|
|
86
|
+
|
|
87
|
+
return tableExists
|
|
88
|
+
|
|
89
|
+
def _sqlite_create_uel_table(self, cc: gt.Container):
|
|
90
|
+
"""
|
|
91
|
+
Fetches the UELs in use for each symbol and creates a mapping from each UEL to an integer.
|
|
92
|
+
The UELs are then renamed to their corresponding integer mappings.
|
|
93
|
+
This function is SQLite specific and is called only when small=True.
|
|
94
|
+
|
|
95
|
+
Parameter:
|
|
96
|
+
cc (gt.Container): The input gt.Container containing symbols and UELs to process.
|
|
97
|
+
"""
|
|
98
|
+
uel_list = cc.getUELs(ignore_unused=True)
|
|
99
|
+
uel_list = pd.Series(
|
|
100
|
+
data=[str(i) for i in range(1, len(uel_list) + 1)], index=uel_list
|
|
101
|
+
)
|
|
102
|
+
cc.renameUELs(uel_list.to_dict(), allow_merge=True)
|
|
103
|
+
self._uel_table_df = uel_list.reset_index()
|
|
104
|
+
self._uel_table_df.columns = ["uni", "element_text"]
|
|
105
|
+
|
|
106
|
+
def _sqlite_create_view(self, viewName, dim, df_cols):
|
|
107
|
+
"""
|
|
108
|
+
Creates user-friendly SQL views with the same name as the original table provided for the symbols.
|
|
109
|
+
If the column headers are part of the UEL table, they are mapped to their corresponding names in the views.
|
|
110
|
+
This function is SQLite specific and is called only when small=True.
|
|
111
|
+
|
|
112
|
+
Parameter:
|
|
113
|
+
viewName (str) : The original table name to be used as the name for the view.
|
|
114
|
+
dim (int) : Dimension of the symbol
|
|
115
|
+
df_cols (list) : Columns of the symbol
|
|
116
|
+
"""
|
|
117
|
+
cols_to_match = df_cols[:dim]
|
|
118
|
+
numeric_cols = {ele: ele for ele in df_cols[dim:]}
|
|
119
|
+
match_headers = self._uel_table_df[
|
|
120
|
+
self._uel_table_df["element_text"].isin(numeric_cols.keys())
|
|
121
|
+
]
|
|
122
|
+
match_headers = match_headers.set_index("element_text")["uni"].to_dict()
|
|
123
|
+
numeric_cols.update(match_headers)
|
|
124
|
+
tableName = f"[{viewName}$]"
|
|
125
|
+
select_query = ", ".join(
|
|
126
|
+
[f"UEL{i}.[uni] AS [{ele}]" for i, ele in enumerate(cols_to_match, 1)]
|
|
127
|
+
+ [
|
|
128
|
+
f"{tableName}.[{key}] AS [{col_name}]"
|
|
129
|
+
for key, col_name in numeric_cols.items()
|
|
130
|
+
]
|
|
131
|
+
)
|
|
132
|
+
join_query = "".join(
|
|
133
|
+
[
|
|
134
|
+
f"\nINNER JOIN [UEL$] AS UEL{i} ON {tableName}.[{ele}] = UEL{i}.[element_text]"
|
|
135
|
+
for i, ele in enumerate(cols_to_match, 1)
|
|
136
|
+
]
|
|
137
|
+
)
|
|
138
|
+
final_query = f"CREATE VIEW [{viewName}] AS SELECT {select_query} FROM {tableName} {join_query};"
|
|
139
|
+
try:
|
|
140
|
+
self._conn.execute(f"DROP VIEW IF EXISTS [{viewName}];")
|
|
141
|
+
self._conn.execute(final_query)
|
|
142
|
+
except Exception as e:
|
|
143
|
+
self._raise_error(f"{e}")
|
|
144
|
+
|
|
145
|
+
def _create_table(
|
|
146
|
+
self,
|
|
147
|
+
df: pd.DataFrame,
|
|
148
|
+
tableName: str,
|
|
149
|
+
schema: str | None,
|
|
150
|
+
ifExists: str,
|
|
151
|
+
**kwargs,
|
|
152
|
+
) -> None:
|
|
153
|
+
"""
|
|
154
|
+
Drops an exisiting table and creates a new table with the same name. Uses specific SQL queries for each DBMS flavour.
|
|
155
|
+
"""
|
|
156
|
+
|
|
157
|
+
if tableName == "[UEL$]":
|
|
158
|
+
self._conn.execute(
|
|
159
|
+
"""CREATE TABLE [UEL$]( uni TEXT, element_text INTEGER PRIMARY KEY ASC);"""
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
if self._traceValue > 1:
|
|
163
|
+
self._traceLog(f"Created new table: >{tableName}<.")
|
|
164
|
+
else:
|
|
165
|
+
tableCols = ""
|
|
166
|
+
for col, dtype in df.dtypes.items():
|
|
167
|
+
if dtype == "float64":
|
|
168
|
+
tableCols += f"[{col}] FLOAT,"
|
|
169
|
+
elif dtype == "int64":
|
|
170
|
+
tableCols += f"[{col}] BIGINT,"
|
|
171
|
+
elif dtype in ["object", "category"]:
|
|
172
|
+
tableCols += f"[{col}] VARCHAR(255),"
|
|
173
|
+
|
|
174
|
+
tableCols = tableCols[:-1]
|
|
175
|
+
|
|
176
|
+
if schema:
|
|
177
|
+
tableName = schema + "." + tableName
|
|
178
|
+
|
|
179
|
+
if ifExists == "replace":
|
|
180
|
+
try:
|
|
181
|
+
self._conn.execute(f"""DROP TABLE IF EXISTS {tableName};""")
|
|
182
|
+
except Exception as e:
|
|
183
|
+
self._raise_error(
|
|
184
|
+
f"Cannot drop table >{tableName}<.\nException from {type(e).__module__}: {type(e).__name__}> {e}"
|
|
185
|
+
)
|
|
186
|
+
self._conn.execute(f"""CREATE TABLE {tableName}({tableCols});""")
|
|
187
|
+
|
|
188
|
+
if self._traceValue > 1:
|
|
189
|
+
self._traceLog(
|
|
190
|
+
f"Created new table: >{tableName}< with columns: >{tableCols}<"
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
def _insert_data(self, df: pd.DataFrame, writeFunction_args: dict):
|
|
194
|
+
placeHolder = "?," * (len(df.columns) - 1)
|
|
195
|
+
tableName = writeFunction_args["name"]
|
|
196
|
+
if df.isnull().values.any(): # replace NaN with None, for SQL NULL
|
|
197
|
+
df = df.astype(object).where(pd.notnull(df), None)
|
|
198
|
+
df_list = list(
|
|
199
|
+
df.itertuples(index=False, name=None)
|
|
200
|
+
) # sql server does not accept nested lists, it has to be tuples
|
|
201
|
+
if writeFunction_args["schema"]:
|
|
202
|
+
tableName = writeFunction_args["schema"] + "." + tableName
|
|
203
|
+
query = f"INSERT INTO {tableName} VALUES(" + placeHolder + "?)"
|
|
204
|
+
if len(df_list) > 0:
|
|
205
|
+
self._conn.executemany(query, df_list)
|
|
206
|
+
|
|
207
|
+
elif self._traceValue > 1:
|
|
208
|
+
self._traceLog(
|
|
209
|
+
f"Empty symbol. No rows were inserted in table >{tableName}<."
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
def pre_write_procedures(self, **kwargs) -> gt.Container:
|
|
213
|
+
try:
|
|
214
|
+
container = kwargs["container"]
|
|
215
|
+
directory = kwargs["directory"]
|
|
216
|
+
sym_list = kwargs["sym_list"]
|
|
217
|
+
except KeyError as e:
|
|
218
|
+
self._raise_error(f"Key error in pre_write_procedures: {e}.")
|
|
219
|
+
|
|
220
|
+
if self._smallFlag:
|
|
221
|
+
write_container = gt.Container(system_directory=directory)
|
|
222
|
+
write_container.read(container, symbols=sym_list)
|
|
223
|
+
self._conn.execute("PRAGMA page_size = 1024;")
|
|
224
|
+
self._sqlite_create_uel_table(cc=write_container)
|
|
225
|
+
self._create_table(
|
|
226
|
+
df=self._uel_table_df,
|
|
227
|
+
tableName="[UEL$]",
|
|
228
|
+
schema=None,
|
|
229
|
+
ifExists="fail",
|
|
230
|
+
)
|
|
231
|
+
self._insert_data(
|
|
232
|
+
df=self._uel_table_df,
|
|
233
|
+
writeFunction_args={
|
|
234
|
+
"name": "[UEL$]",
|
|
235
|
+
"schema": None,
|
|
236
|
+
},
|
|
237
|
+
)
|
|
238
|
+
if not self._globalCommit:
|
|
239
|
+
self._engine.commit()
|
|
240
|
+
|
|
241
|
+
return write_container
|
|
242
|
+
|
|
243
|
+
elif self._check_table_exists(tableName="UEL$", schema=None):
|
|
244
|
+
message = (
|
|
245
|
+
"WARNING: The table >UEL$< already exists in the database file. "
|
|
246
|
+
"It appears that the database was created with the small option enabled. "
|
|
247
|
+
"Appending to or replacing a pre-existing table may lead to unexpected results."
|
|
248
|
+
)
|
|
249
|
+
self._traceLog(message)
|
|
250
|
+
|
|
251
|
+
return container
|
|
252
|
+
|
|
253
|
+
def post_write_procedures(self, **kwargs) -> None:
|
|
254
|
+
tableName = kwargs["tableName"]
|
|
255
|
+
dim_after_unstack = kwargs["dim_after_unstack"]
|
|
256
|
+
colList = kwargs["colList"]
|
|
257
|
+
dim = kwargs["dim"]
|
|
258
|
+
# After the parent tables <tableName$> are created. Views for the symbol name are to be created.
|
|
259
|
+
if self._smallFlag and dim > 0:
|
|
260
|
+
self._sqlite_create_view(
|
|
261
|
+
viewName=tableName, dim=dim_after_unstack, df_cols=colList
|
|
262
|
+
)
|