initial draft
This commit is contained in:
9
.travis.yml
Normal file
9
.travis.yml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
language: python
|
||||||
|
python:
|
||||||
|
- 2.5
|
||||||
|
- 2.6
|
||||||
|
- 2.7
|
||||||
|
install:
|
||||||
|
- pip install -q -e . --use-mirrors
|
||||||
|
script:
|
||||||
|
- python setup.py test
|
10
CHANGES.rst
Normal file
10
CHANGES.rst
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Changelog
|
||||||
|
---------
|
||||||
|
|
||||||
|
Various utility functions that I use alongside SQLAlchemy.
|
||||||
|
|
||||||
|
|
||||||
|
0.1.0 (12.1.2013)
|
||||||
|
^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
- Initial public release
|
27
LICENSE
Normal file
27
LICENSE
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
Copyright (c) 2012, Konsta Vesterinen
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
* The names of the contributors may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT,
|
||||||
|
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||||
|
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
7
MANIFEST.in
Normal file
7
MANIFEST.in
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
include CHANGES.rst LICENSE README.rst
|
||||||
|
recursive-include tests *
|
||||||
|
recursive-exclude tests *.pyc
|
||||||
|
recursive-include docs *
|
||||||
|
recursive-exclude docs *.pyc
|
||||||
|
prune docs/_build
|
||||||
|
exclude docs/_themes/.git
|
@@ -1,4 +0,0 @@
|
|||||||
sqlalchemy-utils
|
|
||||||
================
|
|
||||||
|
|
||||||
Various utility functions that I use alongside SQLAlchemy.
|
|
12
README.rst
Normal file
12
README.rst
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
SQLAlchemy-Utils
|
||||||
|
================
|
||||||
|
|
||||||
|
Various utility functions that I use alongside SQLAlchemy.
|
||||||
|
|
||||||
|
|
||||||
|
Resources
|
||||||
|
---------
|
||||||
|
|
||||||
|
- `Documentation <http://sqlalchemy-utils.readthedocs.org/>`_
|
||||||
|
- `Issue Tracker <http://github.com/kvesteri/sqlalchemy-utils/issues>`_
|
||||||
|
- `Code <http://github.com/kvesteri/sqlalchemy-utils/>`_
|
5
requirements-dev.txt
Normal file
5
requirements-dev.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
-r requirements.txt
|
||||||
|
pytest==2.2.3
|
||||||
|
Pygments==1.2
|
||||||
|
Jinja2==2.3
|
||||||
|
docutils>=0.10
|
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
SQLAlchemy==0.7.8
|
53
setup.py
Normal file
53
setup.py
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
"""
|
||||||
|
SQLAlchemy-Searchable
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Various utility functions I use with SQLAlchemy.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from setuptools import setup, Command
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
class PyTest(Command):
|
||||||
|
user_options = []
|
||||||
|
|
||||||
|
def initialize_options(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def finalize_options(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
errno = subprocess.call(['py.test'])
|
||||||
|
raise SystemExit(errno)
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='SQLAlchemy-Utils',
|
||||||
|
version='0.1',
|
||||||
|
url='https://github.com/kvesteri/sqlalchemy-utils',
|
||||||
|
license='BSD',
|
||||||
|
author='Konsta Vesterinen',
|
||||||
|
author_email='konsta@fastmonkeys.com',
|
||||||
|
description=(
|
||||||
|
'Various utility functions I use with SQLAlchemy.'
|
||||||
|
),
|
||||||
|
long_description=__doc__,
|
||||||
|
packages=['sqlalchemy_utils'],
|
||||||
|
zip_safe=False,
|
||||||
|
include_package_data=True,
|
||||||
|
platforms='any',
|
||||||
|
install_requires=[
|
||||||
|
'SQLAlchemy==0.7.8',
|
||||||
|
],
|
||||||
|
cmdclass={'test': PyTest},
|
||||||
|
classifiers=[
|
||||||
|
'Environment :: Web Environment',
|
||||||
|
'Intended Audience :: Developers',
|
||||||
|
'License :: OSI Approved :: BSD License',
|
||||||
|
'Operating System :: OS Independent',
|
||||||
|
'Programming Language :: Python',
|
||||||
|
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
|
||||||
|
'Topic :: Software Development :: Libraries :: Python Modules'
|
||||||
|
]
|
||||||
|
)
|
71
sqlalchemy_utils/__init__.py
Normal file
71
sqlalchemy_utils/__init__.py
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
from flask import request
|
||||||
|
from sqlalchemy.orm.mapper import Mapper
|
||||||
|
from sqlalchemy.orm.query import _ColumnEntity
|
||||||
|
from sqlalchemy.sql.expression import desc, asc
|
||||||
|
|
||||||
|
|
||||||
|
def sort_query(query, sort):
|
||||||
|
"""
|
||||||
|
Applies an sql ORDER BY for given query
|
||||||
|
|
||||||
|
:param query: query to be modified
|
||||||
|
:param sort: string that defines the label or column to sort the query by
|
||||||
|
"""
|
||||||
|
entities = [entity.entity_zero.class_ for entity in query._entities]
|
||||||
|
for mapper in query._join_entities:
|
||||||
|
if isinstance(mapper, Mapper):
|
||||||
|
entities.append(mapper.class_)
|
||||||
|
else:
|
||||||
|
entities.append(mapper)
|
||||||
|
|
||||||
|
# get all label names for queries such as:
|
||||||
|
# db.session.query(Category, db.func.count(Article.id).label('articles'))
|
||||||
|
labels = []
|
||||||
|
for entity in query._entities:
|
||||||
|
if isinstance(entity, _ColumnEntity) and entity._label_name:
|
||||||
|
labels.append(entity._label_name)
|
||||||
|
|
||||||
|
sort = request.args.get('sort', sort)
|
||||||
|
if not sort:
|
||||||
|
return query
|
||||||
|
|
||||||
|
if sort[0] == '-':
|
||||||
|
func = desc
|
||||||
|
sort = sort[1:]
|
||||||
|
else:
|
||||||
|
func = asc
|
||||||
|
|
||||||
|
component = None
|
||||||
|
parts = sort.split('-')
|
||||||
|
if len(parts) > 1:
|
||||||
|
component = parts[0]
|
||||||
|
sort = parts[1]
|
||||||
|
if sort in labels:
|
||||||
|
query = query.order_by(func(sort))
|
||||||
|
else:
|
||||||
|
for entity in entities:
|
||||||
|
if component and entity.__table__.name != component:
|
||||||
|
continue
|
||||||
|
if sort in entity.__table__.columns:
|
||||||
|
try:
|
||||||
|
attr = getattr(entity, sort)
|
||||||
|
query = query.order_by(func(attr))
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
break
|
||||||
|
return query
|
||||||
|
|
||||||
|
|
||||||
|
def escape_like(string, escape_char='*'):
|
||||||
|
"""
|
||||||
|
Escapes the string paremeter used in SQL LIKE expressions
|
||||||
|
|
||||||
|
:param string: a string to escape
|
||||||
|
:param escape_char: escape character
|
||||||
|
"""
|
||||||
|
return (
|
||||||
|
string
|
||||||
|
.replace(escape_char, escape_char * 2)
|
||||||
|
.replace('%', escape_char + '%')
|
||||||
|
.replace('_', escape_char + '_')
|
||||||
|
)
|
Reference in New Issue
Block a user