Example #1
0
	def LQuery(*args):
		
		if args[1] is None:
			expr = Ltree('None.*')
		else:
			expr = Ltree("*." + str(arg[1]) + ".*") #Validation fails at this point. 
			return args[0].query.filter(args[0].path.lquery(expr)).all()
Example #2
0
    def test_create_category(self):
        '''Ensure creating categories behave as expected.
        '''
        category1 = Category(name='First category', url='/category/cat-256121')
        category2 = Category(name='Second category',
                             url='/category/cat-two-256121',
                             parent=category1)

        self.assertEqual(category1.slug, 'cat')
        self.assertEqual(category1.parent, None)
        self.assertEqual(category1.path, Ltree('cat'))
        self.assertEqual(category2.slug, 'cat_two')
        self.assertEqual(category2.parent, category1)
        self.assertEqual(category2.path, Ltree('cat.cat_two'))
Example #3
0
    async def register(self, session) -> str:
        """
        Obtain and manually set object's id and ltree path.
        session must be provided with tornado_sqlalchemy's ThreadPoolExecutor instance.
        """
        # Prevent INSERT before instance registration
        with session.no_autoflush:
            # Expected to be zero if the tree is empty
            node_count = await as_future(
                lambda: session.query(self.__class__).count())
            # Obtain the next index from the sequence
            id = await as_future(
                lambda: session.execute(Sequence('nodelist_id_seq')))

        ltree_id = Ltree(str(id))

        # TODO: validate parent's path
        if type(self.parent) is not self.__class__:
            if node_count > 0:
                raise TreeNotEmptyError('Parentless node in non-empty tree')
            else:
                self.path = ltree_id
        else:
            self.path = self.parent.path + ltree_id
        self.id = id

        return self.path
Example #4
0
def insertMateriallizedPath(last_id, start_range, end_range, parent_id,
                            parent_path):

    for i in range(start_range, end_range):
        object_created_date = datetime.today() - timedelta(hours=i)
        object_updated_date = datetime.today() - timedelta(minutes=i)
        desc = randomword(i + 10)
        title = randomword(5)
        model = MaterializedPathModel(
            row_id=i,
            created_at=object_created_date.strftime("%Y-%m-%d %H:%M:%S"),
            updated_at=object_updated_date.strftime("%Y-%m-%d %H:%M:%S"),
            parent_id=parent_id,
            title=title,
            description=desc,
            path=Ltree(parent_path + "." + str(i)))
        db.session.add(model)

        if parent_id < 0:
            parent_id += 2
            parent_path = parent_path + "." + str(i)

        if i % 3 == 0:
            parent_id += 1
            parent_object = MaterializedPathModel.query.filter(
                MaterializedPathModel.id == parent_id).first()
            if parent_object is not None:
                parent_path = str(parent_object.path)

        if (i % CHUNK_SIZE == 0):
            logger.info('Commiting Session Rows')
            db.session.commit()
        db.session.commit()
Example #5
0
def strfltee(s: str, replacements=(" ", "-")):
    result = s

    for repl in replacements:
        result = result.replace(repl, "")

    return Ltree(result)
Example #6
0
 def __init__(self, *args, **kwargs):
     engine = kwargs['engine']
     del kwargs['engine']
     super().__init__(*args, **kwargs)
     _id = engine.execute(id_seq)
     self.id = _id
     self.uuid = uuid.uuid4()
     parent = kwargs['parent'] if 'parent' in kwargs else None
     ltree_id = Ltree(str(self.id))
     self.path = ltree_id if parent is None else parent.path + ltree_id
    def create_root(self, db: Session, *,
                    obj_in: OrganizationCreateRoot) -> Organization:
        parent = self.get(
            db, id=obj_in.parent_id) if 'parent_id' in obj_in else None

        obj_in_data = jsonable_encoder(obj_in, exclude=["owner_email"])
        org = Organization(**obj_in_data, parent=None)

        db.add(org)
        db.commit()
        db.refresh(org)
        org.path = (Ltree(str(org.id)) if parent is None else
                    (parent.path or Ltree("_")) + Ltree(str(org.id)))
        org.slug = Organization.initiate_unique_slug(name=org.name,
                                                     id=org.id,
                                                     path=org.path)

        db.commit()
        db.refresh(org)
        return org
