# mad/db.py
#
#
""" JSON file db. """
from .event import Event
from .object import Default, Object
from .utils import root, elapsed, fn_time, to_day, day
import logging
import time
import os
[docs]class Db(Object):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
[docs] def scan(self, path, *args, **kwargs):
""" scan all files. """
p = Default(kwargs, default="")
if not path.endswith(os.sep):
path += os.sep
result = []
for root, dirs, files in os.walk(path, topdown=True):
if not os.path.isdir(root):
continue
for fn in files:
fnn = os.path.join(root, fn)
timed = fn_time(fnn)
if timed and p.start and timed < p.start:
continue
if timed and p.end and timed > p.end:
continue
yield fnn
[docs] def find(self, prefix, *args, **kwargs):
""" find all objects stored with a prefix subdirectory. """
for fn in self.prefixed(prefix, *args):
try:
object = Object().load(fn)
except Exception as ex:
logging.warn("fail %s %s" % (fn, str(ex)))
continue
if "deleted" in object and object.deleted:
continue
yield object
[docs] def prefixed(self, *args, **kwargs):
""" return all filename in a workdir subdirectory, the 'prefix'. """
from .space import cfg
if not args:
return []
files = []
if cfg.workdirs:
workdirs = cfg.workdirs
else:
workdirs = [root()]
for workdir in workdirs:
path = os.path.join(workdir, args[0])
if not os.path.exists(path):
continue
for fn in self.scan(path, *args, **kwargs):
files.append(fn)
return sorted(files, key=lambda x: fn_time(x))
[docs] def prefixes(self):
for p in os.listdir(root()):
yield p
[docs] def is_prefix(self, prefix):
for p in os.listdir(root()):
if prefix in p:
return True
[docs] def selected(self, event):
""" select objects based on a _parsed event. """
thrs = []
if not event._parsed.args:
return []
starttime = time.time()
nr = -1
index = event._parsed.index
for fn in self.prefixed(*event._parsed.args, **event._parsed):
object = self.selector(event, fn)
if object:
nr += 1
if index != None and nr != index:
continue
yield object
endtime = time.time()
logging.warn("# selected %s %s" % (nr, elapsed(endtime - starttime, short=False)))
[docs] def selector(self, event, fn, object=None):
import botlib.selector
s = botlib.selector
if not object:
object = Object().load(fn)
if "nodel" not in event and "deleted" in object and object.deleted:
return
if not s.selector(object, event._parsed.fields):
return
if s.notwanted(object, event._parsed.notwant):
return
if not s.wanted(object, event._parsed.want):
return
if s.ignore(object, event._parsed.ignore):
return
if s.uniq(object, event._parsed.uniq):
return
return object
[docs] def sequence(self, prefix, start, end=time.time(), skip=[]):
""" select objects of type prefix, start time till end time. """
p = Object()
p.start = start
p.end = end
for fn in self.prefixed(prefix, **p):
do_skip = False
for k in skip:
if k in fn:
do_skip = True
if do_skip:
continue
try:
e = Event().load(fn)
except Exception as ex:
logging.warn("fail %s %s" % (fn, str(ex)))
continue
yield e
[docs] def since(self, start, *args, **kwargs):
""" return all objects since a given time. """
e = Event(**kwargs)
e.start = start
for fn in self.prefixed(*args, **e):
try:
object = Object().load(fn)
except Exception as ex:
logging.warn("fail %s %s" % (fn, str(ex)))
continue
if "deleted" in object and object.deleted:
continue
yield object
[docs] def first(self, *args, **kwargs):
""" return first object matching provided prefix. """
for fn in self.prefixed(*args, **kwargs):
try:
object = Object().load(fn)
except Exception as ex:
logging.warn("fail %s %s" % (fn, str(ex)))
continue
if "deleted" in object and object.deleted:
continue
if len(args) > 1 and object.get(args[0]) != args[1]:
continue
return object
[docs] def last(self, *args, **kwargs):
""" return last record with a matching prefix. """
prefix = args[0]
if len(args) > 1:
value = args[1]
else:
value = ""
for fn in self.prefixed(args[0], **kwargs)[::-1]:
try:
object = Object().load(fn)
except Exception as ex:
logging.warn("fail %s %s" % (fn, str(ex)))
continue
if "deleted" in object and object.deleted:
continue
if value and object.get(prefix, "") != value:
continue
return object