예제 #1
0
    def create_fact(self, uid=UID):
        """
        MAKE NEW TABLE WITH GIVEN guid
        :param uid: name, or list of names, for the GUID
        :return: None
        """
        self.add_table_to_schema(["."])

        uid = listwrap(uid)
        new_columns = []
        for u in uid:
            if u == UID:
                pass
            else:
                c = Column(names={".": u},
                           type="string",
                           es_column=typed_column(u, "string"),
                           es_index=self.fact)
                self.add_column_to_schema(c)
                new_columns.append(c)

        command = ("CREATE TABLE " + quote_column(self.fact) + sql_iso(
            sql_list([quoted_GUID + " TEXT "] + [quoted_UID + " INTEGER"] + [
                quote_column(c.es_column) + " " + sql_types[c.type]
                for c in self.tables["."].schema.columns
            ] + [
                "PRIMARY KEY " + sql_iso(
                    sql_list([quoted_GUID] + [quoted_UID] + [
                        quote_column(c.es_column)
                        for c in self.tables["."].schema.columns
                    ]))
            ])))

        self.db.execute(command)
예제 #2
0
    def where(self, filter):
        """
        WILL NOT PULL WHOLE OBJECT, JUST TOP-LEVEL PROPERTIES
        :param filter:  jx_expression filter
        :return: list of objects that match
        """
        select = []
        column_names = []
        for cname, cs in self.columns.items():
            cs = [c for c in cs if c.type not in STRUCT and len(c.nested_path) == 1]
            if len(cs) == 0:
                continue
            column_names.append(cname)
            if len(cs) == 1:
                select.append(quote_column(c.es_column) + " " + quote_column(c.name))
            else:
                select.append(
                    "coalesce(" +
                    sql_list(quote_column(c.es_column) for c in cs) +
                    ") " + quote_column(c.name)
                )

        result = self.db.query(
            SQL_SELECT + SQL("\n,").join(select) +
            SQL_FROM + quote_column(self.sf.fact) +
            SQL_WHERE + jx_expression(filter).to_sql()
        )
        return wrap([{c: v for c, v in zip(column_names, r)} for r in result.data])
예제 #3
0
    def _add_column(self, column):
        cname = column.name
        if column.jx_type == "nested":
            # WE ARE ALSO NESTING
            self._nest_column(column, [cname] + column.nested_path)

        table = concat_field(self.fact_name, column.nested_path[0])

        try:
            with self.namespace.db.transaction() as t:
                t.execute("ALTER TABLE" + quote_column(table) + "ADD COLUMN" +
                          quote_column(column.es_column) + column.es_type)
            self.namespace.columns.add(column)
        except Exception as e:
            if "duplicate column name" in e:
                # THIS HAPPENS WHEN MULTIPLE THREADS ARE ASKING FOR MORE COLUMNS TO STORE DATA
                # THIS SHOULD NOT BE A PROBLEM SINCE THE THREADS BOTH AGREE THE COLUMNS SHOULD EXIST
                # BUT, IT WOULD BE NICE TO MAKE LARGER TRANSACTIONS SO THIS NEVER HAPPENS
                # CONFIRM THE COLUMN EXISTS IN LOCAL DATA STRUCTURES
                for c in self.namespace.columns:
                    if c.es_column == column.es_column:
                        break
                else:
                    Log.error("Did not add column {{column}]",
                              column=column.es_column,
                              cause=e)
            else:
                Log.error("Did not add column {{column}]",
                          column=column.es_column,
                          cause=e)
예제 #4
0
    def _edges_op(self, query, frum):
        query = query.copy()  # WE WILL BE MARKING UP THE QUERY
        index_to_column = {}  # MAP FROM INDEX TO COLUMN (OR SELECT CLAUSE)
        outer_selects = []  # EVERY SELECT CLAUSE (NOT TO BE USED ON ALL TABLES, OF COURSE)
        frum_path = split_field(frum)
        base_table = join_field(frum_path[0:1])
        path = join_field(frum_path[1:])
        nest_to_alias = {
            nested_path: quote_column("__" + unichr(ord('a') + i) + "__")
            for i, (nested_path, sub_table) in enumerate(self.sf.tables.items())
        }

        schema = self.sf.tables[relative_field(frum, self.sf.fact)].schema

        tables = []
        for n, a in nest_to_alias.items():
            if startswith_field(path, n):
                tables.append({"nest": n, "alias": a})
        tables = jx.sort(tables, {"value": {"length": "nest"}})

        from_sql = quote_column(join_field([base_table] + split_field(tables[0].nest))) + tables[0].alias
        for previous, t in zip(tables, tables[1::]):
            from_sql += (
                SQL_LEFT_JOIN + quote_column(concat_field(base_table, t.nest)) + t.alias +
                SQL_ON + join_column(t.alias, quoted_PARENT) + " = " + join_column(previous.alias, quoted_UID)
            )

        main_filter = query.where.to_sql(schema, boolean=True)[0].sql.b

        # SHIFT THE COLUMN DEFINITIONS BASED ON THE NESTED QUERY DEPTH
        ons = []
        join_types = []
        wheres = []
        null_ons = [EXISTS_COLUMN + SQL_IS_NULL]
        groupby = []
        null_groupby = []
        orderby = []
        domains = []

        select_clause = [SQL_ONE + EXISTS_COLUMN] + [quote_column(c.es_column) for c in self.sf.tables['.'].columns]

        for edge_index, query_edge in enumerate(query.edges):
            edge_alias = quote_column("e" + text_type(edge_index))

            if query_edge.value:
                edge_values = [p for c in query_edge.value.to_sql(schema).sql for p in c.items()]

            elif not query_edge.value and any(query_edge.domain.partitions.where):
                case = SQL_CASE
                for pp, p in enumerate(query_edge.domain.partitions):
                    w = p.where.to_sql(schema)[0].sql.b
                    t = quote_value(pp)
                    case += SQL_WHEN + w + SQL_THEN + t
                case += SQL_ELSE + SQL_NULL + SQL_END  # quote value with length of partitions
                edge_values = [("n", case)]

            elif query_edge.range:
                edge_values = query_edge.range.min.to_sql(schema)[0].sql.items() + query_edge.range.max.to_sql(schema)[
                    0].sql.items()
예제 #5
0
def to_sql(self, schema, not_null=False, boolean=False):
    cols = [
        Data({cname: c}) for cname, cs in schema.map_to_sql(self.var).items()
        for c in cs
    ]
    if not cols:
        # DOES NOT EXIST
        return wrap([{
            "name": ".",
            "sql": {
                "0": "NULL"
            },
            "nested_path": ROOT_PATH
        }])
    acc = {}
    if boolean:
        for col in cols:
            cname, col = col.items()[0]
            nested_path = col.nested_path[0]
            if col.type == OBJECT:
                value = "1"
            elif col.type == "boolean":
                value = quote_column(col.es_column).sql
            else:
                value = "(" + quote_column(col.es_column).sql + ") IS NOT NULL"
            tempa = acc.setdefault(nested_path, {})
            tempb = tempa.setdefault(get_property_name(cname), {})
            tempb['b'] = value
    else:
        for col in cols:
            cname, col = col.items()[0]
            if col.type == OBJECT:
                prefix = self.var + "."
                for cn, cs in schema.items():
                    if cn.startswith(prefix):
                        for child_col in cs:
                            tempa = acc.setdefault(child_col.nested_path[0],
                                                   {})
                            tempb = tempa.setdefault(get_property_name(cname),
                                                     {})
                            tempb[json_type_to_sql_type[
                                col.type]] = quote_column(
                                    child_col.es_column).sql
            else:
                nested_path = col.nested_path[0]
                tempa = acc.setdefault(nested_path, {})
                tempb = tempa.setdefault(get_property_name(cname), {})
                tempb[json_type_to_sql_type[col.type]] = quote_column(
                    col.es_column).sql

    return wrap([{
        "name": relative_field(cname, self.var),
        "sql": types,
        "nested_path": nested_path
    } for nested_path, pairs in acc.items() for cname, types in pairs.items()])
예제 #6
0
 def _make_digits_table(self):
     existence = self.db.query("PRAGMA table_info(__digits__)")
     if not existence.data:
         with self.db.transaction() as t:
             t.execute(
                 "CREATE TABLE" + quote_column(DIGITS_TABLE) + "(value INTEGER)"
             )
             t.execute(
                 "INSERT INTO"
                 + quote_column(DIGITS_TABLE)
                 + SQL_UNION_ALL.join(SQL_SELECT + quote_value(i) for i in range(10))
             )
예제 #7
0
    def test_bad_exists_properties(self):
        test = {
            "data": [{
                "~e~": 1
            }, {
                "~e~": 1
            }],
            "query": {
                "from": TEST_TABLE,
                "select": [{
                    "name": "count",
                    "aggregate": "count"
                }],
            },
            "expecting_list": {
                "meta": {
                    "format": "value"
                },
                "data": {
                    "count": 2
                }
            }
        }

        subtest = wrap(test)

        cont = self.utils.fill_container(subtest, typed=False)
        db = Sqlite(filename="metadata.localhost.sqlite")
        try:
            with db.transaction() as t:
                t.execute(
                    "insert into " + quote_column("meta.columns") +
                    "(name, es_type, jx_type, nested_path, es_column, es_index, last_updated) VALUES "
                    + quote_set([
                        ".", "object", "exists", '["."]', ".", cont.alias,
                        Date.now()
                    ]))
        except Exception as e:
            pass
        try:
            with db.transaction() as t:
                t.execute(
                    "insert into " + quote_column("meta.columns") +
                    "(name, es_type, jx_type, nested_path, es_column, es_index, last_updated) VALUES "
                    + quote_set([
                        "~e~", "long", "exists", '["."]', "~e~", cont.alias,
                        Date.now()
                    ]))
        except Exception as e:
            pass

        self.utils.send_queries(subtest)
예제 #8
0
    def _add_column(self, column):
        cname = column.names["."]
        if column.type == "nested":
            # WE ARE ALSO NESTING
            self._nest_column(column, [cname] + column.nested_path)

        table = concat_field(self.fact, column.nested_path[0])

        self.db.execute("ALTER TABLE " + quote_column(table) + " ADD COLUMN " +
                        quote_column(column.es_column) + " " +
                        sql_types[column.type])

        self.add_column_to_schema(column)
예제 #9
0
    def _add_column(self, column):
        cname = column.name
        if column.jx_type == "nested":
            # WE ARE ALSO NESTING
            self._nest_column(column, [cname] + column.nested_path)

        table = concat_field(self.fact_name, column.nested_path[0])

        with self.namespace.db.transaction() as t:
            t.execute("ALTER TABLE" + quote_column(table) + "ADD COLUMN" +
                      quote_column(column.es_column) + " " + column.es_type)

        self.namespace.columns.add(column)
예제 #10
0
    def _drop_column(self, column):
        # DROP COLUMN BY RENAMING IT, WITH __ PREFIX TO HIDE IT
        cname = column.name
        if column.jx_type == "nested":
            # WE ARE ALSO NESTING
            self._nest_column(column, [cname] + column.nested_path)

        table = concat_field(self.fact_name, column.nested_path[0])

        with self.namespace.db.transaction() as t:
            t.execute("ALTER TABLE" + quote_column(table) + "RENAME COLUMN" +
                      quote_column(column.es_column) + " TO " +
                      quote_column("__" + column.es_column))
        self.namespace.columns.remove(column)
예제 #11
0
    def _insert(self, collection):
        for nested_path, details in collection.items():
            active_columns = wrap(list(details.active_columns))
            rows = details.rows
            num_rows = len(rows)
            table_name = concat_field(self.name, nested_path)

            if table_name == self.name:
                # DO NOT REQUIRE PARENT OR ORDER COLUMNS
                meta_columns = [GUID, UID]
            else:
                meta_columns = [UID, PARENT, ORDER]

            all_columns = meta_columns + active_columns.es_column  # ONLY THE PRIMITIVE VALUE COLUMNS
            command = ConcatSQL([
                SQL_INSERT,
                quote_column(table_name),
                sql_iso(sql_list(map(quote_column, all_columns))), SQL_VALUES,
                sql_list(
                    sql_iso(
                        sql_list(quote_value(row.get(c)) for c in all_columns))
                    for row in unwrap(rows))
            ])

            with self.db.transaction() as t:
                t.execute(command)
예제 #12
0
    def _db_create(self):
        with self._db_transaction():
            self.db.execute(
                "CREATE TABLE "
                + db_table_name
                + sql_iso(
                    sql_list(
                        [
                            quote_column(c.name)
                            + " "
                            + json_type_to_sqlite_type[c.jx_type]
                            for c in METADATA_COLUMNS
                        ]
                        + [
                            "PRIMARY KEY"
                            + sql_iso(
                                sql_list(map(quote_column, ["es_index", "es_column"]))
                            )
                        ]
                    )
                )
            )

            for c in METADATA_COLUMNS:
                self._add(c)
                self._db_insert_column(c)