Example #8
0
 def __init__(self, *args, **kwargs):
     if 'slug' not in kwargs:
         url = kwargs.get('url')
         slug = re.search(r'/category/(\D+)-\d+', url).group(1)
         slug = slug.replace('-', '_')
         kwargs['slug'] = slug
     else:
         slug = kwargs.get('slug')
     ltree_slug = Ltree(slug)
     parent = kwargs.get('parent')
     kwargs['path'] = ltree_slug if not parent else parent.path + ltree_slug
     super().__init__(*args, **kwargs)
    def parent_category_term(self):
        """
        Hybrid property representing the parent (CategoryTerm) of a CategoryTerm, if one exists

        Performs a query based on the CategoryTerm.path Ltree property. If the path of the CategoryTerm is a single
        (root) level (e.g. 'root' rather than 'root.foo.bar') then there isn't a parent CategoryTerm and this property
        is made empty.

        Otherwise the current path is shortened (up) by a single level and used to find the relevant parent
        CategoryTerm (i.e. '1.2.3' becomes '1.2').

        :rtype CategoryTerm
        :return: CategoryTerm that is a parent of the current CategoryTerm as determined by the Ltree column
        """
        parent_category_term_path = Ltree(self.path)
        if len(parent_category_term_path) == 1:
            return None

        parent_category_term_path = Ltree(self.path)[:-1]

        return CategoryTerm.query.filter_by(
            path=parent_category_term_path).first()
Example #10
0
def group_by_path(request: Request, path: str) -> Group:
    """Get a group specified by {group_path} in the route (or 404)."""
    # If loading the specified group path into the GroupSchema changed it, do a
    # 301 redirect to the resulting group path. This will happen in cases like
    # the original url including capital letters in the group path, where we
    # want to redirect to the proper all-lowercase path instead.
    if path != request.matchdict['group_path']:
        request.matchdict['group_path'] = path
        proper_url = request.route_url(request.matched_route.name,
                                       **request.matchdict)

        raise HTTPMovedPermanently(location=proper_url)

    query = request.query(Group).filter(Group.path == Ltree(path))

    return get_resource(request, query)
Example #11
0
    def handleStorage(email, gaia_id, fs):
        """
        Expect some input of the form:
        {
            email: "",
            id: "",
            storage: ...,
        }
        """

        User(email=email, gaia_id=gaia_id)
        assert User.validate(email, gaia_id), "Invalid email and gaia_id combination"

        # TODO OPTIMIZE BY SENDING IN BULK
        for path, file in fs.items():
            File.upsert(email, Ltree(encode(path)), file)  # TODO FOR BIB

        return True
def update_common_topic_tags(config_path: str) -> None:
    """Update the list of common topic tags for all groups."""
    db_session = get_session_from_config(config_path)

    all_groups = db_session.query(Group).all()

    for group in all_groups:
        # create a subquery for all tags from topics in that group - UNNEST() converts
        # the arrays of tags into rows so that we can easily group and count, and
        # created_time will be used to determine when a particular tag was last used
        group_tags = (
            db_session.query(
                func.unnest(Topic._tags).label("tag"), Topic.created_time  # noqa
            )
            .filter(Topic.group == group)
            .subquery()
        )

        # get the list of the most common tags, based on frequency and breaking ties
        # with which was used most recently
        common_tags = (
            db_session.query(
                group_tags.columns["tag"],
                func.count().label("frequency"),
                func.max(group_tags.columns["created_time"]).label("last_used"),
            )
            .group_by("tag")
            .order_by(desc("frequency"), desc("last_used"))
            .limit(MAX_NUM_COMMON_TAGS)
            .all()
        )

        group._common_topic_tags = [  # noqa
            Ltree(common_tag[0]) for common_tag in common_tags
        ]

        db_session.add(group)
        db_session.commit()
def _generate_category_term_ltree_path(path_elements: Dict[str, str]) -> Ltree:
    """
    Converts a series of parent Category Terms into an ltree column compatible value

    Category Terms are hierarchical, with parent terms representing broader categories and children, narrower
    categories. Currently this hierarchy is represented as a tree data structure, implemented in the underlying
    database using an 'ltree' data type (https://www.postgresql.org/docs/current/ltree.html).

    This data type stores the path from the current item to the root item, including any intermediate/ancestor items.
    This path is represented as a `.` separated string of labels for each item.

    For example, the path from an item to the root item could be: [Item] -> [Parent Item] -> [Root Item]. When encoded
    as an ltree path this becomes: '[Root Item].[Parent Item].[Item]'. Labels are limited to alphanumeric characters
    and underscores - i.e. 'root_item.parent_item.item'.

    Categories used in this project are usually taken from RDF vocabularies, which typically use URIs to identify each
    concept/category. The category JSON Schema used to structure imported categories consistently requires the path of
    each category to be expressed as a list of identifiers, consequently these are typically lists of URIs.

    As these identifiers cannot be used in an ltree path encoding, this method converts them into 'ltree safe' versions
    by replacing any non-alphanumeric or underscore character with an underscore.

    For example, `['http://example.com/12', 'http://example.com/1']` becomes `'http_example_com_12.http_example_com_1'`.

    :type path_elements: list
    :param path_elements: category scheme identifiers for the categories between a category and the root category

    :rtype Ltree
    :return version of the categories path encoded as a ltree data type path expression
    """
    if len(path_elements.values()) == 0:
        raise ValueError("Path for category cannot be empty")

    path = list(
        map(lambda subject: re.sub('[^0-9a-zA-Z]+', '_', subject),
            path_elements.values()))
    return Ltree('.'.join(path))
Example #14
0
 def test_length(self, path, length):
     assert len(Ltree(path)) == length
Example #15
0
 def test_validate_with_invalid_path(self, path):
     with pytest.raises(ValueError) as e:
         Ltree.validate(path)
     assert str(
         e.value) == ("'{0}' is not a valid ltree path.".format(path))
Example #16
0
 def test_validate_with_valid_codes(self, code):
     Ltree.validate(code)
Example #17
0
 def test_iadd(self, path, other, result):
     ltree = Ltree(path)
     ltree += other
     assert ltree == result
Example #18
0
 def test_init(self):
     assert Ltree('path.path') == Ltree(Ltree('path.path'))
Example #19
0
 def test_lca(self, path, others, result):
     assert Ltree(path).lca(*others) == result
Example #20
0
 def test_non_equality_operator(self):
     assert Ltree('path.path') != u'path.'
     assert not (Ltree('path.path') != 'path.path')
Example #21
0
 def test_equality_operator(self):
     assert Ltree('path.path') == 'path.path'
     assert 'path.path' == Ltree('path.path')
     assert Ltree('path.path') == Ltree('path.path')
Example #22
0
 def test_validate_with_valid_codes(self, code):
     Ltree.validate(code)
Example #23
0
 def test_validate_with_invalid_path(self, path):
     with pytest.raises(ValueError) as e:
         Ltree.validate(path)
     assert str(e.value) == (
         "'{0}' is not a valid ltree path.".format(path)
     )
Example #24
0
 def test_index(self, path, subpath, index):
     assert Ltree(path).index(subpath) == index
Example #25
0
 def test_getitem(self, path, item_slice, result):
     assert Ltree(path)[item_slice] == result
Example #26
0
 def test_repr(self):
     return repr(Ltree('path')) == "Ltree('path')"
Example #27
0
 def test_add(self, path, other, result):
     assert Ltree(path) + other == result
Example #28
0
 def test_unicode(self):
     ltree = Ltree('path.path')
     assert six.text_type(ltree) == 'path.path'
Example #29
0
 def test_radd(self, path, other, result):
     assert other + Ltree(path) == result
Example #30
0
 def test_str(self):
     ltree = Ltree('path')
     assert str(ltree) == 'path'
Example #31
0
 def test_hash(self):
     return hash(Ltree('path')) == hash('path')
Example #32
0
 def test_constructor_with_invalid_code(self):
     with pytest.raises(ValueError) as e:
         Ltree('..')
     assert str(e.value) == "'..' is not a valid ltree path."