db.t.f.epoch(), thanks Niphlod
This commit is contained in:
@@ -1 +1 @@
|
|||||||
Version 2.0.9 (2012-09-14 09:42:11) stable
|
Version 2.0.9 (2012-09-14 15:51:53) stable
|
||||||
|
|||||||
+69
-50
@@ -40,7 +40,7 @@ Example of usage:
|
|||||||
>>> # from dal import DAL, Field
|
>>> # from dal import DAL, Field
|
||||||
|
|
||||||
### create DAL connection (and create DB if it doesn't exist)
|
### create DAL connection (and create DB if it doesn't exist)
|
||||||
>>> db = DAL(('sqlite://storage.sqlite','mysql://a:b@localhost/x'),
|
>>> db = DAL(('sqlite://storage.sqlite','mysql://a:b@localhost/x'),
|
||||||
... folder=None)
|
... folder=None)
|
||||||
|
|
||||||
### define a table 'person' (create/alter as necessary)
|
### define a table 'person' (create/alter as necessary)
|
||||||
@@ -330,7 +330,7 @@ if not 'google' in DRIVERS:
|
|||||||
DRIVERS.append('Sybase(Sybase)')
|
DRIVERS.append('Sybase(Sybase)')
|
||||||
except ImportError:
|
except ImportError:
|
||||||
logger.debug('no Sybase driver')
|
logger.debug('no Sybase driver')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import kinterbasdb
|
import kinterbasdb
|
||||||
DRIVERS.append('Interbase(kinterbasdb)')
|
DRIVERS.append('Interbase(kinterbasdb)')
|
||||||
@@ -342,7 +342,7 @@ if not 'google' in DRIVERS:
|
|||||||
import fdb
|
import fdb
|
||||||
DRIVERS.append('Firbird(fdb)')
|
DRIVERS.append('Firbird(fdb)')
|
||||||
except ImportError:
|
except ImportError:
|
||||||
logger.debug('no Firebird driver fdb')
|
logger.debug('no Firebird driver fdb')
|
||||||
#####
|
#####
|
||||||
try:
|
try:
|
||||||
import firebirdsql
|
import firebirdsql
|
||||||
@@ -660,7 +660,7 @@ class BaseAdapter(ConnectionPool):
|
|||||||
|
|
||||||
def find_driver(self,adapter_args,uri=None):
|
def find_driver(self,adapter_args,uri=None):
|
||||||
if hasattr(self,'driver') and self.driver!=None:
|
if hasattr(self,'driver') and self.driver!=None:
|
||||||
return
|
return
|
||||||
drivers_available = [driver for driver in self.drivers
|
drivers_available = [driver for driver in self.drivers
|
||||||
if driver in globals()]
|
if driver in globals()]
|
||||||
if uri:
|
if uri:
|
||||||
@@ -668,7 +668,7 @@ class BaseAdapter(ConnectionPool):
|
|||||||
request_driver = items[1] if len(items)>1 else None
|
request_driver = items[1] if len(items)>1 else None
|
||||||
else:
|
else:
|
||||||
request_driver = None
|
request_driver = None
|
||||||
request_driver = request_driver or adapter_args.get('driver')
|
request_driver = request_driver or adapter_args.get('driver')
|
||||||
if request_driver:
|
if request_driver:
|
||||||
if request_driver in drivers_available:
|
if request_driver in drivers_available:
|
||||||
self.driver_name = request_driver
|
self.driver_name = request_driver
|
||||||
@@ -680,7 +680,7 @@ class BaseAdapter(ConnectionPool):
|
|||||||
self.driver = globals().get(self.driver_name)
|
self.driver = globals().get(self.driver_name)
|
||||||
else:
|
else:
|
||||||
raise RuntimeError, "no driver available %s", self.drivers
|
raise RuntimeError, "no driver available %s", self.drivers
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, db,uri,pool_size=0, folder=None, db_codec='UTF-8',
|
def __init__(self, db,uri,pool_size=0, folder=None, db_codec='UTF-8',
|
||||||
credential_decoder=IDENTITY, driver_args={},
|
credential_decoder=IDENTITY, driver_args={},
|
||||||
@@ -799,7 +799,7 @@ class BaseAdapter(ConnectionPool):
|
|||||||
else:
|
else:
|
||||||
schema = parms[0]
|
schema = parms[0]
|
||||||
ftype = "SELECT AddGeometryColumn ('%%(schema)s', '%%(tablename)s', '%%(fieldname)s', %%(srid)s, '%s', %%(dimension)s);" % types[geotype]
|
ftype = "SELECT AddGeometryColumn ('%%(schema)s', '%%(tablename)s', '%%(fieldname)s', %%(srid)s, '%s', %%(dimension)s);" % types[geotype]
|
||||||
ftype = ftype % dict(schema=schema,
|
ftype = ftype % dict(schema=schema,
|
||||||
tablename=tablename,
|
tablename=tablename,
|
||||||
fieldname=field_name, srid=srid,
|
fieldname=field_name, srid=srid,
|
||||||
dimension=dimension)
|
dimension=dimension)
|
||||||
@@ -890,7 +890,7 @@ class BaseAdapter(ConnectionPool):
|
|||||||
else:
|
else:
|
||||||
table._dbt = pjoin(
|
table._dbt = pjoin(
|
||||||
dbpath, '%s_%s.table' % (table._db._uri_hash, tablename))
|
dbpath, '%s_%s.table' % (table._db._uri_hash, tablename))
|
||||||
|
|
||||||
if table._dbt:
|
if table._dbt:
|
||||||
table._loggername = pjoin(dbpath, 'sql.log')
|
table._loggername = pjoin(dbpath, 'sql.log')
|
||||||
logfile = self.file_open(table._loggername, 'a')
|
logfile = self.file_open(table._loggername, 'a')
|
||||||
@@ -1002,7 +1002,7 @@ class BaseAdapter(ConnectionPool):
|
|||||||
query = ['ALTER TABLE %s DROP %s;' % (tablename, key)]
|
query = ['ALTER TABLE %s DROP %s;' % (tablename, key)]
|
||||||
metadata_change = True
|
metadata_change = True
|
||||||
elif sql_fields[key]['sql'] != sql_fields_old[key]['sql'] \
|
elif sql_fields[key]['sql'] != sql_fields_old[key]['sql'] \
|
||||||
and not (key in table.fields and
|
and not (key in table.fields and
|
||||||
isinstance(table[key].type, SQLCustomType)) \
|
isinstance(table[key].type, SQLCustomType)) \
|
||||||
and not sql_fields[key]['type'].startswith('reference')\
|
and not sql_fields[key]['type'].startswith('reference')\
|
||||||
and not sql_fields[key]['type'].startswith('double')\
|
and not sql_fields[key]['type'].startswith('double')\
|
||||||
@@ -1073,6 +1073,9 @@ class BaseAdapter(ConnectionPool):
|
|||||||
def EXTRACT(self, first, what):
|
def EXTRACT(self, first, what):
|
||||||
return "EXTRACT(%s FROM %s)" % (what, self.expand(first))
|
return "EXTRACT(%s FROM %s)" % (what, self.expand(first))
|
||||||
|
|
||||||
|
def EPOCH(self, first):
|
||||||
|
return self.EXTRACT(first, 'epoch')
|
||||||
|
|
||||||
def AGGREGATE(self, first, what):
|
def AGGREGATE(self, first, what):
|
||||||
return "%s(%s)" % (what, self.expand(first))
|
return "%s(%s)" % (what, self.expand(first))
|
||||||
|
|
||||||
@@ -1273,7 +1276,7 @@ class BaseAdapter(ConnectionPool):
|
|||||||
first = expression.first
|
first = expression.first
|
||||||
second = expression.second
|
second = expression.second
|
||||||
op = expression.op
|
op = expression.op
|
||||||
if not second is None:
|
if not second is None:
|
||||||
return op(first, second)
|
return op(first, second)
|
||||||
elif not first is None:
|
elif not first is None:
|
||||||
return op(first)
|
return op(first)
|
||||||
@@ -1580,14 +1583,14 @@ class BaseAdapter(ConnectionPool):
|
|||||||
"""
|
"""
|
||||||
sql = self._select(query, fields, attributes)
|
sql = self._select(query, fields, attributes)
|
||||||
cache = attributes.get('cache', None)
|
cache = attributes.get('cache', None)
|
||||||
if cache and attributes.get('cacheable',False):
|
if cache and attributes.get('cacheable',False):
|
||||||
del attributes['cache']
|
del attributes['cache']
|
||||||
(cache_model, time_expire) = cache
|
(cache_model, time_expire) = cache
|
||||||
key = self.uri + '/' + sql
|
key = self.uri + '/' + sql
|
||||||
if len(key)>200: key = hashlib.md5(key).hexdigest()
|
if len(key)>200: key = hashlib.md5(key).hexdigest()
|
||||||
args = (sql,fields,attributes)
|
args = (sql,fields,attributes)
|
||||||
return cache_model(
|
return cache_model(
|
||||||
key,
|
key,
|
||||||
lambda self=self,args=args:self._select_aux(*args),
|
lambda self=self,args=args:self._select_aux(*args),
|
||||||
time_expire)
|
time_expire)
|
||||||
else:
|
else:
|
||||||
@@ -1906,7 +1909,7 @@ class BaseAdapter(ConnectionPool):
|
|||||||
for (i,row) in enumerate(rows):
|
for (i,row) in enumerate(rows):
|
||||||
new_row = Row()
|
new_row = Row()
|
||||||
for (j,colname) in enumerate(colnames):
|
for (j,colname) in enumerate(colnames):
|
||||||
value = row[j]
|
value = row[j]
|
||||||
tmp = tmps[j]
|
tmp = tmps[j]
|
||||||
if tmp:
|
if tmp:
|
||||||
(tablename,fieldname,table,field,ft) = tmp
|
(tablename,fieldname,table,field,ft) = tmp
|
||||||
@@ -1920,14 +1923,14 @@ class BaseAdapter(ConnectionPool):
|
|||||||
if field.filter_out:
|
if field.filter_out:
|
||||||
value = field.filter_out(value)
|
value = field.filter_out(value)
|
||||||
colset[fieldname] = value
|
colset[fieldname] = value
|
||||||
|
|
||||||
# for backward compatibility
|
# for backward compatibility
|
||||||
if ft=='id' and fieldname!='id' and \
|
if ft=='id' and fieldname!='id' and \
|
||||||
not 'id' in table.fields:
|
not 'id' in table.fields:
|
||||||
colset['id'] = value
|
colset['id'] = value
|
||||||
|
|
||||||
if ft == 'id' and not cacheable:
|
if ft == 'id' and not cacheable:
|
||||||
# temporary hack to deal with
|
# temporary hack to deal with
|
||||||
# GoogleDatastoreAdapter
|
# GoogleDatastoreAdapter
|
||||||
# references
|
# references
|
||||||
if isinstance(self, GoogleDatastoreAdapter):
|
if isinstance(self, GoogleDatastoreAdapter):
|
||||||
@@ -2027,8 +2030,11 @@ class SQLiteAdapter(BaseAdapter):
|
|||||||
'second': (17, 19),
|
'second': (17, 19),
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
(i, j) = table[lookup]
|
if lookup != 'epoch':
|
||||||
return int(s[i:j])
|
(i, j) = table[lookup]
|
||||||
|
return int(s[i:j])
|
||||||
|
else:
|
||||||
|
return time.mktime(datetime.datetime.strptime(s, '%Y-%m-%d %H:%M:%S').timetuple())
|
||||||
except:
|
except:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -2280,6 +2286,9 @@ class MySQLAdapter(BaseAdapter):
|
|||||||
return 'SUBSTRING(%s,%s,%s)' % (self.expand(field),
|
return 'SUBSTRING(%s,%s,%s)' % (self.expand(field),
|
||||||
parameters[0], parameters[1])
|
parameters[0], parameters[1])
|
||||||
|
|
||||||
|
def EPOCH(self, first):
|
||||||
|
return "UNIX_TIMESTAMP(%s)" % self.expand(first)
|
||||||
|
|
||||||
def _drop(self,table,mode):
|
def _drop(self,table,mode):
|
||||||
# breaks db integrity but without this mysql does not drop table
|
# breaks db integrity but without this mysql does not drop table
|
||||||
return ['SET FOREIGN_KEY_CHECKS=0;','DROP TABLE %s;' % table,
|
return ['SET FOREIGN_KEY_CHECKS=0;','DROP TABLE %s;' % table,
|
||||||
@@ -2984,7 +2993,7 @@ class MSSQLAdapter(BaseAdapter):
|
|||||||
# (in the form of arg1=value1&arg2=value2&...)
|
# (in the form of arg1=value1&arg2=value2&...)
|
||||||
# Default values (drivers like FreeTDS insist on uppercase parameter keys)
|
# Default values (drivers like FreeTDS insist on uppercase parameter keys)
|
||||||
argsdict = { 'DRIVER':'{SQL Server}' }
|
argsdict = { 'DRIVER':'{SQL Server}' }
|
||||||
urlargs = m.group('urlargs') or ''
|
urlargs = m.group('urlargs') or ''
|
||||||
for argmatch in self.REGEX_ARGPATTERN.finditer(urlargs):
|
for argmatch in self.REGEX_ARGPATTERN.finditer(urlargs):
|
||||||
argsdict[str(argmatch.group('argkey')).upper()] = argmatch.group('argvalue')
|
argsdict[str(argmatch.group('argkey')).upper()] = argmatch.group('argvalue')
|
||||||
urlargs = ';'.join(['%s=%s' % (ak, av) for (ak, av) in argsdict.iteritems()])
|
urlargs = ';'.join(['%s=%s' % (ak, av) for (ak, av) in argsdict.iteritems()])
|
||||||
@@ -3009,6 +3018,9 @@ class MSSQLAdapter(BaseAdapter):
|
|||||||
return rows[minimum:]
|
return rows[minimum:]
|
||||||
return rows[minimum:maximum]
|
return rows[minimum:maximum]
|
||||||
|
|
||||||
|
def EPOCH(self, first):
|
||||||
|
return "DATEDIFF(second, '1970-01-01 00:00:00', %s)" % self.expand(first)
|
||||||
|
|
||||||
# GIS functions
|
# GIS functions
|
||||||
|
|
||||||
# No STAsGeoJSON in MSSQL
|
# No STAsGeoJSON in MSSQL
|
||||||
@@ -3156,7 +3168,7 @@ class SybaseAdapter(MSSQLAdapter):
|
|||||||
logger.error('NdGpatch error')
|
logger.error('NdGpatch error')
|
||||||
raise e
|
raise e
|
||||||
else:
|
else:
|
||||||
m = self.REGEX_URI.match(uri)
|
m = self.REGEX_URI.match(uri)
|
||||||
if not m:
|
if not m:
|
||||||
raise SyntaxError, \
|
raise SyntaxError, \
|
||||||
"Invalid URI string in DAL: %s" % self.uri
|
"Invalid URI string in DAL: %s" % self.uri
|
||||||
@@ -3228,6 +3240,9 @@ class FireBirdAdapter(BaseAdapter):
|
|||||||
def RANDOM(self):
|
def RANDOM(self):
|
||||||
return 'RAND()'
|
return 'RAND()'
|
||||||
|
|
||||||
|
def EPOCH(self, first):
|
||||||
|
return "DATEDIFF(second, '1970-01-01 00:00:00', %s)" % self.expand(first)
|
||||||
|
|
||||||
def NOT_NULL(self,default,field_type):
|
def NOT_NULL(self,default,field_type):
|
||||||
return 'DEFAULT %s NOT NULL' % self.represent(default,field_type)
|
return 'DEFAULT %s NOT NULL' % self.represent(default,field_type)
|
||||||
|
|
||||||
@@ -3252,7 +3267,7 @@ class FireBirdAdapter(BaseAdapter):
|
|||||||
|
|
||||||
def __init__(self,db,uri,pool_size=0,folder=None,db_codec ='UTF-8',
|
def __init__(self,db,uri,pool_size=0,folder=None,db_codec ='UTF-8',
|
||||||
credential_decoder=IDENTITY, driver_args={},
|
credential_decoder=IDENTITY, driver_args={},
|
||||||
adapter_args={}):
|
adapter_args={}):
|
||||||
self.db = db
|
self.db = db
|
||||||
self.dbengine = "firebird"
|
self.dbengine = "firebird"
|
||||||
self.uri = uri
|
self.uri = uri
|
||||||
@@ -3283,7 +3298,7 @@ class FireBirdAdapter(BaseAdapter):
|
|||||||
user = credential_decoder(user),
|
user = credential_decoder(user),
|
||||||
password = credential_decoder(password),
|
password = credential_decoder(password),
|
||||||
charset = charset)
|
charset = charset)
|
||||||
|
|
||||||
def connect(driver_args=driver_args):
|
def connect(driver_args=driver_args):
|
||||||
return self.driver.connect(**driver_args)
|
return self.driver.connect(**driver_args)
|
||||||
self.pool_connection(connect)
|
self.pool_connection(connect)
|
||||||
@@ -3343,7 +3358,7 @@ class FireBirdEmbeddedAdapter(FireBirdAdapter):
|
|||||||
user=credential_decoder(user),
|
user=credential_decoder(user),
|
||||||
password=credential_decoder(password),
|
password=credential_decoder(password),
|
||||||
charset=charset)
|
charset=charset)
|
||||||
|
|
||||||
def connect(driver_args=driver_args):
|
def connect(driver_args=driver_args):
|
||||||
return self.driver.connect(**driver_args)
|
return self.driver.connect(**driver_args)
|
||||||
self.pool_connection(connect)
|
self.pool_connection(connect)
|
||||||
@@ -4416,7 +4431,7 @@ class GoogleDatastoreAdapter(NoSQLAdapter):
|
|||||||
else:
|
else:
|
||||||
projection.append(f.name)
|
projection.append(f.name)
|
||||||
|
|
||||||
# projection's can't include 'id'.
|
# projection's can't include 'id'.
|
||||||
# it will be added to the result later
|
# it will be added to the result later
|
||||||
query_projection = [
|
query_projection = [
|
||||||
p for p in projection if \
|
p for p in projection if \
|
||||||
@@ -4912,7 +4927,7 @@ class MongoDBAdapter(NoSQLAdapter):
|
|||||||
print "in expand and this is a query"
|
print "in expand and this is a query"
|
||||||
# any query using 'id':=
|
# any query using 'id':=
|
||||||
# set name as _id (as per pymongo/mongodb primary key)
|
# set name as _id (as per pymongo/mongodb primary key)
|
||||||
# convert second arg to an objectid field
|
# convert second arg to an objectid field
|
||||||
# (if its not already)
|
# (if its not already)
|
||||||
# if second arg is 0 convert to objectid
|
# if second arg is 0 convert to objectid
|
||||||
if isinstance(expression.first,Field) and \
|
if isinstance(expression.first,Field) and \
|
||||||
@@ -4922,9 +4937,9 @@ class MongoDBAdapter(NoSQLAdapter):
|
|||||||
not isinstance(expression.second,ObjectId):
|
not isinstance(expression.second,ObjectId):
|
||||||
if isinstance(expression.second,int):
|
if isinstance(expression.second,int):
|
||||||
try:
|
try:
|
||||||
# Because the reference field is by default
|
# Because the reference field is by default
|
||||||
# an integer and therefore this must be an
|
# an integer and therefore this must be an
|
||||||
# integer to be able to work with other
|
# integer to be able to work with other
|
||||||
# databases
|
# databases
|
||||||
expression.second = ObjectId(("%X" % expression.second))
|
expression.second = ObjectId(("%X" % expression.second))
|
||||||
except:
|
except:
|
||||||
@@ -5212,27 +5227,27 @@ class MongoDBAdapter(NoSQLAdapter):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
def ADD(self, first, second):
|
def ADD(self, first, second):
|
||||||
raise NotImplementedError, "This must yet be replaced with javescript in order to accomplish this. Sorry"
|
raise NotImplementedError, "This must yet be replaced with javascript in order to accomplish this. Sorry"
|
||||||
return '%s + %s' % (self.expand(first), self.expand(second, first.type))
|
return '%s + %s' % (self.expand(first), self.expand(second, first.type))
|
||||||
|
|
||||||
def SUB(self, first, second):
|
def SUB(self, first, second):
|
||||||
raise NotImplementedError, "This must yet be replaced with javescript in order to accomplish this. Sorry"
|
raise NotImplementedError, "This must yet be replaced with javascript in order to accomplish this. Sorry"
|
||||||
return '(%s - %s)' % (self.expand(first), self.expand(second, first.type))
|
return '(%s - %s)' % (self.expand(first), self.expand(second, first.type))
|
||||||
|
|
||||||
def MUL(self, first, second):
|
def MUL(self, first, second):
|
||||||
raise NotImplementedError, "This must yet be replaced with javescript in order to accomplish this. Sorry"
|
raise NotImplementedError, "This must yet be replaced with javascript in order to accomplish this. Sorry"
|
||||||
return '(%s * %s)' % (self.expand(first), self.expand(second, first.type))
|
return '(%s * %s)' % (self.expand(first), self.expand(second, first.type))
|
||||||
|
|
||||||
def DIV(self, first, second):
|
def DIV(self, first, second):
|
||||||
raise NotImplementedError, "This must yet be replaced with javescript in order to accomplish this. Sorry"
|
raise NotImplementedError, "This must yet be replaced with javascript in order to accomplish this. Sorry"
|
||||||
return '(%s / %s)' % (self.expand(first), self.expand(second, first.type))
|
return '(%s / %s)' % (self.expand(first), self.expand(second, first.type))
|
||||||
|
|
||||||
def MOD(self, first, second):
|
def MOD(self, first, second):
|
||||||
raise NotImplementedError, "This must yet be replaced with javescript in order to accomplish this. Sorry"
|
raise NotImplementedError, "This must yet be replaced with javascript in order to accomplish this. Sorry"
|
||||||
return '(%s %% %s)' % (self.expand(first), self.expand(second, first.type))
|
return '(%s %% %s)' % (self.expand(first), self.expand(second, first.type))
|
||||||
|
|
||||||
def AS(self, first, second):
|
def AS(self, first, second):
|
||||||
raise NotImplementedError, "This must yet be replaced with javescript in order to accomplish this. Sorry"
|
raise NotImplementedError, "This must yet be replaced with javascript in order to accomplish this. Sorry"
|
||||||
return '%s AS %s' % (self.expand(first), second)
|
return '%s AS %s' % (self.expand(first), second)
|
||||||
|
|
||||||
#We could implement an option that simulates a full featured SQL database. But I think the option should be set explicit or implemented as another library.
|
#We could implement an option that simulates a full featured SQL database. But I think the option should be set explicit or implemented as another library.
|
||||||
@@ -5344,31 +5359,31 @@ class MongoDBAdapter(NoSQLAdapter):
|
|||||||
|
|
||||||
#TODO javascript has math
|
#TODO javascript has math
|
||||||
def ADD(self, first, second):
|
def ADD(self, first, second):
|
||||||
raise NotImplementedError, "This must yet be replaced with javescript in order to accomplish this. Sorry"
|
raise NotImplementedError, "This must yet be replaced with javascript in order to accomplish this. Sorry"
|
||||||
return '%s + %s' % (self.expand(first), self.expand(second, first.type))
|
return '%s + %s' % (self.expand(first), self.expand(second, first.type))
|
||||||
|
|
||||||
#TODO javascript has math
|
#TODO javascript has math
|
||||||
def SUB(self, first, second):
|
def SUB(self, first, second):
|
||||||
raise NotImplementedError, "This must yet be replaced with javescript in order to accomplish this. Sorry"
|
raise NotImplementedError, "This must yet be replaced with javascript in order to accomplish this. Sorry"
|
||||||
return '(%s - %s)' % (self.expand(first), self.expand(second, first.type))
|
return '(%s - %s)' % (self.expand(first), self.expand(second, first.type))
|
||||||
|
|
||||||
#TODO javascript has math
|
#TODO javascript has math
|
||||||
def MUL(self, first, second):
|
def MUL(self, first, second):
|
||||||
raise NotImplementedError, "This must yet be replaced with javescript in order to accomplish this. Sorry"
|
raise NotImplementedError, "This must yet be replaced with javascript in order to accomplish this. Sorry"
|
||||||
return '(%s * %s)' % (self.expand(first), self.expand(second, first.type))
|
return '(%s * %s)' % (self.expand(first), self.expand(second, first.type))
|
||||||
#TODO javascript has math
|
#TODO javascript has math
|
||||||
|
|
||||||
def DIV(self, first, second):
|
def DIV(self, first, second):
|
||||||
raise NotImplementedError, "This must yet be replaced with javescript in order to accomplish this. Sorry"
|
raise NotImplementedError, "This must yet be replaced with javascript in order to accomplish this. Sorry"
|
||||||
return '(%s / %s)' % (self.expand(first), self.expand(second, first.type))
|
return '(%s / %s)' % (self.expand(first), self.expand(second, first.type))
|
||||||
#TODO javascript has math
|
#TODO javascript has math
|
||||||
def MOD(self, first, second):
|
def MOD(self, first, second):
|
||||||
raise NotImplementedError, "This must yet be replaced with javescript in order to accomplish this. Sorry"
|
raise NotImplementedError, "This must yet be replaced with javascript in order to accomplish this. Sorry"
|
||||||
return '(%s %% %s)' % (self.expand(first), self.expand(second, first.type))
|
return '(%s %% %s)' % (self.expand(first), self.expand(second, first.type))
|
||||||
|
|
||||||
#TODO javascript can do this
|
#TODO javascript can do this
|
||||||
def AS(self, first, second):
|
def AS(self, first, second):
|
||||||
raise NotImplementedError, "This must yet be replaced with javescript in order to accomplish this. Sorry"
|
raise NotImplementedError, "This must yet be replaced with javascript in order to accomplish this. Sorry"
|
||||||
return '%s AS %s' % (self.expand(first), second)
|
return '%s AS %s' % (self.expand(first), second)
|
||||||
|
|
||||||
#We could implement an option that simulates a full featured SQL database. But I think the option should be set explicit or implemented as another library.
|
#We could implement an option that simulates a full featured SQL database. But I think the option should be set explicit or implemented as another library.
|
||||||
@@ -6455,7 +6470,7 @@ class Row(object):
|
|||||||
|
|
||||||
def values(self):
|
def values(self):
|
||||||
return self.__dict__.values()
|
return self.__dict__.values()
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return self.__dict__.__iter__()
|
return self.__dict__.__iter__()
|
||||||
|
|
||||||
@@ -6648,7 +6663,7 @@ class DAL(object):
|
|||||||
db.define_table('tablename', Field('fieldname1'),
|
db.define_table('tablename', Field('fieldname1'),
|
||||||
Field('fieldname2'))
|
Field('fieldname2'))
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def set_folder(folder):
|
def set_folder(folder):
|
||||||
"""
|
"""
|
||||||
@@ -7211,7 +7226,7 @@ def index():
|
|||||||
Added 2012-08-24 "fields" and "colnames" optional arguments. If either
|
Added 2012-08-24 "fields" and "colnames" optional arguments. If either
|
||||||
is provided, the results cursor returned by the DB driver will be
|
is provided, the results cursor returned by the DB driver will be
|
||||||
converted to a DAL Rows object using the db._adapter.parse() method.
|
converted to a DAL Rows object using the db._adapter.parse() method.
|
||||||
|
|
||||||
The "fields" argument is a list of DAL Field objects that match the
|
The "fields" argument is a list of DAL Field objects that match the
|
||||||
fields returned from the DB. The Field objects should be part of one or
|
fields returned from the DB. The Field objects should be part of one or
|
||||||
more Table objects defined on the DAL object. The "fields" list can
|
more Table objects defined on the DAL object. The "fields" list can
|
||||||
@@ -7224,14 +7239,14 @@ def index():
|
|||||||
can be specified as a list of field names in tablename.fieldname format.
|
can be specified as a list of field names in tablename.fieldname format.
|
||||||
Again, these should represent tables and fields defined on the DAL
|
Again, these should represent tables and fields defined on the DAL
|
||||||
object.
|
object.
|
||||||
|
|
||||||
It is also possible to specify both "fields" and the associated
|
It is also possible to specify both "fields" and the associated
|
||||||
"colnames". In that case, "fields" can also include DAL Expression
|
"colnames". In that case, "fields" can also include DAL Expression
|
||||||
objects in addition to Field objects. For Field objects in "fields",
|
objects in addition to Field objects. For Field objects in "fields",
|
||||||
the associated "colnames" must still be in tablename.fieldname format.
|
the associated "colnames" must still be in tablename.fieldname format.
|
||||||
For Expression objects in "fields", the associated "colnames" can
|
For Expression objects in "fields", the associated "colnames" can
|
||||||
be any arbitrary labels.
|
be any arbitrary labels.
|
||||||
|
|
||||||
Note, the DAL Table objects referred to by "fields" or "colnames" can
|
Note, the DAL Table objects referred to by "fields" or "colnames" can
|
||||||
be dummy tables and do not have to represent any real tables in the
|
be dummy tables and do not have to represent any real tables in the
|
||||||
database. Also, note that the "fields" and "colnames" must be in the
|
database. Also, note that the "fields" and "colnames" must be in the
|
||||||
@@ -7390,7 +7405,7 @@ class Table(object):
|
|||||||
db.users.insert(name='me') # print db.users._insert(...) to see SQL
|
db.users.insert(name='me') # print db.users._insert(...) to see SQL
|
||||||
db.users.drop()
|
db.users.drop()
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
db,
|
db,
|
||||||
@@ -8075,6 +8090,10 @@ class Expression(object):
|
|||||||
db = self.db
|
db = self.db
|
||||||
return Expression(db, db._adapter.EXTRACT, self, 'second', 'integer')
|
return Expression(db, db._adapter.EXTRACT, self, 'second', 'integer')
|
||||||
|
|
||||||
|
def epoch(self):
|
||||||
|
db = self.db
|
||||||
|
return Expression(db, db._adapter.EPOCH, self, None, 'integer')
|
||||||
|
|
||||||
def __getslice__(self, start, stop):
|
def __getslice__(self, start, stop):
|
||||||
db = self.db
|
db = self.db
|
||||||
if start < 0:
|
if start < 0:
|
||||||
@@ -8215,7 +8234,7 @@ class Expression(object):
|
|||||||
|
|
||||||
def st_asgeojson(self, precision=15, options=0, version=1):
|
def st_asgeojson(self, precision=15, options=0, version=1):
|
||||||
return Expression(self.db, self.db._adapter.ST_ASGEOJSON, self,
|
return Expression(self.db, self.db._adapter.ST_ASGEOJSON, self,
|
||||||
dict(precision=precision, options=options,
|
dict(precision=precision, options=options,
|
||||||
version=version), 'dict')
|
version=version), 'dict')
|
||||||
|
|
||||||
def st_astext(self):
|
def st_astext(self):
|
||||||
@@ -8464,7 +8483,7 @@ class Field(Expression):
|
|||||||
elif not filename:
|
elif not filename:
|
||||||
filename = file.name
|
filename = file.name
|
||||||
filename = os.path.basename(filename.replace('/', os.sep)\
|
filename = os.path.basename(filename.replace('/', os.sep)\
|
||||||
.replace('\\', os.sep))
|
.replace('\\', os.sep))
|
||||||
m = REGEX_STORE_PATTERN.search(filename)
|
m = REGEX_STORE_PATTERN.search(filename)
|
||||||
extension = m and m.group('e') or 'txt'
|
extension = m and m.group('e') or 'txt'
|
||||||
uuid_key = web2py_uuid().replace('-', '')[-16:]
|
uuid_key = web2py_uuid().replace('-', '')[-16:]
|
||||||
@@ -8752,7 +8771,7 @@ class Set(object):
|
|||||||
key,
|
key,
|
||||||
(lambda self=self,distinct=distinct: \
|
(lambda self=self,distinct=distinct: \
|
||||||
db._adapter.count(self.query,distinct)),
|
db._adapter.count(self.query,distinct)),
|
||||||
time_expire)
|
time_expire)
|
||||||
return db._adapter.count(self.query,distinct)
|
return db._adapter.count(self.query,distinct)
|
||||||
|
|
||||||
def select(self, *fields, **attributes):
|
def select(self, *fields, **attributes):
|
||||||
@@ -8870,7 +8889,7 @@ class RecordUpdater(object):
|
|||||||
self.colset, self.table, self.id = colset, table, id
|
self.colset, self.table, self.id = colset, table, id
|
||||||
|
|
||||||
def __call__(self, **fields):
|
def __call__(self, **fields):
|
||||||
colset, table, id = self.colset, self.table, self.id
|
colset, table, id = self.colset, self.table, self.id
|
||||||
newfields = fields or dict(colset)
|
newfields = fields or dict(colset)
|
||||||
for fieldname in newfields.keys():
|
for fieldname in newfields.keys():
|
||||||
if not fieldname in table.fields or table[fieldname].type=='id':
|
if not fieldname in table.fields or table[fieldname].type=='id':
|
||||||
@@ -9192,7 +9211,7 @@ class Rows(object):
|
|||||||
def xml(self,strict=False,row_name='row',rows_name='rows'):
|
def xml(self,strict=False,row_name='row',rows_name='rows'):
|
||||||
"""
|
"""
|
||||||
serializes the table using sqlhtml.SQLTABLE (if present)
|
serializes the table using sqlhtml.SQLTABLE (if present)
|
||||||
"""
|
"""
|
||||||
if strict:
|
if strict:
|
||||||
ncols = len(self.colnames)
|
ncols = len(self.colnames)
|
||||||
def f(row,field,indent=' '):
|
def f(row,field,indent=' '):
|
||||||
|
|||||||
@@ -311,12 +311,13 @@ class TestDatetime(unittest.TestCase):
|
|||||||
9, 30)), 3)
|
9, 30)), 3)
|
||||||
self.assertEqual(len(db(db.t.a == datetime.datetime(1971, 12,
|
self.assertEqual(len(db(db.t.a == datetime.datetime(1971, 12,
|
||||||
21, 11, 30)).select()), 1)
|
21, 11, 30)).select()), 1)
|
||||||
self.assertEqual(len(db(db.t.a.year() == 1971).select()), 2)
|
self.assertEqual(db(db.t.a.year() == 1971).count(), 2)
|
||||||
self.assertEqual(len(db(db.t.a.month() == 12).select()), 2)
|
self.assertEqual(db(db.t.a.month() == 12).count(), 2)
|
||||||
self.assertEqual(len(db(db.t.a.day() == 21).select()), 3)
|
self.assertEqual(db(db.t.a.day() == 21).count(), 3)
|
||||||
self.assertEqual(len(db(db.t.a.hour() == 11).select()), 1)
|
self.assertEqual(db(db.t.a.hour() == 11).count(), 1)
|
||||||
self.assertEqual(len(db(db.t.a.minutes() == 30).select()), 3)
|
self.assertEqual(db(db.t.a.minutes() == 30).count(), 3)
|
||||||
self.assertEqual(len(db(db.t.a.seconds() == 0).select()), 3)
|
self.assertEqual(db(db.t.a.seconds() == 0).count(), 3)
|
||||||
|
self.assertEqual(db(db.t.a.epoch()<365*24*3600).count(),1)
|
||||||
db.t.drop()
|
db.t.drop()
|
||||||
|
|
||||||
|
|
||||||
@@ -329,7 +330,7 @@ class TestExpressions(unittest.TestCase):
|
|||||||
self.assertEqual(db.t.insert(a=2), 2)
|
self.assertEqual(db.t.insert(a=2), 2)
|
||||||
self.assertEqual(db.t.insert(a=3), 3)
|
self.assertEqual(db.t.insert(a=3), 3)
|
||||||
self.assertEqual(db(db.t.a == 3).update(a=db.t.a + 1), 1)
|
self.assertEqual(db(db.t.a == 3).update(a=db.t.a + 1), 1)
|
||||||
self.assertEqual(len(db(db.t.a == 4).select()), 1)
|
self.assertEqual(db(db.t.a == 4).count(), 1)
|
||||||
db.t.drop()
|
db.t.drop()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user