예제 #13
0
    def _insert(self, collection):
        for nested_path, details in collection.items():
            active_columns = wrap(list(details.active_columns))
            rows = details.rows
            table_name = concat_field(self.facts.snowflake.fact_name,
                                      nested_path)

            if table_name == self.facts.snowflake.fact_name:
                # DO NOT REQUIRE PARENT OR ORDER COLUMNS
                meta_columns = [GUID, UID]
            else:
                meta_columns = [UID, PARENT, ORDER]

            all_columns = meta_columns + active_columns.es_column

            prefix = ("INSERT INTO " + quote_column(table_name) +
                      sql_iso(sql_list(map(quote_column, all_columns))))

            # BUILD THE RECORDS
            records = SQL_UNION_ALL.join(
                SQL_SELECT +
                sql_list(quote_value(row.get(c)) for c in all_columns)
                for row in unwrap(rows))

            with self.db.transaction() as t:
                t.execute(prefix + records)
예제 #14
0
def to_sql(self, schema, not_null=False, boolean=False):
    if self.var == GUID:
        return wrap([{"name": ".", "sql": {"s": quoted_GUID}, "nested_path": ROOT_PATH}])
    vars = schema[self.var]
    if not vars:
        # DOES NOT EXIST
        return wrap([{"name": ".", "sql": {"0": SQL_NULL}, "nested_path": ROOT_PATH}])
    var_name = list(set(listwrap(vars).name))
    if len(var_name) > 1:
        Log.error("do not know how to handle")
    var_name = var_name[0]
    cols = schema.leaves(self.var)
    acc = {}
    if boolean:
        for col in cols:
            cname = relative_field(col.name, var_name)
            nested_path = col.nested_path[0]
            if col.type == OBJECT:
                value = SQL_TRUE
            elif col.type == BOOLEAN:
                value = quote_column(col.es_column)
            else:
                value = quote_column(col.es_column) + SQL_IS_NOT_NULL
            tempa = acc.setdefault(nested_path, {})
            tempb = tempa.setdefault(get_property_name(cname), {})
            tempb['b'] = value
    else:
        for col in cols:
            cname = relative_field(col.name, var_name)
            if col.type == OBJECT:
                prefix = self.var + "."
                for cn, cs in schema.items():
                    if cn.startswith(prefix):
                        for child_col in cs:
                            tempa = acc.setdefault(child_col.nested_path[0], {})
                            tempb = tempa.setdefault(get_property_name(cname), {})
                            tempb[json_type_to_sql_type[col.type]] = quote_column(child_col.es_column)
            else:
                nested_path = col.nested_path[0]
                tempa = acc.setdefault(nested_path, {})
                tempb = tempa.setdefault(get_property_name(cname), {})
                tempb[json_type_to_sql_type[col.type]] = quote_column(col.es_column)

    return wrap([
        {"name": cname, "sql": types, "nested_path": nested_path}
        for nested_path, pairs in acc.items() for cname, types in pairs.items()
    ])
예제 #15
0
 def remove_facts(self, fact_name):
     paths = self.ns.columns._snowflakes[fact_name]
     if paths:
         with self.db.transaction() as t:
             for p in paths:
                 full_name = concat_field(fact_name, p[0])
                 t.execute("DROP TABLE "+quote_column(full_name))
         self.ns.columns.remove_table(fact_name)
예제 #16
0
def id_generator(db):
    """
    INSTALL AN ID GENERATOR
    """
    about = db.about(VERSION_TABLE)
    if not about:
        with db.transaction() as t:
            t.execute(
                sql_create(VERSION_TABLE, {
                    "version": "TEXT",
                    "next_id": "LONG"
                }))
            t.execute(
                sql_insert(VERSION_TABLE, {
                    "version": "1.0",
                    "next_id": 1000
                }))
    else:
        for cid, name, dtype, notnull, dfft_value, pk in about:
            if name == "next_id":
                break
        else:
            with db.transaction() as t:
                t.execute("ALTER TABLE " + quote_column(VERSION_TABLE) +
                          " ADD COLUMN next_id LONG")
                t.execute(SQL_UPDATE + quote_column(VERSION_TABLE) + SQL_SET +
                          sql_eq(next_id=1000))

    def _gen_ids():
        while True:
            with db.transaction() as t:
                top_id = first(
                    first(
                        t.query(
                            sql_query({
                                "select": "next_id",
                                "from": VERSION_TABLE
                            })).data))
                max_id = top_id + 1000
                t.execute(SQL_UPDATE + quote_column(VERSION_TABLE) + SQL_SET +
                          sql_eq(next_id=max_id))
            while top_id < max_id:
                yield top_id
                top_id += 1

    return _gen_ids().__next__
