Added modular DAL, updated gluon imports to new structure
This commit is contained in:
@@ -0,0 +1,342 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import uuid
|
||||
import re
|
||||
|
||||
from .regex import REGEX_NOPASSWD, REGEX_UNPACK, REGEX_CONST_STRING, REGEX_W
|
||||
from .classes import SQLCustomType
|
||||
#from ..objects import Field, Table
|
||||
|
||||
|
||||
PLURALIZE_RULES = [
|
||||
(re.compile('child$'), re.compile('child$'), 'children'),
|
||||
(re.compile('oot$'), re.compile('oot$'), 'eet'),
|
||||
(re.compile('ooth$'), re.compile('ooth$'), 'eeth'),
|
||||
(re.compile('l[eo]af$'), re.compile('l([eo])af$'), 'l\\1aves'),
|
||||
(re.compile('sis$'), re.compile('sis$'), 'ses'),
|
||||
(re.compile('man$'), re.compile('man$'), 'men'),
|
||||
(re.compile('ife$'), re.compile('ife$'), 'ives'),
|
||||
(re.compile('eau$'), re.compile('eau$'), 'eaux'),
|
||||
(re.compile('lf$'), re.compile('lf$'), 'lves'),
|
||||
(re.compile('[sxz]$'), re.compile('$'), 'es'),
|
||||
(re.compile('[^aeioudgkprt]h$'), re.compile('$'), 'es'),
|
||||
(re.compile('(qu|[^aeiou])y$'), re.compile('y$'), 'ies'),
|
||||
(re.compile('$'), re.compile('$'), 's'),
|
||||
]
|
||||
|
||||
def pluralize(singular, rules=PLURALIZE_RULES):
|
||||
for line in rules:
|
||||
re_search, re_sub, replace = line
|
||||
plural = re_search.search(singular) and re_sub.sub(replace, singular)
|
||||
if plural: return plural
|
||||
|
||||
def hide_password(uri):
|
||||
if isinstance(uri,(list,tuple)):
|
||||
return [hide_password(item) for item in uri]
|
||||
return REGEX_NOPASSWD.sub('******',uri)
|
||||
|
||||
|
||||
def cleanup(text):
|
||||
"""
|
||||
Validates that the given text is clean: only contains [0-9a-zA-Z_]
|
||||
"""
|
||||
#if not REGEX_ALPHANUMERIC.match(text):
|
||||
# raise SyntaxError('invalid table or field name: %s' % text)
|
||||
return text
|
||||
|
||||
|
||||
def list_represent(x,r=None):
|
||||
return ', '.join(str(y) for y in x or [])
|
||||
|
||||
|
||||
def xorify(orderby):
|
||||
if not orderby:
|
||||
return None
|
||||
orderby2 = orderby[0]
|
||||
for item in orderby[1:]:
|
||||
orderby2 = orderby2 | item
|
||||
return orderby2
|
||||
|
||||
|
||||
def use_common_filters(query):
|
||||
return (query and hasattr(query,'ignore_common_filters') and \
|
||||
not query.ignore_common_filters)
|
||||
|
||||
|
||||
def bar_escape(item):
|
||||
return str(item).replace('|', '||')
|
||||
|
||||
|
||||
def bar_encode(items):
|
||||
return '|%s|' % '|'.join(bar_escape(item) for item in items if str(item).strip())
|
||||
|
||||
|
||||
def bar_decode_integer(value):
|
||||
if not hasattr(value,'split') and hasattr(value,'read'):
|
||||
value = value.read()
|
||||
return [long(x) for x in value.split('|') if x.strip()]
|
||||
|
||||
|
||||
def bar_decode_string(value):
|
||||
return [x.replace('||', '|') for x in
|
||||
REGEX_UNPACK.split(value[1:-1]) if x.strip()]
|
||||
|
||||
|
||||
def archive_record(qset, fs, archive_table, current_record):
|
||||
tablenames = qset.db._adapter.tables(qset.query)
|
||||
if len(tablenames) != 1:
|
||||
raise RuntimeError("cannot update join")
|
||||
for row in qset.select():
|
||||
fields = archive_table._filter_fields(row)
|
||||
fields[current_record] = row.id
|
||||
archive_table.insert(**fields)
|
||||
return False
|
||||
|
||||
|
||||
def smart_query(fields,text):
|
||||
from ..objects import Field, Table
|
||||
if not isinstance(fields,(list,tuple)):
|
||||
fields = [fields]
|
||||
new_fields = []
|
||||
for field in fields:
|
||||
if isinstance(field,Field):
|
||||
new_fields.append(field)
|
||||
elif isinstance(field,Table):
|
||||
for ofield in field:
|
||||
new_fields.append(ofield)
|
||||
else:
|
||||
raise RuntimeError("fields must be a list of fields")
|
||||
fields = new_fields
|
||||
field_map = {}
|
||||
for field in fields:
|
||||
n = field.name.lower()
|
||||
if not n in field_map:
|
||||
field_map[n] = field
|
||||
n = str(field).lower()
|
||||
if not n in field_map:
|
||||
field_map[n] = field
|
||||
constants = {}
|
||||
i = 0
|
||||
while True:
|
||||
m = REGEX_CONST_STRING.search(text)
|
||||
if not m: break
|
||||
text = text[:m.start()]+('#%i' % i)+text[m.end():]
|
||||
constants[str(i)] = m.group()[1:-1]
|
||||
i+=1
|
||||
text = re.sub('\s+',' ',text).lower()
|
||||
for a,b in [('&','and'),
|
||||
('|','or'),
|
||||
('~','not'),
|
||||
('==','='),
|
||||
('<','<'),
|
||||
('>','>'),
|
||||
('<=','<='),
|
||||
('>=','>='),
|
||||
('<>','!='),
|
||||
('=<','<='),
|
||||
('=>','>='),
|
||||
('=','='),
|
||||
(' less or equal than ','<='),
|
||||
(' greater or equal than ','>='),
|
||||
(' equal or less than ','<='),
|
||||
(' equal or greater than ','>='),
|
||||
(' less or equal ','<='),
|
||||
(' greater or equal ','>='),
|
||||
(' equal or less ','<='),
|
||||
(' equal or greater ','>='),
|
||||
(' not equal to ','!='),
|
||||
(' not equal ','!='),
|
||||
(' equal to ','='),
|
||||
(' equal ','='),
|
||||
(' equals ','='),
|
||||
(' less than ','<'),
|
||||
(' greater than ','>'),
|
||||
(' starts with ','startswith'),
|
||||
(' ends with ','endswith'),
|
||||
(' not in ' , 'notbelongs'),
|
||||
(' in ' , 'belongs'),
|
||||
(' is ','=')]:
|
||||
if a[0]==' ':
|
||||
text = text.replace(' is'+a,' %s ' % b)
|
||||
text = text.replace(a,' %s ' % b)
|
||||
text = re.sub('\s+',' ',text).lower()
|
||||
text = re.sub('(?P<a>[\<\>\!\=])\s+(?P<b>[\<\>\!\=])','\g<a>\g<b>',text)
|
||||
query = field = neg = op = logic = None
|
||||
for item in text.split():
|
||||
if field is None:
|
||||
if item == 'not':
|
||||
neg = True
|
||||
elif not neg and not logic and item in ('and','or'):
|
||||
logic = item
|
||||
elif item in field_map:
|
||||
field = field_map[item]
|
||||
else:
|
||||
raise RuntimeError("Invalid syntax")
|
||||
elif not field is None and op is None:
|
||||
op = item
|
||||
elif not op is None:
|
||||
if item.startswith('#'):
|
||||
if not item[1:] in constants:
|
||||
raise RuntimeError("Invalid syntax")
|
||||
value = constants[item[1:]]
|
||||
else:
|
||||
value = item
|
||||
if field.type in ('text', 'string', 'json'):
|
||||
if op == '=': op = 'like'
|
||||
if op == '=': new_query = field==value
|
||||
elif op == '<': new_query = field<value
|
||||
elif op == '>': new_query = field>value
|
||||
elif op == '<=': new_query = field<=value
|
||||
elif op == '>=': new_query = field>=value
|
||||
elif op == '!=': new_query = field!=value
|
||||
elif op == 'belongs': new_query = field.belongs(value.split(','))
|
||||
elif op == 'notbelongs': new_query = ~field.belongs(value.split(','))
|
||||
elif field.type in ('text', 'string', 'json'):
|
||||
if op == 'contains': new_query = field.contains(value)
|
||||
elif op == 'like': new_query = field.like(value)
|
||||
elif op == 'startswith': new_query = field.startswith(value)
|
||||
elif op == 'endswith': new_query = field.endswith(value)
|
||||
else: raise RuntimeError("Invalid operation")
|
||||
elif field._db._adapter.dbengine=='google:datastore' and \
|
||||
field.type in ('list:integer', 'list:string', 'list:reference'):
|
||||
if op == 'contains': new_query = field.contains(value)
|
||||
else: raise RuntimeError("Invalid operation")
|
||||
else: raise RuntimeError("Invalid operation")
|
||||
if neg: new_query = ~new_query
|
||||
if query is None:
|
||||
query = new_query
|
||||
elif logic == 'and':
|
||||
query &= new_query
|
||||
elif logic == 'or':
|
||||
query |= new_query
|
||||
field = op = neg = logic = None
|
||||
return query
|
||||
|
||||
|
||||
def sqlhtml_validators(field):
|
||||
"""
|
||||
Field type validation, using web2py's validators mechanism.
|
||||
|
||||
makes sure the content of a field is in line with the declared
|
||||
fieldtype
|
||||
"""
|
||||
db = field.db
|
||||
try:
|
||||
from gluon import validators
|
||||
except ImportError:
|
||||
return []
|
||||
field_type, field_length = field.type, field.length
|
||||
if isinstance(field_type, SQLCustomType):
|
||||
if hasattr(field_type, 'validator'):
|
||||
return field_type.validator
|
||||
else:
|
||||
field_type = field_type.type
|
||||
elif not isinstance(field_type,str):
|
||||
return []
|
||||
requires=[]
|
||||
def ff(r,id):
|
||||
row=r(id)
|
||||
if not row:
|
||||
return str(id)
|
||||
elif hasattr(r, '_format') and isinstance(r._format,str):
|
||||
return r._format % row
|
||||
elif hasattr(r, '_format') and callable(r._format):
|
||||
return r._format(row)
|
||||
else:
|
||||
return str(id)
|
||||
if field_type in (('string', 'text', 'password')):
|
||||
requires.append(validators.IS_LENGTH(field_length))
|
||||
elif field_type == 'json':
|
||||
requires.append(validators.IS_EMPTY_OR(validators.IS_JSON(native_json=field.db._adapter.native_json)))
|
||||
elif field_type == 'double' or field_type == 'float':
|
||||
requires.append(validators.IS_FLOAT_IN_RANGE(-1e100, 1e100))
|
||||
elif field_type == 'integer':
|
||||
requires.append(validators.IS_INT_IN_RANGE(-2**31, 2**31))
|
||||
elif field_type == 'bigint':
|
||||
requires.append(validators.IS_INT_IN_RANGE(-2**63, 2**63))
|
||||
elif field_type.startswith('decimal'):
|
||||
requires.append(validators.IS_DECIMAL_IN_RANGE(-10**10, 10**10))
|
||||
elif field_type == 'date':
|
||||
requires.append(validators.IS_DATE())
|
||||
elif field_type == 'time':
|
||||
requires.append(validators.IS_TIME())
|
||||
elif field_type == 'datetime':
|
||||
requires.append(validators.IS_DATETIME())
|
||||
elif db and field_type.startswith('reference') and \
|
||||
field_type.find('.') < 0 and \
|
||||
field_type[10:] in db.tables:
|
||||
referenced = db[field_type[10:]]
|
||||
def repr_ref(id, row=None, r=referenced, f=ff): return f(r, id)
|
||||
field.represent = field.represent or repr_ref
|
||||
if hasattr(referenced, '_format') and referenced._format:
|
||||
requires = validators.IS_IN_DB(db,referenced._id,
|
||||
referenced._format)
|
||||
if field.unique:
|
||||
requires._and = validators.IS_NOT_IN_DB(db,field)
|
||||
if field.tablename == field_type[10:]:
|
||||
return validators.IS_EMPTY_OR(requires)
|
||||
return requires
|
||||
elif db and field_type.startswith('list:reference') and \
|
||||
field_type.find('.') < 0 and \
|
||||
field_type[15:] in db.tables:
|
||||
referenced = db[field_type[15:]]
|
||||
def list_ref_repr(ids, row=None, r=referenced, f=ff):
|
||||
if not ids:
|
||||
return None
|
||||
from ..adapters.google import GoogleDatastoreAdapter
|
||||
refs = None
|
||||
db, id = r._db, r._id
|
||||
if isinstance(db._adapter, GoogleDatastoreAdapter):
|
||||
def count(values): return db(id.belongs(values)).select(id)
|
||||
rx = range(0, len(ids), 30)
|
||||
refs = reduce(lambda a,b:a&b, [count(ids[i:i+30]) for i in rx])
|
||||
else:
|
||||
refs = db(id.belongs(ids)).select(id)
|
||||
return (refs and ', '.join(f(r,x.id) for x in refs) or '')
|
||||
field.represent = field.represent or list_ref_repr
|
||||
if hasattr(referenced, '_format') and referenced._format:
|
||||
requires = validators.IS_IN_DB(db,referenced._id,
|
||||
referenced._format,multiple=True)
|
||||
else:
|
||||
requires = validators.IS_IN_DB(db,referenced._id,
|
||||
multiple=True)
|
||||
if field.unique:
|
||||
requires._and = validators.IS_NOT_IN_DB(db,field)
|
||||
if not field.notnull:
|
||||
requires = validators.IS_EMPTY_OR(requires)
|
||||
return requires
|
||||
elif field_type.startswith('list:'):
|
||||
def repr_list(values,row=None): return', '.join(str(v) for v in (values or []))
|
||||
field.represent = field.represent or repr_list
|
||||
if field.unique:
|
||||
requires.append(validators.IS_NOT_IN_DB(db, field))
|
||||
sff = ['in', 'do', 'da', 'ti', 'de', 'bo']
|
||||
if field.notnull and not field_type[:2] in sff:
|
||||
requires.append(validators.IS_NOT_EMPTY())
|
||||
elif not field.notnull and field_type[:2] in sff and requires:
|
||||
requires[0] = validators.IS_EMPTY_OR(requires[0])
|
||||
return requires
|
||||
|
||||
|
||||
def varquote_aux(name,quotestr='%s'):
|
||||
return name if REGEX_W.match(name) else quotestr % name
|
||||
|
||||
|
||||
def uuid2int(uuidv):
|
||||
return uuid.UUID(uuidv).int
|
||||
|
||||
|
||||
def int2uuid(n):
|
||||
return str(uuid.UUID(int=n))
|
||||
|
||||
|
||||
# Geodal utils
|
||||
def geoPoint(x, y):
|
||||
return "POINT (%f %f)" % (x, y)
|
||||
|
||||
|
||||
def geoLine(*line):
|
||||
return "LINESTRING (%s)" % ','.join("%f %f" % item for item in line)
|
||||
|
||||
|
||||
def geoPolygon(*line):
|
||||
return "POLYGON ((%s))" % ','.join("%f %f" % item for item in line)
|
||||
Reference in New Issue
Block a user