Raw SQL within Pylons app that uses SQLAlchemy? - sqlalchemy

I've inherited a Pylons app that uses SQLAlchemy. I know nothing about SQLAlchemy and very little about Pylons :)
I need to run some raw SQL from within the app. The SQLAlchemy currently seems to be working in the following way (example code):
import myapp.model as model
model.Session.query(model.KeyValue) # existing code
.join(model.Key)
.filter(model.Key.name == name)
).count() == 0, name
How do I get it to run raw SQL? I see that I need an execute() statement, but how exactly do I run it? The following both fail:
model.Session.execute('create table hello_world;')
model.Connection.execute("""
create table hello_world;
""")
What's the magic invocation? There's no reference to a Connection object in the existing code, and I'm not sure how to create one.

You can obtain connection that is used by Session by using its connection method:
connection = model.Session.connection()
Then you can issue your query:
connection.execute('create table hello_world;')
Note that in Pylons model.Session is not a sqlalchemy.orm.session.Session class. It's an instance of sqlalchemy.orm.scoping.ScopedSession. That's how it's created in model.meta module:
Session = scoped_session(sessionmaker())

My first impulse is to recommend trying the execute() method of an instance of Connection, instead of the execute() method of the class itself as your example code suggests that you're doing.
Are you working off of the Pylons Book examples ?

Related

SQLAlchemy - Unable to reflect SQL view

I'm getting the following error message when trying to reflect any of my SQL views:
sqlalchemy/dialects/mysql/reflection.py", line 306, in _describe_to_create
buffer.append(" ".join(line))
TypeError: sequence item 2: expected str instance, bytes found
I have tried using both the autoload_with and autoload=True options in my select query constructor to no avail.
I have the appropriate permissions on my view. My query is pretty simple:
company_country = Table('company_country', metadata, autoload_with=engine)
query = select(company_country.c.country)
return query
I've tried the inspect utility and it does not list my SQL view, nor does the reflecting all tables described below the views section on this page: https://docs.sqlalchemy.org/en/14/core/reflection.html#reflecting-views
I'm using version SQLAlchemy->1.4.32, Python 3.x and mySQL 8.0.28 on Mac if that's any help
I should add that I can query my SQL views using the text() constructor but it would be far more preferable to use select() if possible.
Any tips appreciated
I was using the mysql-connector client for interop with other code, but after switching to the mysqlclient, I was able to reflect the views.
https://docs.sqlalchemy.org/en/14/dialects/mysql.html#module-sqlalchemy.dialects.mysql.mysqldb

How to get max_allocated_packets from JDBC connection from a Slick DB connection to MySQL

Is there a way via Scala with Slick database query and access library (or using other tricks - dare I say mocks?) to get max_allocated_packets from JDBC-read connection properties from a Slick-style DB connection to MySQL?
As I suspect, the code makes several touch type actions at deeper levels and this connection property is then populated.
Ex: Once a connection is made in com.mysql.cj.jdbc.ConnectionImpl ... using Scala with the Slick library... the value for the JDBC connect property of max_allocated_packets is within the object (debugged in IntelliJ). How can I extract this value or obtain it in higher level code as asked above?
Of course I can query the DB directly to get that value, but I am hoping I can extract this property after the setup phase.
If the value is publically available on a connection, you could try to use SimpleDBIO action to access the JDBC-level values.
See: https://scala-slick.org/doc/3.2.0/dbio.html#jdbc-interoperability
It would be of the form:
val getMaxPacketAction = SimpleDBIO[Int] { database =>
// make use of database.connection here
}
However, this is still going to the database for a connection, so it may be just easier to query for the value you want.

In strapi, that is configured to use MySql, how do I create a new content type record in the code?

y'all,
Within my custom, strapi content type, controller code, what method in the model object do I use to create a new record? My app is configured to use MySql.
The following worked fine when I was using MongoDB, but now with MySql, it doesn't work.
With Mongo, in my code, I was doing this:
let model = strapi.models[modelName];
await model.create({"Name":"<NEW ENTRY>", "Path":ruleData.requestedPath});
, but now, with MySql, I get an error saying that model.create() is not a function. 🤔
Also, when I step into the code, create() is no longer there. I also can't seem to find the equivalent "create" method in the model object, for mysql.
??? Does the strapi ORM, model object change member functions, etc when moving from MongoDB to MySql??? I thought not since that was a big part of the reason for using the ORM.
I suggest you use strapi.query('article') instead of strapi.models.article
So it will be strapi.query('article').create({...})

For django testing, how do I use keepdb with mariadb

I have a database with a lot of nonmanaged tables which I'm using for a django app. For testing I'm wanting to use the --keepdb option so that I don't have to repopulate these tables every time. I'm using MariaDB for my database. If I don't use the keepdb option everything works fine, the test database gets created and destroyed properly.
But when I try to run the test keeping the database:
$ python manage.py test --keepdb
I get the following error:
Using existing test database for alias 'default'...
Got an error creating the test database: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CREATE DATABASE IF NOT EXISTS test_livedb ;\n SET sql_note' at line 2")
I assume that this is an issue with a different syntax between MariaDB and MySQL. Is there anyway to get the keepdb option to work with MariaDB?
thanks very much!
For what it's worth: This bug was introduced in Django 2.0.0 and fixed in Django 2.1.3 (https://code.djangoproject.com/ticket/29827)
Two things - check out Factory Boy (for creating test data) and I would suggest checking out Pytest as well. With non-managed tables, the issue I think you'll run into is that (at least in my experience) django won't create them in the test environment and you end up running into issues because there is no migration file to create those tables (since they're unmanaged). Django runs the migration files when creating the test environment.
With Pytest you can run with a --nomigrations flag which builds your test database directly off the models (thus creating the tables you need for your unmanaged models).
If you combine Pytest and Factory Boy you should be able to come up with the ability to setup your test data so it works as expected, is repeatable and testable without issue.
I actually approach it like this (slightly hacky, but it works with our complex setup):
On my model:
class Meta(object):
db_table = 'my_custom_table'
managed = getattr(settings, 'UNDER_TEST', False)
I create the UNDER_TEST variable in settings.py like this:
# Create global variable that will tell if our application is under test
UNDER_TEST = (len(sys.argv) > 1 and sys.argv[1] == 'test')
That way - when the application is UNDER_TEST the model is marked as managed (and Pytest will create the appropriate DB table). Then FactoryBoy handles putting all my test data into that table (either in setUp of the test or elsewhere) so I can test against it.
That's my suggestion - others might have something a little more clear or cleaner.

Adding output converter to pyodbc connection in SQLAlchemy

using:
Python 2.7.3
SQLAlchemy 0.7.8
PyODBC 3.0.3
I have implemented my own Dialect for the EXASolution DB using PyODBC as the underlying db driver. I need to make use of PyODBC's output_converter function to translate DECIMAL(x, 0) columns to integers/longs.
The following code snippet does the trick:
pyodbc = self.dbapi
dbapi_con = connection.connection
dbapi_version = dbapi_con.getinfo(pyodbc.SQL_DRIVER_VER)
(major, minor, patch) = [int(x) for x in dbapi_version]
if major >= 3:
dbapi_con.add_output_converter(pyodbc.SQL_DECIMAL, self.decimal2int)
I have placed this code snippet in the initialize(self, connection) method of
class EXADialect_pyodbc(PyODBCConnector, EXADialect):
Code gets called, and no exception is thrown, but this is a one time initialization. Later on, other connections are created. These connections are not passed through my initialization code.
Does anyone have a hint on how connection initialization works with SQLAlchemy, and where to place my code so that it gets called for every new connection created?
This is an old question, but something I hit recently, so an updated answer may help someone else along the way. In my case, I was trying to automatically downcase mssql UNIQUEIDENTIFIER columns (guids).
You can grab the raw connection (pyodbc) through the session or engine to do this:
engine = create_engine(connection_string)
make_session = sessionmaker(engine)
...
session = make_session()
session.connection().connection.add_output_converter(SQL_DECIMAL, decimal2int)
# or
connection = engine.connect().connection
connection.add_output_converter(SQL_DECIMAL, decimal2int)