예제 #17
0
 def monitor(self, please_stop):
     while not please_stop:
         # Delete expired session
         try:
             with self.db.transaction() as t:
                 t.execute("DELETE FROM " + quote_column(self.table) +
                           SQL_WHERE + sql_lt(expires=Date.now().unix))
         except Exception as e:
             Log.warning("problem with session expires", cause=e)
         (please_stop | Till(seconds=60)).wait()
예제 #18
0
    def _window_op(self, query, window):
        # http://www2.sqlite.org/cvstrac/wiki?p=UnsupportedSqlAnalyticalFunctions
        if window.value == "rownum":
            return (
                "ROW_NUMBER()-1 OVER (" +
                " PARTITION BY " + sql_iso(sql_list(window.edges.values)) +
                SQL_ORDERBY + sql_iso(sql_list(window.edges.sort)) +
                ") AS " + quote_column(window.name)
            )

        range_min = text_type(coalesce(window.range.min, "UNBOUNDED"))
        range_max = text_type(coalesce(window.range.max, "UNBOUNDED"))

        return (
            sql_aggs[window.aggregate] + sql_iso(window.value.to_sql()) + " OVER (" +
            " PARTITION BY " + sql_iso(sql_list(window.edges.values)) +
            SQL_ORDERBY + sql_iso(sql_list(window.edges.sort)) +
            " ROWS BETWEEN " + range_min + " PRECEDING AND " + range_max + " FOLLOWING " +
            ") AS " + quote_column(window.name)
        )
예제 #19
0
    def __init__(self, db):
        self.db = db
        self._snowflakes = {}  # MAP FROM BASE TABLE TO LIST OF NESTED TABLES
        self._columns = ColumnList()

        # FIND ALL TABLES
        result = self.db.query(
            "SELECT * FROM sqlite_master WHERE type='table' ORDER BY name")
        tables = wrap([{k: d[i]
                        for i, k in enumerate(result.header)}
                       for d in result.data])
        last_nested_path = []
        for table in tables:
            if table.name.startswith("__"):
                continue
            base_table, nested_path = tail_field(table.name)

            # FIND COMMON NESTED PATH SUFFIX
            for i, p in enumerate(last_nested_path):
                if startswith_field(nested_path, p):
                    last_nested_path = last_nested_path[i:]
                    break
            else:
                last_nested_path = []

            full_nested_path = [nested_path] + last_nested_path
            nested_tables = self._snowflakes.setdefault(
                base_table, [nested_path] + last_nested_path)
            nested_tables.append(
                jx_base.TableDesc(name=table.name,
                                  nested_path=full_nested_path))

            # LOAD THE COLUMNS
            command = "PRAGMA table_info" + sql_iso(quote_column(table.name))
            details = self.db.query(command)

            for cid, name, dtype, notnull, dfft_value, pk in details.data:
                if name.startswith("__"):
                    continue
                cname, ctype = untyped_column(name)
                self._columns.add(
                    Column(
                        name=cname,  # I THINK COLUMNS HAVE THIER FULL PATH
                        jx_type=coalesce(
                            ctype, {
                                "TEXT": "string",
                                "REAL": "number",
                                "INTEGER": "integer"
                            }.get(dtype)),
                        nested_path=full_nested_path,
                        es_type=dtype,
                        es_column=name,
                        es_index=table.name))
            last_nested_path = full_nested_path
예제 #20
0
    def create_snowflake(self, fact_name, uid=UID):
        """
        MAKE NEW TABLE WITH GIVEN guid
        :param fact_name:  NAME FOR THE CENTRAL FACTS
        :param uid: name, or list of names, for the GUID
        :return: Facts
        """
        self.add_table_to_schema(["."])

        uid = listwrap(uid)
        new_columns = []
        for u in uid:
            if u == UID:
                pass
            else:
                c = Column(
                    name=u,
                    jx_type=STRING,
                    es_column=typed_column(u, "string"),
                    es_index=fact_name
                )
                self.add_column_to_schema(c)
                new_columns.append(c)

        command = (
            "CREATE TABLE " + quote_column(fact_name) + sql_iso(sql_list(
                [quoted_GUID + " TEXT "] +
                [quoted_UID + " INTEGER"] +
                [quote_column(c.es_column) + " " + json_type_to_sqlite_type[c.jx_type] for c in self.tables["."].schema.columns] +
                ["PRIMARY KEY " + sql_iso(sql_list(
                    [quoted_GUID] +
                    [quoted_UID] +
                    [quote_column(c.es_column) for c in self.tables["."].schema.columns]
                ))]
            ))
        )

        self.db.execute(command)

        snowflake = Snowflake(fact_name, self)
        return Facts(self, snowflake)
