Commit 51a1a78e authored by Aurélien Campéas's avatar Aurélien Campéas
Browse files

util: provide a more complete query string builder

parent e47e7acef953
......@@ -213,25 +213,26 @@ class Snapshot(SeriesServices):
def cset_heads_query(self, csetfilter=(), order='desc'):
tablename = self.tsh._serie_to_tablename(self.cn, self.seriename)
q = sqlq(
'select ts.cset, ts.snapshot '
f'from "{self.tsh.namespace}.timeserie"."{tablename}" as ts, '
f' "{self.tsh.namespace}".changeset as cset'
' where cset.id = ts.cset'
'ts.cset', 'ts.snapshot'
).relation(
f'"{self.tsh.namespace}.timeserie"."{tablename}" as ts',
).join(
f'"{self.tsh.namespace}".changeset as cset on cset.id = ts.cset'
)
if csetfilter:
q.append('and ts.cset <= cset.id')
q.where('ts.cset <= cset.id')
for filtercb in csetfilter:
q.append('and ', filtercb)
q.where(filtercb)
q.append(f'order by ts.id {order}')
q.option(f'order by ts.id {order}')
return q
def find(self, csetfilter=(),
from_value_date=None, to_value_date=None):
q = self.cset_heads_query(csetfilter)
q.append('limit 1')
q.option('limit 1')
try:
csid, cid = q.do(self.cn).fetchone()
......
......@@ -17,6 +17,7 @@ from tshistory.util import (
start_end,
sqlfile,
sqlp,
sqlq,
tx,
tzaware_serie
)
......@@ -449,45 +450,40 @@ class timeseries(SeriesServices):
"""
log = []
sql = [
'select distinct cset.id, cset.author, cset.insertion_date, cset.metadata '
f'from "{self.namespace}".changeset as cset '
f'join "{self.namespace}".changeset_series as css on css.cset = cset.id '
f'join "{self.namespace}".registry as reg on reg.id = css.serie '
]
wheres = []
q = sqlq(
'cset.id', 'cset.author', 'cset.insertion_date', 'cset.metadata',
opt='distinct'
).relation(
f'"{self.namespace}".changeset as cset'
).join(
f'"{self.namespace}".changeset_series as css on css.cset = cset.id',
f'"{self.namespace}".registry as reg on reg.id = css.serie'
)
if names:
# XXX check names exist
wheres.append('reg.seriename in (%s)' % ','.join(
repr(name) for name in names)
q.where(
'reg.seriename in %(names)s',
names=tuple(names)
)
if authors:
wheres.append('cset.author in (%s)' % ','.join(
repr(auth) for auth in authors)
q.where(
'cset.author in %(authors)s',
author=tuple(authors)
)
if fromrev:
wheres.append('cset.id >= %(fromrev)s')
q.where('cset.id >= %(fromrev)s', fromrev=fromrev)
if torev:
wheres.append('cset.id <= %(torev)s')
q.where('cset.id <= %(torev)s', torev=torev)
if fromdate:
wheres.append('cset.insertion_date >= %(fromdate)s')
q.where('cset.insertion_date >= %(fromdate)s', fromdate=fromdate)
if todate:
wheres.append('cset.insertion_date <= %(todate)s')
q.where('cset.insertion_date <= %(todate)s', todate=todate)
sql.append('where ' + ' and '.join(wheres))
if limit:
sql.append('limit %(limit)s ')
sql.append('order by cset.id desc')
q.option('limit %(limit)s', limit=limit)
q.option('order by cset.id desc')
sql = ''.join(sql)
rset = cn.execute(sql, {
'fromdate': fromdate,
'todate': todate,
'fromrev': fromrev,
'torev': torev
})
rset = q.do(cn)
for csetid, author, revdate, meta in rset.fetchall():
log.append({'rev': csetid, 'author': author,
'date': pd.Timestamp(revdate).tz_convert('utc'),
......
......@@ -33,26 +33,68 @@ class sqlp:
class sqlq:
"""utility to incremntally build an sql query string along with its
"""utility to incrementally build an sql query string along with its
parameters
"""
__slots__ = ('sql', 'kw')
__slots__ = ('head', 'headopt', 'relations', 'joins', 'wheres', 'options', 'kw')
def __init__(self, *head, opt=''):
assert opt in ('', 'distinct')
self.head = list(head)
self.headopt = opt
self.relations = []
self.joins = []
self.wheres = []
self.options = []
self.kw = {}
def select(self, *select):
self.head.append(', '.join(select))
return self
def relation(self, *relations):
self.relations.append(', '.join(relations))
return self
def join(self, *joins, jtype='inner'):
assert jtype in ('inner', 'outer')
for j in joins:
self.joins.append(f'{jtype} join {j}')
return self
def where(self, *wheres, **kw):
self.kw.update(kw)
for where in wheres:
if isinstance(where, sqlp):
self.kw.update(where.kw)
where = where.sql
self.wheres.append(where)
return self
def option(self, option, **kw):
self.options.append(option)
self.kw.update(kw)
return self
def __init__(self, sql, **kw):
self.sql = [sql]
self.kw = kw
@property
def sql(self):
select = f'select {self.headopt} ' + ', '.join(self.head)
froms = 'from ' + ', '.join(self.relations)
join = ' '.join(self.joins)
wheres = 'where ' + ' and '.join(self.wheres) if self.wheres else ''
options = ' '.join(self.options)
sql = [select, froms, join, wheres, options]
return ' '.join(sql)
def append(self, *sql, **kw):
self.kw.update(kw)
for block in sql:
if isinstance(block, sqlp):
self.kw.update(block.kw)
block = block.sql
self.sql.append(block)
def __str__(self):
return f'query::[{self.sql}, {self.kw}]'
__repr__ = __str__
def do(self, cn):
return cn.execute(
' '.join(self.sql), **self.kw
self.sql,
**self.kw
)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment