Metadata-Version: 2.1
Name: ftrack-query
Version: 1.7.0
Summary: Easy query generation for the FTrack API.
Home-page: https://github.com/huntfx/ftrack-query
Author: Peter Hunt
Author-email: peter@huntfx.uk
License: MIT
Download-URL: https://github.com/huntfx/ftrack-query/archive/1.7.0.tar.gz
Project-URL: Documentation, https://github.com/huntfx/ftrack-query/wiki
Project-URL: Source, https://github.com/huntfx/ftrack-query
Project-URL: Issues, https://github.com/huntfx/ftrack-query/issues
Description: # ftrack-query
        FTrack Query is an object-orientated wrapper over the FTrack API. While the default query syntax is powerful, it is entirely text based so dynamic queries can be difficult to construct. This module supports **and**/**or** operators with nested comparisons.
        
        It is recommended to first read https://ftrack-python-api.readthedocs.io/en/stable/tutorial.html for a basic understanding of how the FTrack API works.
        
        ## Installation
            pip install ftrack_query
        
        ## Examples
        
        ### Original Syntax
        This will build queries attached to the current session, which allows them to be executed directly.
        
        ```python
        from ftrack_query import FTrackQuery, entity, or_
        
        with FTrackQuery() as session:
            # Create
            note = session.Note.create(
                content='My new note',
                author=session.User('peter'),
                category=session.NoteLabel.where(entity.color!=None, name='Internal').one(),
            )
        
            # Query
            task = session.Task.where(
                entity.status.name.in_('Lighting', 'Rendering'),
                or_(
                    entity.parent == session.Episode.first(),
                    entity.parent == None,
                ),
                name='My Task',
            ).order(
                entity.type.name.desc(),
            ).select(
                'name', 'type.name', 'status.name',
            ).first()
        
            task['notes'].append(note)
            session.commit()
        ```
        
        # Statement Syntax
        In version 1.7, new statement functions were added, to allow queries to be built without an associated `session` object.
        
        These require a `session.execute` call in order to work, but the underlying logic is the same as with the original syntax.
        
        ```python
        from ftrack_query import FTrackQuery, select, create, update, delete
        
        with FTrackQuery() as session:
            # Query
            stmt = (
                select('Task.name', 'Task.type.name', 'Task.status.name')
                .where(entity.status.name.in_('Lighting', 'Rendering'))
                .order_by(entity.name.desc())
                .offset(5)
                .limit(1)
            )
            task = session.execute(stmt).first()
            print(f'Task found: {task})
        
            # Create
            stmt = (
                create('Task')
                .values(name='My Task', parent=task)
            )
            task = session.execute(stmt)
            session.commit()
            print(f'Task created: {task}')
        
            # Update
            stmt = (
                update('Task')
                .where(name='Old Task Name')
                .values(name='New Task Name')
            )
            rows = session.execute(stmt)
            session.commit()
            print(f'Tasks updated: {rows}')
        
            # Delete
            stmt = (
                delete('Task')
                .where(name='Old Task Name')
            )
            rows = session.execute(stmt)
            session.commit()
            print(f'Tasks deleted: {rows}')
        ```
        
        ### Event Syntax
        The event system uses a slightly different query language, this has been added for convenience but generally should not be needed.
        
        ```python
        from ftrack_query import FTrackQuery, event
        
        with FTrackQuery() as session:
            session.event_hub.subscribe(str(
                event.and_(
                    event.topic('ftrack.update'),
                    event.data.user.name != getuser(),
                )
            ))
            session.event_hub.wait()
        ```
        
        # Reference
        
        ## FTrackQuery
        Main class inherited from `ftrack_api.Session`.
        
        ## Query
        Every available entity type is an attribute of a session. What was originally `session.query('Note')` is now `session.Note`. This results in the `Query` object, which is used for constructing and executing queries.
        
        ### .where(_\*args, \*\*kwargs_)
        Filter the result.
        
        Using kwargs is the recommended way, with a syntax like `.where(first_name='Peter', last_name='Hunt')`.
        
        Using args is required for complex queries. This uses the `Comparison` object, which is automatically created when comparing multiple `Query` objects. An example would be `.where(entity.project.metadata.any(entity.key!='disabled'))`.
        
        ### .populate(_\*args_) | .select(_\*args_)
        Pre-fetch entity attributes.
        
        An an example, in order to iterate through the name of every user, it would be a good idea to prefetch `first_name` and `last_name`, as otherwise two queries will be performed for each individual user.
        
        ### .order_by(_attribute_)
        Sort the results by an attribute.
        
        The attribute and order can be given in the format `entity.name.desc()`, or as a raw string such as `name descending`.
        
        ### .reverse()
        Reverse the sorting direction.
        
        ### .limit(_value_)
        Limit the amount of results to a certain value.
        
        ### .offset(_value_)
        In the case of using a limit, this applies an offset to the result that is returned.
        
        ### .in_(_subquery_) | .not_in(_subquery_)
        Perform a check to check if an attribute matches any results.
        
        This can accept a subquery such `.in_('select id from table where x is y')`, or a list of items like `.in_('x', 'y')`.
        
        ### .\_\_call\_\_(_value_)
        If an entity has a primary key, by calling the value of that primary key, the entity or `None` will be returned.
        Currently only `User` supports this.
        
        ## Comparison
        The `Comparison` object is designed to convert data to a string. It contains a wide array of operators that can be used against any data type, including other `Comparison` objects.
        
        Any comparison can be reversed with the `~` prefix or the `not_` function.
        
        - String Comparison: `entity.attr=='value'`
        - Number comparison: `entity.attr>5`
        - Pattern Comparison: `entity.attr.like('value%')`
        - Time Comparison: `entity.attr.after(arrow.now().floor('day'))`
        - Scalar Relationship: `entity.attr.has(subattr='value')`
        - Collection Relationship: `entity.attr.any(subattr='value')`
        - Subquery Relationship: `entity.attr.in_(subquery)`
        
        ## and\_(_\*args, \*\*kwargs_) | or\_(_\*args, \*\*kwargs_)
        Join multiple comparisons. `and_` is used by default if nothing is provided.
        
        ## Statements
        The statement functions build upon the `Query` object, but are not attached to any session. Instead of `session.Note`, it becomes `select('Note')`.
        
        ### select(_\*_entity_type_)
        A select statement has access to the `Query` methods such as `.where()`.
        
        If multiple arguments are given, it will use these in place of `.populate()` (eg. `select('Task.name', Task.parent')` is the same as `select('Task').populate('name', 'parent')`).
        
        Calling `session.execute(stmt)` will execute the query and return FTrack's own `QueryResult` object, from which `.one()`, `.first()` or `.all()` may be called.
        
        ### create(_entity_type_)
        A create statement has a `.values()` method used to input the data.
        
        Calling `session.execute(stmt)` will return the created entity.
        
        ### update(_entity_type_)
        An update statement has access to all of the `Query` methods, but also has a `.values()` method used to input the new data.
        
        Calling `session.execute(stmt)` will return how many entities were found and updated.
        
        ### delete(_entity_type_)
        A delete statement has access to most of the `Query` methods.
        
        Calling `session.execute(stmt)` will return how many entities were deleted.
        
        A convenience method, `.clean_components()`, can be used when deleting a `Component`. Enabling this will remove the component from every location before it is deleted.
        
        
        
        ## Equivalent examples from the [API reference](http://ftrack-python-api.rtd.ftrack.com/en/0.9.0/querying.html):
        
        ```python
        # Project
        select('Project')
        
        # Project where status is active
        select('Project').where(status='active')
        
        # Project where status is active and name like "%thrones"
        select('Project').where(entity.name.like('%thrones'), status='active')
        
        # session.query('Project where status is active and (name like "%thrones" or full_name like "%thrones")')
        select('Project').where(or_(entity.name.like('%thrones'), entity.full_name.like('%thrones')), status='active')
        
        # session.query('Task where project.id is "{0}"'.format(project['id']))
        select('Task').where(project=project)
        
        # session.query('Task where project.id is "{0}" and status.type.name is "Done"'.format(project['id']))
        select('Task').where(entity.status.type.name == 'Done', project=project)
        
        # session.query('Task where timelogs.start >= "{0}"'.format(arrow.now().floor('day')))
        select('Task').where(entity.timelogs.start >= arrow.now().floor('day'))
        
        # session.query('Note where author has (first_name is "Jane" and last_name is "Doe")')
        select('Note').where(entity.author.has(first_name='Jane', last_name='Doe'))
        
        # session.query('User where not timelogs any ()')
        select('User').where(~entity.timelogs.any())
        
        # projects = session.query('select full_name, status.name from Project')
        select('Project.full_name', 'Project.status.name')
        # or
        select('Project').populate('full_name', 'status.name')
        
        # select name from Project where allocations.resource[Group].memberships any (user.username is "john_doe")
        select('Project').select('name').where(entity.allocations.resource['Group'].memberships.any(entity.user.username == 'john_doe'))
        
        # Note where parent_id is "{version_id}" or parent_id in (select id from ReviewSessionObject where version_id is "{version_id}")
        select('Note').where(or_(entity.parent_id.in_(select('ReviewSessionObject.id').where(version_id=version_id)), parent_id=version_id))
        ```
        
Keywords: ftrack,api,query,event
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Requires-Python: >=2.7.9, <4.0
Description-Content-Type: text/markdown