예제 #21
0
    def create_or_replace_facts(self, fact_name, uid=UID):
        """
        MAKE NEW TABLE WITH GIVEN guid
        :param fact_name:  NAME FOR THE CENTRAL FACTS
        :param uid: name, or list of names, for the GUID
        :return: Facts
        """
        self.remove_snowflake(fact_name)
        self._snowflakes[fact_name] = ["."]

        uid = listwrap(uid)
        new_columns = []
        for u in uid:
            if u == UID:
                pass
            else:
                c = Column(name=u,
                           jx_type=mo_json.STRING,
                           es_column=typed_column(
                               u, json_type_to_sql_type[mo_json.STRING]),
                           es_type=json_type_to_sqlite_type[mo_json.STRING],
                           es_index=fact_name,
                           last_updated=Date.now())
                self.add_column_to_schema(c)
                new_columns.append(c)

        command = ("CREATE TABLE " + quote_column(fact_name) + sql_iso(
            sql_list([quoted_GUID + " TEXT "] + [quoted_UID + " INTEGER"] + [
                quote_column(c.es_column) + " " + c.es_type
                for c in new_columns
            ] + [
                "PRIMARY KEY " + sql_iso(
                    sql_list([quoted_GUID] + [quoted_UID] +
                             [quote_column(c.es_column) for c in new_columns]))
            ])))

        with self.db.transaction() as t:
            t.execute(command)

        snowflake = Snowflake(fact_name, self)
        return Facts(self, snowflake)
예제 #22
0
    def _nest_column(self, column, new_path):
        destination_table = concat_field(self.fact, new_path)
        existing_table = concat_field(self.fact, column.nested_path[0])

        # FIND THE INNER COLUMNS WE WILL BE MOVING
        moving_columns = []
        for c in self.columns:
            if destination_table != column.es_index and column.es_column == c.es_column:
                moving_columns.append(c)
                c.nested_path = [new_path] + c.nested_path

        # TODO: IF THERE ARE CHILD TABLES, WE MUST UPDATE THEIR RELATIONS TOO?

        # DEFINE A NEW TABLE?
        # LOAD THE COLUMNS
        command = "PRAGMA table_info(" + quote_table(destination_table) + ")"
        details = self.db.query(command)
        if not details.data:
            command = ("CREATE TABLE " + quote_table(destination_table) + "(" +
                       (",".join([
                           quoted_UID + " INTEGER", quoted_PARENT + " INTEGER",
                           quoted_ORDER + " INTEGER"
                       ])) + ", PRIMARY KEY (" + quoted_UID + ")" +
                       ", FOREIGN KEY (" + quoted_PARENT + ") REFERENCES " +
                       quote_table(existing_table) + "(" + quoted_UID + ")"
                       ")")
            self.db.execute(command)
            self.add_table_to_schema([new_path])

        # TEST IF THERE IS ANY DATA IN THE NEW NESTED ARRAY
        if not moving_columns:
            return

        column.es_index = destination_table
        self.db.execute("ALTER TABLE " + quote_table(destination_table) +
                        " ADD COLUMN " + quote_column(column.es_column) + " " +
                        sql_types[column.type])

        # Deleting parent columns
        for col in moving_columns:
            column = col.es_column
            tmp_table = "tmp_" + existing_table
            columns = self.db.query("select * from " +
                                    quote_table(existing_table) +
                                    " LIMIT 0").header
            self.db.execute("ALTER TABLE " + quote_table(existing_table) +
                            " RENAME TO " + quote_table(tmp_table))
            self.db.execute(
                "CREATE TABLE " + quote_table(existing_table) + " AS SELECT " +
                (", ".join([quote_table(c) for c in columns if c != column])) +
                " FROM " + quote_table(tmp_table))
            self.db.execute("DROP TABLE " + quote_table(tmp_table))
예제 #23
0
    def save_session(self, app, session, response):
        if not session or not session.keys():
            return
        if not session.session_id:
            session.session_id = generate_sid()
            session.permanent = True
        DEBUG and Log.note("save session {{session}}", session=session)

        now = Date.now().unix
        session_id = session.session_id
        result = self.db.query(
            sql_query({
                "from": self.table,
                "where": {
                    "eq": {
                        "session_id": session_id
                    }
                }
            }))
        saved_record = first(Data(zip(result.header, r)) for r in result.data)
        expires = min(session.expires,
                      now + self.cookie.inactive_lifetime.seconds)
        if saved_record:
            DEBUG and Log.note("found session {{session}}",
                               session=saved_record)

            saved_record.data = value2json(session)
            saved_record.expires = expires
            saved_record.last_used = now
            with self.db.transaction() as t:
                t.execute("UPDATE " + quote_column(self.table) + SQL_SET +
                          sql_list(
                              sql_eq(**{k: v})
                              for k, v in saved_record.items()) + SQL_WHERE +
                          sql_eq(session_id=session_id))
        else:
            new_record = {
                "session_id": session_id,
                "data": value2json(session),
                "expires": expires,
                "last_used": now,
            }
            DEBUG and Log.note("new record for db {{session}}",
                               session=new_record)
            with self.db.transaction() as t:
                t.execute(sql_insert(self.table, new_record))

            response.set_cookie(app.session_cookie_name,
                                session_id,
                                expires=expires)
예제 #24
0
 def _gen_ids(self):
     while True:
         with self.db.transaction() as t:
             top_id = first(
                 first(
                     t.query(
                         SQL_SELECT
                         + quote_column("next_id")
                         + SQL_FROM
                         + quote_column(ABOUT_TABLE)
                     ).data
                 )
             )
             max_id = top_id + 1000
             t.execute(
                 SQL_UPDATE
                 + quote_column(ABOUT_TABLE)
                 + SQL_SET
                 + sql_eq(next_id=max_id)
             )
         while top_id < max_id:
             yield top_id
             top_id += 1
예제 #25
0
    def read_db(self):
        """
        PULL SCHEMA FROM DATABASE, BUILD THE MODEL
        :return: None
        """

        # FIND ALL TABLES
        result = self.db.query(
            "SELECT * FROM sqlite_master WHERE type='table' ORDER BY name")
        tables = wrap([{k: d[i]
                        for i, k in enumerate(result.header)}
                       for d in result.data])
        tables_found = False
        for table in tables:
            if table.name.startswith("__"):
                continue
            tables_found = True
            nested_path = [
                join_field(split_field(tab.name)[1:])
                for tab in jx.reverse(tables)
                if startswith_field(table.name, tab.name)
            ]
            self.add_table_to_schema(nested_path)

            # LOAD THE COLUMNS
            command = "PRAGMA table_info" + sql_iso(quote_column(table.name))
            details = self.db.query(command)

            for cid, name, dtype, notnull, dfft_value, pk in details.data:
                if name.startswith("__"):
                    continue
                cname, ctype = untyped_column(name)
                column = Column(names={
                    np: relative_field(cname, np)
                    for np in nested_path
                },
                                type=coalesce(
                                    ctype, {
                                        "TEXT": "string",
                                        "REAL": "number",
                                        "INTEGER": "integer"
                                    }.get(dtype)),
                                nested_path=nested_path,
                                es_column=name,
                                es_index=table.name)

                self.add_column_to_schema(column)

        return tables_found
예제 #26
0
    def where(self, filter):
        """
        WILL NOT PULL WHOLE OBJECT, JUST TOP-LEVEL PROPERTIES
        :param filter:  jx_expression filter
        :return: list of objects that match
        """
        select = []
        column_names = []
        for c in self.schema.columns:
            if c.jx_type in STRUCT:
                continue
            if len(c.nested_path) != 1:
                continue
            column_names.append(c.name)
            select.append(sql_alias(quote_column(c.es_column), c.name))

        where_sql = SQLang[jx_expression(filter)].to_sql(self.schema)[0].sql.b
        result = self.db.query(ConcatSQL((
            SQL_SELECT, JoinSQL(SQL_COMMA, select),
            SQL_FROM, quote_column(self.snowflake.fact_name),
            SQL_WHERE, where_sql
        )))

        return wrap([{c: v for c, v in zip(column_names, r)} for r in result.data])
예제 #27
0
 def _gen_ids():
     while True:
         with db.transaction() as t:
             top_id = first(
                 first(
                     t.query(
                         sql_query({
                             "select": "next_id",
                             "from": VERSION_TABLE
                         })).data))
             max_id = top_id + 1000
             t.execute(SQL_UPDATE + quote_column(VERSION_TABLE) + SQL_SET +
                       sql_eq(next_id=max_id))
         while top_id < max_id:
             yield top_id
             top_id += 1
