Truncate.
This commit is contained in:
parent
71d7bd95ad
commit
373542b61c
1 changed files with 3 additions and 239 deletions
|
@ -1,252 +1,16 @@
|
||||||
anosql
|
anosql
|
||||||
======
|
======
|
||||||
|
|
||||||
**NOTICE**: This project is now deprecated in favor of `aiosql`_.
|
|
||||||
|
|
||||||
Unfortunately, I no longer have the time to devote to this project, and aiosql
|
|
||||||
is now a lot more popular. I don't think it makes sense to maintain both.
|
|
||||||
Open source ftw! Thanks for your hard work, `Will`_!
|
|
||||||
|
|
||||||
.. _aiosql: https://github.com/nackjicholson/aiosql
|
|
||||||
.. _Will: https://github.com/nackjicholson
|
|
||||||
|
|
||||||
.. image:: https://badge.fury.io/py/anosql.svg
|
|
||||||
:target: https://badge.fury.io/py/anosql
|
|
||||||
:alt: pypi package version
|
|
||||||
|
|
||||||
.. image:: http://readthedocs.org/projects/anosql/badge/?version=latest
|
|
||||||
:target: http://anosql.readthedocs.io/en/latest/?badge=latest
|
|
||||||
:alt: Documentation Status
|
|
||||||
|
|
||||||
.. image:: https://travis-ci.org/honza/anosql.svg?branch=master
|
|
||||||
:target: https://travis-ci.org/honza/anosql
|
|
||||||
:alt: Travid build status
|
|
||||||
|
|
||||||
A Python library for using SQL
|
A Python library for using SQL
|
||||||
|
|
||||||
Inspired by the excellent `Yesql`_ library by Kris Jenkins. In my mother
|
Inspired by the excellent Yesql library by Kris Jenkins. In my mother tongue, ano means yes.
|
||||||
tongue, *ano* means *yes*.
|
|
||||||
|
|
||||||
If you are on python3.6+ or need ``anosql`` to work with ``asyncio``-based database drivers, see the related project, `aiosql <https://github.com/nackjicholson/aiosql>`_.
|
This is a vendored copy of `anosql`_, which exists to capture a few pre-deprecation patches that never made it into the last release, and bazel-ify everything for my use.
|
||||||
|
|
||||||
Complete documentation is available at `Read The Docs <https://anosql.readthedocs.io/en/latest/>`_.
|
|
||||||
|
|
||||||
Installation
|
|
||||||
------------
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ pip install anosql
|
|
||||||
|
|
||||||
Usage
|
|
||||||
-----
|
|
||||||
|
|
||||||
Basics
|
|
||||||
******
|
|
||||||
|
|
||||||
Given a ``queries.sql`` file:
|
|
||||||
|
|
||||||
.. code-block:: sql
|
|
||||||
|
|
||||||
-- name: get-all-greetings
|
|
||||||
-- Get all the greetings in the database
|
|
||||||
SELECT * FROM greetings;
|
|
||||||
|
|
||||||
-- name: select-users
|
|
||||||
-- Get all the users from the database,
|
|
||||||
-- and return it as a dict
|
|
||||||
SELECT * FROM USERS;
|
|
||||||
|
|
||||||
We can issue SQL queries, like so:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
import anosql
|
|
||||||
import psycopg2
|
|
||||||
import sqlite3
|
|
||||||
|
|
||||||
# PostgreSQL
|
|
||||||
conn = psycopg2.connect('...')
|
|
||||||
queries = anosql.from_path('queries.sql', 'psycopg2')
|
|
||||||
|
|
||||||
# Or, Sqlite3...
|
|
||||||
conn = sqlite3.connect('cool.db')
|
|
||||||
queries = anosql.from_path('queries.sql', 'sqlite3')
|
|
||||||
|
|
||||||
queries.get_all_greetings(conn)
|
|
||||||
# => [(1, 'en', 'Hi')]
|
|
||||||
|
|
||||||
queries.get_all_greetings.__doc__
|
|
||||||
# => Get all the greetings in the database
|
|
||||||
|
|
||||||
queries.get_all_greetings.sql
|
|
||||||
# => SELECT * FROM greetings;
|
|
||||||
|
|
||||||
queries.available_queries
|
|
||||||
# => ['get_all_greetings']
|
|
||||||
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
**********
|
|
||||||
|
|
||||||
Often, you want to change parts of the query dynamically, particularly values in
|
|
||||||
the ``WHERE`` clause. You can use parameters to do this:
|
|
||||||
|
|
||||||
.. code-block:: sql
|
|
||||||
|
|
||||||
-- name: get-greetings-for-language
|
|
||||||
-- Get all the greetings in the database for given language
|
|
||||||
SELECT *
|
|
||||||
FROM greetings
|
|
||||||
WHERE lang = %s;
|
|
||||||
|
|
||||||
And they become positional parameters:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
visitor_language = "en"
|
|
||||||
queries.get_greetings_for_language(conn, visitor_language)
|
|
||||||
# => [(1, 'en', 'Hi')]
|
|
||||||
|
|
||||||
|
|
||||||
One Row Query
|
|
||||||
*************
|
|
||||||
|
|
||||||
Often, you would expect at most one row from a query, so that getting a list
|
|
||||||
is not convenient. Appending ``?`` to the query name makes it return either one
|
|
||||||
tuple if it returned one row, or ``None`` in other cases.
|
|
||||||
|
|
||||||
.. code-block:: sql
|
|
||||||
|
|
||||||
-- name: get-a-greeting?
|
|
||||||
-- Get a greeting based on its id
|
|
||||||
SELECT *
|
|
||||||
FROM greetings
|
|
||||||
WHERE id = %s;
|
|
||||||
|
|
||||||
Then a tuple is returned:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
queries.get_a_greeting(conn, 1)
|
|
||||||
# => (1, 'en', 'Hi')
|
|
||||||
|
|
||||||
|
|
||||||
Named Parameters
|
|
||||||
****************
|
|
||||||
|
|
||||||
To make queries with many parameters more understandable and maintainable, you
|
|
||||||
can give the parameters names:
|
|
||||||
|
|
||||||
.. code-block:: sql
|
|
||||||
|
|
||||||
-- name: get-greetings-for-language-and-length
|
|
||||||
-- Get all the greetings in the database for given language and length
|
|
||||||
SELECT *
|
|
||||||
FROM greetings
|
|
||||||
WHERE lang = :lang
|
|
||||||
AND len(greeting) <= :length_limit;
|
|
||||||
|
|
||||||
If you were writing a Postgresql query, you could also format the parameters as
|
|
||||||
``%s(lang)`` and ``%s(length_limit)``.
|
|
||||||
|
|
||||||
Then, call your queries like you would any Python function with named
|
|
||||||
parameters:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
visitor_language = "en"
|
|
||||||
|
|
||||||
greetings_for_texting = queries.get_greetings_for_language_and_length(
|
|
||||||
conn, lang=visitor_language, length_limit=140)
|
|
||||||
|
|
||||||
Update/Insert/Delete
|
|
||||||
********************
|
|
||||||
|
|
||||||
In order to run ``UPDATE``, ``INSERT``, or ``DELETE`` statements, you need to
|
|
||||||
add ``!`` to the end of your query name. Anosql will then execute it properly.
|
|
||||||
It will also return the number of affected rows.
|
|
||||||
|
|
||||||
Insert queries returning autogenerated values
|
|
||||||
*********************************************
|
|
||||||
|
|
||||||
If you want the auto-generated primary key to be returned after you run an
|
|
||||||
insert query, you can add ``<!`` to the end of your query name.
|
|
||||||
|
|
||||||
.. code-block:: sql
|
|
||||||
|
|
||||||
-- name: create-user<!
|
|
||||||
INSERT INTO person (name) VALUES (:name)
|
|
||||||
|
|
||||||
Adding custom query loaders.
|
|
||||||
****************************
|
|
||||||
|
|
||||||
Out of the box, ``anosql`` supports SQLite and PostgreSQL via the stdlib ``sqlite3`` database driver
|
|
||||||
and ``psycopg2``. If you would like to extend ``anosql`` to communicate with other types of databases,
|
|
||||||
you may create a driver adapter class and register it with ``anosql.core.register_driver_adapter()``.
|
|
||||||
|
|
||||||
Driver adapters are duck-typed classes which adhere to the below interface. Looking at ``anosql/adapters`` package
|
|
||||||
is a good place to get started by looking at how the ``psycopg2`` and ``sqlite3`` adapters work.
|
|
||||||
|
|
||||||
To register a new loader::
|
|
||||||
|
|
||||||
import anosql
|
|
||||||
import anosql.core
|
|
||||||
|
|
||||||
class MyDbAdapter():
|
|
||||||
def process_sql(self, name, op_type, sql):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def select(self, conn, sql, parameters):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@contextmanager
|
|
||||||
def select_cursor(self, conn, sql, parameters):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def insert_update_delete(self, conn, sql, parameters):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def insert_update_delete_many(self, conn, sql, parameters):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def insert_returning(self, conn, sql, parameters):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def execute_script(self, conn, sql):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
anosql.core.register_driver_adapter("mydb", MyDbAdapter)
|
|
||||||
|
|
||||||
# To use make a connection to your db, and pass "mydb" as the db_type:
|
|
||||||
import mydbdriver
|
|
||||||
conn = mydbriver.connect("...")
|
|
||||||
|
|
||||||
anosql.load_queries("path/to/sql/", "mydb")
|
|
||||||
greetings = anosql.get_greetings(conn)
|
|
||||||
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
If your adapter constructor takes arguments, you can register a function which can build
|
|
||||||
your adapter instance::
|
|
||||||
|
|
||||||
def adapter_factory():
|
|
||||||
return MyDbAdapter("foo", 42)
|
|
||||||
|
|
||||||
anosql.register_driver_adapter("mydb", adapter_factory)
|
|
||||||
|
|
||||||
Tests
|
|
||||||
-----
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ pip install tox
|
|
||||||
$ tox
|
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
|
||||||
BSD, short and sweet
|
BSD, short and sweet
|
||||||
|
|
||||||
|
.. _anosql: https://github.com/honza/anosql
|
||||||
.. _Yesql: https://github.com/krisajenkins/yesql/
|
.. _Yesql: https://github.com/krisajenkins/yesql/
|
||||||
|
|
Loading…
Reference in a new issue