예제 #28
0
    def _load_from_database(self):
        # FIND ALL TABLES
        result = self.db.query(
            "SELECT * FROM sqlite_master WHERE type='table' ORDER BY name")
        tables = wrap([{k: d
                        for k, d in zip(result.header, row)}
                       for row in result.data])
        last_nested_path = []
        for table in tables:
            if table.name.startswith("__"):
                continue
            base_table, nested_path = tail_field(table.name)

            # FIND COMMON NESTED PATH SUFFIX
            for i, p in enumerate(last_nested_path):
                if startswith_field(nested_path, p):
                    last_nested_path = last_nested_path[i:]
                    break
            else:
                last_nested_path = []

            full_nested_path = [nested_path] + last_nested_path
            self._snowflakes[literal_field(base_table)] += [full_nested_path]

            # LOAD THE COLUMNS
            command = "PRAGMA table_info" + sql_iso(quote_column(table.name))
            details = self.db.query(command)

            for cid, name, dtype, notnull, dfft_value, pk in details.data:
                if name.startswith("__"):
                    continue
                cname, ctype = untyped_column(name)
                self.add(
                    Column(name=cname,
                           jx_type=coalesce(sql_type_to_json_type.get(ctype),
                                            IS_NULL),
                           nested_path=full_nested_path,
                           es_type=dtype,
                           es_column=name,
                           es_index=table.name,
                           last_updated=Date.now()))
            last_nested_path = full_nested_path
예제 #29
0
    def update_session(self, session_id, props):
        """
        UPDATE GIVEN SESSION WITH PROPERTIES
        :param session_id:
        :param props:
        :return:
        """
        now = Date.now().unix
        session = self.get_session(session_id)
        for k, v in props.items():
            session[k] = v
        session.last_used = now

        record = {
            "session_id": session_id,
            "data": value2json(session),
            "expires": session.expires,
            "last_used": session.last_used,
        }

        with self.db.transaction() as t:
            t.execute(SQL_UPDATE + quote_column(self.table) + SQL_SET +
                      sql_list(sql_eq(**{k: v}) for k, v in record.items()) +
                      SQL_WHERE + sql_eq(session_id=session_id))
예제 #30
0
    "nested": "TEXT"
}

STATS = {
    "count": "COUNT({{value}})",
    "std": "SQRT((1-1.0/COUNT({{value}}))*VARIANCE({{value}}))",
    "min": "MIN({{value}})",
    "max": "MAX({{value}})",
    "sum": "SUM({{value}})",
    "median": "MEDIAN({{value}})",
    "sos": "SUM({{value}}*{{value}})",
    "var": "(1-1.0/COUNT({{value}}))*VARIANCE({{value}})",
    "avg": "AVG({{value}})"
}

quoted_GUID = quote_column(GUID)
quoted_UID = quote_column(UID)
quoted_ORDER = quote_column(ORDER)
quoted_PARENT = quote_column(PARENT)


def sql_text_array_to_set(column):
    def _convert(row):
        text = row[column]
        if text == None:
            return set()
        else:
            value = json2value(row[column])
            return set(value) - {None}

    return _convert
예제 #31
0
from jx_python import jx
from mo_collections import UniqueIndex
from mo_dots import Data, FlatList, Null, NullType, ROOT_PATH, concat_field, is_container, is_data, is_list, join_field, listwrap, split_field, unwraplist, wrap
from mo_files import File
from mo_future import items, none_type, reduce, text_type, binary_type
from mo_json import (INTEGER, NUMBER, STRING, STRUCT, json2value, python_type_to_json_type, value2json)
from mo_json.typed_encoder import unnest_path, untype_path
from mo_logs import Except, Log
from mo_threads import Lock, Queue, Thread, Till
from mo_times.dates import Date
from pyLibrary.sql import (SQL_AND, SQL_FROM, SQL_ORDERBY, SQL_SELECT, SQL_WHERE, sql_iso, sql_list)
from pyLibrary.sql.sqlite import json_type_to_sqlite_type, quote_column, quote_value

DEBUG = False
singlton = None
db_table_name = quote_column("meta.columns")

INSERT, UPDATE, DELETE, EXECUTE = "insert", "update", "delete", "execute"


class ColumnList(Table, jx_base.Container):
    """
    OPTIMIZED FOR THE PARTICULAR ACCESS PATTERNS USED
    """

    def __init__(self, name):
        Table.__init__(self, "meta.columns")
        self.db_file = File("metadata." + name + ".sqlite")
        self.data = {}  # MAP FROM ES_INDEX TO (abs_column_name to COLUMNS)
        self.locker = Lock()
        self._schema = None